15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
22 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
23 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
28 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
29 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
34 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
36 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
40 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
41 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
43 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
46 #ifndef RAPIDJSON_SCHEMA_VERBOSE
47 #define RAPIDJSON_SCHEMA_VERBOSE 0
50 #if RAPIDJSON_SCHEMA_VERBOSE
57 RAPIDJSON_DIAG_OFF(effc++)
61 RAPIDJSON_DIAG_OFF(weak-vtables)
62 RAPIDJSON_DIAG_OFF(exit-time-destructors)
63 RAPIDJSON_DIAG_OFF(
c++98-compat-pedantic)
64 RAPIDJSON_DIAG_OFF(variadic-macros)
68 RAPIDJSON_DIAG_OFF(4512)
76 #if RAPIDJSON_SCHEMA_VERBOSE
80 inline void PrintInvalidKeyword(
const char* keyword) {
81 printf(
"Fail keyword: %s\n", keyword);
84 inline void PrintInvalidKeyword(
const wchar_t* keyword) {
85 wprintf(L
"Fail keyword: %ls\n", keyword);
88 inline void PrintInvalidDocument(
const char* document) {
89 printf(
"Fail document: %s\n\n", document);
92 inline void PrintInvalidDocument(
const wchar_t* document) {
93 wprintf(L
"Fail document: %ls\n\n", document);
96 inline void PrintValidatorPointers(
unsigned depth,
const char*
s,
const char* d) {
97 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
100 inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
101 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
106 #endif // RAPIDJSON_SCHEMA_VERBOSE
111 #if RAPIDJSON_SCHEMA_VERBOSE
112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
118 RAPIDJSON_MULTILINEMACRO_BEGIN\
119 context.invalidKeyword = keyword.GetString();\
120 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
122 RAPIDJSON_MULTILINEMACRO_END
127 template <
typename ValueType,
typename Allocator>
132 template <
typename SchemaDocumentType>
141 virtual bool IsValid()
const = 0;
147 template <
typename SchemaType>
164 template<
typename Encoding,
typename Allocator>
167 typedef typename Encoding::Ch
Ch;
179 if (d < 0) n.
u.
i =
static_cast<int64_t>(d);
200 for (
SizeType i = 0; i < memberCount; i++)
201 h ^=
Hash(kv[i * 2], kv[i * 2 + 1]);
202 *
stack_.template Push<uint64_t>() = h;
210 for (
SizeType i = 0; i < elementCount; i++)
212 *
stack_.template Push<uint64_t>() = h;
220 return *
stack_.template Top<uint64_t>();
240 const unsigned char* d =
static_cast<const unsigned char*
>(
data);
241 for (
size_t i = 0; i <
len; i++)
243 *
stack_.template Push<uint64_t>() = h;
260 template <
typename SchemaDocumentType>
265 typedef typename ValueType::Ch
Ch;
337 template <
typename SchemaDocumentType>
340 typedef typename SchemaDocumentType::ValueType
ValueType;
344 typedef typename EncodingType::Ch
Ch;
382 typedef typename SchemaDocumentType::ValueType
ValueType;
383 typedef typename ValueType::ConstValueIterator ConstValueIterator;
384 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
386 if (!value.IsObject())
389 if (
const ValueType*
v =
GetMember(value, GetTypeString())) {
393 else if (
v->IsArray())
394 for (ConstValueIterator itr =
v->Begin(); itr !=
v->End(); ++itr)
398 if (
const ValueType*
v =
GetMember(value, GetEnumString()))
399 if (
v->IsArray() &&
v->Size() > 0) {
401 for (ConstValueIterator itr =
v->Begin(); itr !=
v->End(); ++itr) {
405 EnumHasherType
h(&hasherAllocator, 256);
411 if (schemaDocument) {
417 if (
const ValueType*
v =
GetMember(value, GetNotString())) {
418 schemaDocument->CreateSchema(&
not_, p.Append(GetNotString(),
allocator_), *
v, document);
425 const ValueType* properties =
GetMember(value, GetPropertiesString());
426 const ValueType* required =
GetMember(value, GetRequiredString());
427 const ValueType* dependencies =
GetMember(value, GetDependenciesString());
432 if (properties && properties->IsObject())
433 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
436 if (required && required->IsArray())
437 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
441 if (dependencies && dependencies->IsObject())
442 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
444 if (itr->value.IsArray())
445 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
450 if (allProperties.Size() > 0) {
461 if (properties && properties->IsObject()) {
463 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
470 if (
const ValueType*
v =
GetMember(value, GetPatternPropertiesString())) {
475 for (ConstMemberIterator itr =
v->MemberBegin(); itr !=
v->MemberEnd(); ++itr) {
483 if (required && required->IsArray())
484 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
485 if (itr->IsString()) {
493 if (dependencies && dependencies->IsObject()) {
496 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
499 if (itr->value.IsArray()) {
501 std::memset(
properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
502 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
505 properties_[sourceIndex].dependencies[targetIndex] =
true;
508 else if (itr->value.IsObject()) {
510 schemaDocument->CreateSchema(&
properties_[sourceIndex].dependenciesSchema, q.Append(itr->name,
allocator_), itr->value, document);
518 if (
const ValueType*
v =
GetMember(value, GetAdditionalPropertiesString())) {
521 else if (
v->IsObject())
529 if (
const ValueType*
v =
GetMember(value, GetItemsString())) {
532 schemaDocument->CreateSchema(&
itemsList_, q, *
v, document);
533 else if (
v->IsArray()) {
536 for (ConstValueIterator itr =
v->Begin(); itr !=
v->End(); ++itr, index++)
544 if (
const ValueType*
v =
GetMember(value, GetAdditionalItemsString())) {
547 else if (
v->IsObject())
557 if (
const ValueType*
v =
GetMember(value, GetPatternString()))
561 if (
const ValueType*
v =
GetMember(value, GetMinimumString()))
565 if (
const ValueType*
v =
GetMember(value, GetMaximumString()))
572 if (
const ValueType*
v =
GetMember(value, GetMultipleOfString()))
573 if (
v->IsNumber() &&
v->GetDouble() > 0.0)
592 #if RAPIDJSON_SCHEMA_HAS_REGEX
627 bool otherValid =
false;
632 bool patternValid =
true;
635 patternValid =
false;
644 if (!patternValid || !otherValid)
647 else if (!patternValid && !otherValid)
674 bool oneValid =
false;
750 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
770 std::memset(context.
propertyExist, 0,
sizeof(
bool) * propertyCount_);
849 else if (
properties_[sourceIndex].dependenciesSchema)
881 #define RAPIDJSON_STRING_(name, ...) \
882 static const ValueType& Get##name##String() {\
883 static const Ch s[] = { __VA_ARGS__, '\0' };\
884 static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
901 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
903 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
904 RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
905 RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
906 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
907 RAPIDJSON_STRING_(MaxProperties, 'm', 'a', '
x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
911 RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
912 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
918 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', '
v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
919 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
920 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', '
f')
922 #undef RAPIDJSON_STRING_
936 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
938 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
957 template <
typename V1,
typename V2>
959 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
967 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
968 return itr != value.MemberEnd() ? &(itr->value) : 0;
979 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
980 out = static_cast<SizeType>(v->GetUint64());
985 if (v->IsArray() && v->Size() > 0) {
987 out.
count = v->Size();
991 schemaDocument.CreateSchema(&out.
schemas[i], q.Append(i,
allocator_), (*v)[i], document);
998 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
999 template <
typename ValueType>
1001 if (value.IsString()) {
1005 AllocatorType::Free(r);
1014 return pattern->
Search(str);
1016 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1017 template <
typename ValueType>
1019 if (value.IsString())
1021 return new (
allocator_->Malloc(
sizeof(
RegexType)))
RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1023 catch (
const std::regex_error&) {
1029 std::match_results<const Ch*>
r;
1030 return std::regex_search(str, str + length, r, *pattern);
1033 template <
typename ValueType>
1037 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1088 const Ch* str = name.GetString();
1128 if (static_cast<uint64_t>(i >= 0 ? i : -i) %
multipleOf_.GetUint64() != 0)
1189 double a = std::abs(d), b = std::abs(
multipleOf_.GetDouble());
1190 double q = std::floor(a / b);
1191 double r = a - q *
b;
1263 template<
typename Stack,
typename Ch>
1266 *documentStack.template Push<Ch>() =
'/';
1269 for (
size_t i = 0; i <
length; i++)
1270 *documentStack.template Push<Ch>() = buffer[i];
1275 template <
typename Stack>
1279 char *
buffer = documentStack.template Push<char>(1 + 10);
1282 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end -
buffer)));
1285 char *
buffer = documentStack.template Push<char>(1 + 20);
1288 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end -
buffer)));
1298 template <
typename SchemaDocumentType>
1301 typedef typename SchemaDocumentType::Ch
Ch;
1319 template <
typename ValueT,
typename Allocator = CrtAllocator>
1326 typedef typename EncodingType::Ch
Ch;
1330 template <
typename,
typename,
typename>
1368 refEntry->~SchemaRefEntry();
1376 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1386 rhs.remoteProvider_ = 0;
1388 rhs.ownAllocator_ = 0;
1395 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1438 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1442 for (
SizeType i = 0; i < v.Size(); i++)
1459 static const Ch kRefString[] = {
'$',
'r',
'e',
'f',
'\0' };
1460 static const ValueType kRefValue(kRefString, 4);
1462 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1463 if (itr == v.MemberEnd())
1466 if (itr->value.IsString()) {
1469 const Ch* s = itr->value.GetString();
1471 while (i < len && s[i] !=
'#')
1478 if (pointer.IsValid()) {
1479 if (
const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1488 else if (s[i] ==
'#') {
1490 if (pointer.IsValid()) {
1491 if (
const ValueType* nv = pointer.Get(document))
1506 if (pointer ==
target->pointer)
1513 if (schema ==
target->schema)
1550 typename SchemaDocumentType,
1561 typedef typename EncodingType::Ch
Ch;
1571 const SchemaDocumentType& schemaDocument,
1572 StateAllocator* allocator = 0,
1577 root_(schemaDocument.GetRoot()),
1598 const SchemaDocumentType& schemaDocument,
1599 OutputHandler& outputHandler,
1600 StateAllocator* allocator = 0,
1605 root_(schemaDocument.GetRoot()),
1651 #if RAPIDJSON_SCHEMA_VERBOSE
1652 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
1653 RAPIDJSON_MULTILINEMACRO_BEGIN\
1654 *documentStack_.template Push<Ch>() = '\0';\
1655 documentStack_.template Pop<Ch>(1);\
1656 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
1657 RAPIDJSON_MULTILINEMACRO_END
1659 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
1662 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
1663 if (!valid_) return false; \
1664 if (!BeginValue() || !CurrentSchema().method arg1) {\
1665 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
1666 return valid_ = false;\
1669 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
1670 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
1671 if (context->hasher)\
1672 static_cast<HasherType*>(context->hasher)->method arg2;\
1673 if (context->validators)\
1674 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
1675 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
1676 if (context->patternPropertiesValidators)\
1677 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
1678 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
1681 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
1682 return valid_ = EndValue() && outputHandler_.method arg2
1684 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
1685 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
1686 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
1687 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
1708 if (!
valid_)
return false;
1716 if (!
valid_)
return false;
1729 if (!
valid_)
return false;
1735 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
1736 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
1737 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
1738 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
1752 StateAllocator::Free(v);
1766 StateAllocator::Free(h);
1774 return StateAllocator::Free(p);
1783 const SchemaDocumentType& schemaDocument,
1788 StateAllocator* allocator = 0,
1824 typename Context::PatternValidatorType patternValidatorType =
CurrentContext().valuePatternValidatorType;
1830 CurrentContext().objectPatternValidatorType = patternValidatorType;
1831 ISchemaValidator**& va =
CurrentContext().patternPropertiesValidators;
1833 va =
static_cast<ISchemaValidator**
>(
MallocState(
sizeof(ISchemaValidator*) * count));
1847 #if RAPIDJSON_SCHEMA_VERBOSE
1862 if (context.valueUniqueness) {
1867 if (itr->GetUint64() ==
h)
1884 if (str[i] ==
'~') {
1888 else if (str[i] ==
'/') {
1901 if (
HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
1902 a->~HashCodeArray();
1903 StateAllocator::Free(a);
1913 static OutputHandler nullHandler;
1927 #if RAPIDJSON_SCHEMA_VERBOSE
1948 unsigned parseFlags,
1949 typename InputStream,
1950 typename SourceEncoding,
1956 typedef typename InputStream::Ch
Ch;
1965 template <
typename Handler>
1994 const SchemaDocumentType&
sd_;
2006 #endif // RAPIDJSON_SCHEMA_H_