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;
169 Hasher(
Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
173 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
174 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
175 bool Int64(
int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
176 bool Uint64(
uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
179 if (d < 0) n.u.i =
static_cast<int64_t>(d);
180 else n.u.u =
static_cast<uint64_t>(d);
182 return WriteNumber(n);
199 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
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;
209 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
210 for (
SizeType i = 0; i < elementCount; i++)
212 *stack_.template Push<uint64_t>() = h;
220 return *stack_.template Top<uint64_t>();
224 static const size_t kDefaultSize = 256;
233 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
235 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
237 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
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;
254 Stack<Allocator> stack_;
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;
351 allocator_(allocator),
355 type_((1 << kTotalSchemaType) - 1),
358 additionalPropertiesSchema_(),
359 patternProperties_(),
360 patternPropertyCount_(),
364 additionalProperties_(true),
367 hasSchemaDependencies_(),
368 additionalItemsSchema_(),
374 additionalItems_(true),
379 exclusiveMinimum_(false),
380 exclusiveMaximum_(false)
382 typedef typename SchemaDocumentType::ValueType
ValueType;
383 typedef typename ValueType::ConstValueIterator ConstValueIterator;
384 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
386 if (!
value.IsObject())
393 else if (v->IsArray())
394 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
399 if (v->IsArray() && v->Size() > 0) {
400 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(
uint64_t) * v->Size()));
401 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
403 char buffer[256 + 24];
405 EnumHasherType h(&hasherAllocator, 256);
407 enum_[enumCount_++] = h.GetHashCode();
411 if (schemaDocument) {
412 AssignIfExist(allOf_, *schemaDocument, p,
value, GetAllOfString(), document);
413 AssignIfExist(anyOf_, *schemaDocument, p,
value, GetAnyOfString(), document);
414 AssignIfExist(oneOf_, *schemaDocument, p,
value, GetOneOfString(), document);
418 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
419 notValidatorIndex_ = validatorCount_;
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)
434 AddUniqueElement(allProperties, itr->name);
436 if (required && required->IsArray())
437 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
439 AddUniqueElement(allProperties, *itr);
441 if (dependencies && dependencies->IsObject())
442 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
443 AddUniqueElement(allProperties, itr->name);
444 if (itr->value.IsArray())
445 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
447 AddUniqueElement(allProperties, *i);
450 if (allProperties.Size() > 0) {
451 propertyCount_ = allProperties.Size();
452 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
453 for (
SizeType i = 0; i < propertyCount_; i++) {
454 new (&properties_[i]) Property();
455 properties_[i].name = allProperties[i];
456 properties_[i].schema = GetTypeless();
461 if (properties && properties->IsObject()) {
462 PointerType q = p.Append(GetPropertiesString(), allocator_);
463 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
465 if (FindPropertyIndex(itr->name, &index))
466 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
470 if (
const ValueType* v = GetMember(
value, GetPatternPropertiesString())) {
471 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
472 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
473 patternPropertyCount_ = 0;
475 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
476 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
477 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
478 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
479 patternPropertyCount_++;
483 if (required && required->IsArray())
484 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
485 if (itr->IsString()) {
487 if (FindPropertyIndex(*itr, &index)) {
488 properties_[index].required =
true;
493 if (dependencies && dependencies->IsObject()) {
494 PointerType q = p.Append(GetDependenciesString(), allocator_);
495 hasDependencies_ =
true;
496 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
498 if (FindPropertyIndex(itr->name, &sourceIndex)) {
499 if (itr->value.IsArray()) {
500 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
501 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
502 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
504 if (FindPropertyIndex(*targetItr, &targetIndex))
505 properties_[sourceIndex].dependencies[targetIndex] =
true;
508 else if (itr->value.IsObject()) {
509 hasSchemaDependencies_ =
true;
510 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
511 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
518 if (
const ValueType* v = GetMember(
value, GetAdditionalPropertiesString())) {
520 additionalProperties_ = v->GetBool();
521 else if (v->IsObject())
522 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
525 AssignIfExist(minProperties_,
value, GetMinPropertiesString());
526 AssignIfExist(maxProperties_,
value, GetMaxPropertiesString());
530 PointerType q = p.Append(GetItemsString(), allocator_);
532 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
533 else if (v->IsArray()) {
534 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
536 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
537 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
541 AssignIfExist(minItems_,
value, GetMinItemsString());
542 AssignIfExist(maxItems_,
value, GetMaxItemsString());
544 if (
const ValueType* v = GetMember(
value, GetAdditionalItemsString())) {
546 additionalItems_ = v->GetBool();
547 else if (v->IsObject())
548 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
551 AssignIfExist(uniqueItems_,
value, GetUniqueItemsString());
554 AssignIfExist(minLength_,
value, GetMinLengthString());
555 AssignIfExist(maxLength_,
value, GetMaxLengthString());
558 pattern_ = CreatePattern(*v);
563 minimum_.CopyFrom(*v, *allocator_);
567 maximum_.CopyFrom(*v, *allocator_);
569 AssignIfExist(exclusiveMinimum_,
value, GetExclusiveMinimumString());
570 AssignIfExist(exclusiveMaximum_,
value, GetExclusiveMaximumString());
573 if (v->IsNumber() && v->GetDouble() > 0.0)
574 multipleOf_.CopyFrom(*v, *allocator_);
579 allocator_->Free(enum_);
582 for (
SizeType i = 0; i < propertyCount_; i++)
583 properties_[i].~Property();
584 AllocatorType::Free(properties_);
586 if (patternProperties_) {
587 for (
SizeType i = 0; i < patternPropertyCount_; i++)
588 patternProperties_[i].~PatternProperty();
589 AllocatorType::Free(patternProperties_);
591 AllocatorType::Free(itemsTuple_);
592 #if RAPIDJSON_SCHEMA_HAS_REGEX
594 pattern_->~RegexType();
595 allocator_->Free(pattern_);
607 else if (itemsTuple_) {
610 else if (additionalItemsSchema_)
612 else if (additionalItems_)
627 bool otherValid =
false;
632 bool patternValid =
true;
633 for (
SizeType i = 0; i < count; i++)
635 patternValid =
false;
644 if (!patternValid || !otherValid)
647 else if (!patternValid && !otherValid)
653 for (
SizeType i = 0; i < enumCount_; i++)
661 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
665 if (anyOf_.schemas) {
666 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
673 if (oneOf_.schemas) {
674 bool oneValid =
false;
675 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
693 if (!(type_ & (1 << kNullSchemaType)))
695 return CreateParallelValidator(context);
699 if (!(type_ & (1 << kBooleanSchemaType)))
701 return CreateParallelValidator(context);
705 if (!CheckInt(context, i))
707 return CreateParallelValidator(context);
711 if (!CheckUint(context, u))
713 return CreateParallelValidator(context);
717 if (!CheckInt(context, i))
719 return CreateParallelValidator(context);
723 if (!CheckUint(context, u))
725 return CreateParallelValidator(context);
729 if (!(type_ & (1 << kNumberSchemaType)))
732 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
735 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
738 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
741 return CreateParallelValidator(context);
745 if (!(type_ & (1 << kStringSchemaType)))
748 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
750 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
751 if (count < minLength_)
753 if (count > maxLength_)
758 if (pattern_ && !IsPatternMatch(pattern_, str, length))
761 return CreateParallelValidator(context);
765 if (!(type_ & (1 << kObjectSchemaType)))
768 if (hasDependencies_ || hasRequired_) {
770 std::memset(context.
propertyExist, 0,
sizeof(
bool) * propertyCount_);
773 if (patternProperties_) {
774 SizeType count = patternPropertyCount_ + 1;
780 return CreateParallelValidator(context);
784 if (patternProperties_) {
786 for (
SizeType i = 0; i < patternPropertyCount_; i++)
787 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
792 if (FindPropertyIndex(
ValueType(str, len).Move(), &index)) {
807 if (additionalPropertiesSchema_) {
817 else if (additionalProperties_) {
830 for (
SizeType index = 0; index < propertyCount_; index++)
831 if (properties_[index].required)
835 if (memberCount < minProperties_)
838 if (memberCount > maxProperties_)
841 if (hasDependencies_) {
842 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
844 if (properties_[sourceIndex].dependencies) {
845 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
846 if (properties_[sourceIndex].dependencies[targetIndex] && !context.
propertyExist[targetIndex])
849 else if (properties_[sourceIndex].dependenciesSchema)
850 if (!context.
validators[properties_[sourceIndex].dependenciesValidatorIndex]->
IsValid())
859 if (!(type_ & (1 << kArraySchemaType)))
865 return CreateParallelValidator(context);
871 if (elementCount < minItems_)
874 if (elementCount > maxItems_)
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_
925 enum SchemaValueType {
936 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
938 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
939 typedef std::basic_regex<Ch> RegexType;
941 typedef char RegexType;
945 SchemaArray() : schemas(), count() {}
946 ~SchemaArray() { AllocatorType::Free(schemas); }
957 template <
typename V1,
typename V2>
958 void AddUniqueElement(V1&
a,
const V2& v) {
959 for (
typename V1::ConstValueIterator itr =
a.Begin(); itr !=
a.End(); ++itr)
962 V1
c(v, *allocator_);
963 a.PushBack(
c, *allocator_);
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();
988 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
989 memset(out.schemas, 0,
sizeof(
Schema*)* out.count);
990 for (
SizeType i = 0; i < out.count; i++)
991 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
992 out.begin = validatorCount_;
993 validatorCount_ += out.count;
998 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
999 template <
typename ValueType>
1001 if (
value.IsString()) {
1002 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(
value.GetString());
1003 if (!r->IsValid()) {
1005 AllocatorType::Free(r);
1013 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
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&) {
1028 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1029 std::match_results<const Ch*> r;
1030 return std::regex_search(str, str + length, r, *pattern);
1033 template <
typename ValueType>
1034 RegexType* CreatePattern(
const ValueType&) {
return 0; }
1036 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1037 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1040 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1041 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1042 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1043 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1044 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1045 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1046 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1049 bool CreateParallelValidator(
Context& context)
const {
1050 if (enum_ || context.arrayUniqueness)
1051 context.hasher = context.factory.CreateHasher();
1053 if (validatorCount_) {
1055 context.validators =
static_cast<ISchemaValidator**
>(context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1056 context.validatorCount = validatorCount_;
1059 CreateSchemaValidators(context, allOf_);
1062 CreateSchemaValidators(context, anyOf_);
1065 CreateSchemaValidators(context, oneOf_);
1068 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1070 if (hasSchemaDependencies_) {
1071 for (
SizeType i = 0; i < propertyCount_; i++)
1072 if (properties_[i].dependenciesSchema)
1073 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1080 void CreateSchemaValidators(
Context& context,
const SchemaArray& schemas)
const {
1081 for (
SizeType i = 0; i < schemas.count; i++)
1082 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1087 SizeType len = name.GetStringLength();
1088 const Ch* str = name.GetString();
1089 for (
SizeType index = 0; index < propertyCount_; index++)
1090 if (properties_[index].name.GetStringLength() == len &&
1091 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(
Ch) * len) == 0))
1100 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1103 if (!minimum_.IsNull()) {
1104 if (minimum_.IsInt64()) {
1105 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1108 else if (minimum_.IsUint64()) {
1111 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1115 if (!maximum_.IsNull()) {
1116 if (maximum_.IsInt64()) {
1117 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1120 else if (maximum_.IsUint64())
1122 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1126 if (!multipleOf_.IsNull()) {
1127 if (multipleOf_.IsUint64()) {
1128 if (
static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1131 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1139 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1142 if (!minimum_.IsNull()) {
1143 if (minimum_.IsUint64()) {
1144 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1147 else if (minimum_.IsInt64())
1149 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1153 if (!maximum_.IsNull()) {
1154 if (maximum_.IsUint64()) {
1155 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1158 else if (maximum_.IsInt64())
1160 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1164 if (!multipleOf_.IsNull()) {
1165 if (multipleOf_.IsUint64()) {
1166 if (i % multipleOf_.GetUint64() != 0)
1169 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1176 bool CheckDoubleMinimum(
Context& context,
double d)
const {
1177 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
1182 bool CheckDoubleMaximum(
Context& context,
double d)
const {
1183 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
1188 bool CheckDoubleMultipleOf(
Context& context,
double d)
const {
1189 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1190 double q = std::floor(
a / b);
1191 double r =
a - q * b;
1198 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1199 ~Property() { AllocatorType::Free(dependencies); }
1203 SizeType dependenciesValidatorIndex;
1208 struct PatternProperty {
1209 PatternProperty() : schema(), pattern() {}
1210 ~PatternProperty() {
1212 pattern->~RegexType();
1213 AllocatorType::Free(pattern);
1231 Property* properties_;
1232 const SchemaType* additionalPropertiesSchema_;
1233 PatternProperty* patternProperties_;
1238 bool additionalProperties_;
1239 bool hasDependencies_;
1241 bool hasSchemaDependencies_;
1249 bool additionalItems_;
1252 RegexType* pattern_;
1259 bool exclusiveMinimum_;
1260 bool exclusiveMaximum_;
1263 template<
typename Stack,
typename Ch>
1266 *documentStack.template Push<Ch>() =
'/';
1268 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ?
u32toa(index, buffer) :
u64toa(index, buffer)) - buffer);
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>
1342 remoteProvider_(remoteProvider),
1343 allocator_(allocator),
1346 schemaMap_(allocator, kInitialSchemaMapSize),
1347 schemaRef_(allocator, kInitialSchemaRefSize)
1354 CreateSchemaRecursive(&root_,
PointerType(), document, document);
1357 while (!schemaRef_.Empty()) {
1358 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1359 if (
const SchemaType* s = GetSchema(refEntry->target)) {
1360 if (refEntry->schema)
1361 *refEntry->schema = s;
1364 if (!GetSchema(refEntry->source)) {
1365 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source,
const_cast<SchemaType*
>(s),
false, allocator_);
1368 refEntry->~SchemaRefEntry();
1373 schemaRef_.ShrinkToFit();
1376 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1379 remoteProvider_(rhs.remoteProvider_),
1380 allocator_(rhs.allocator_),
1381 ownAllocator_(rhs.ownAllocator_),
1383 schemaMap_(std::move(rhs.schemaMap_)),
1384 schemaRef_(std::move(rhs.schemaRef_))
1386 rhs.remoteProvider_ = 0;
1388 rhs.ownAllocator_ = 0;
1394 while (!schemaMap_.Empty())
1395 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1409 struct SchemaRefEntry {
1416 struct SchemaEntry {
1420 schema->~SchemaType();
1421 Allocator::Free(schema);
1431 *schema = SchemaType::GetTypeless();
1436 CreateSchema(schema,
pointer, v, document);
1438 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1439 CreateSchemaRecursive(0,
pointer.Append(itr->name, allocator_), itr->value, document);
1442 for (
SizeType i = 0; i < v.Size(); i++)
1443 CreateSchemaRecursive(0,
pointer.Append(i, allocator_), v[i], document);
1449 if (!HandleRefSchema(
pointer, schema, v, document)) {
1451 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(
pointer, s,
true, allocator_);
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()) {
1467 SizeType len = itr->value.GetStringLength();
1469 const Ch* s = itr->value.GetString();
1471 while (i < len && s[i] !=
'#')
1475 if (remoteProvider_) {
1488 else if (s[i] ==
'#') {
1492 if (HandleRefSchema(
source, schema, *nv, document))
1495 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(
source,
pointer, schema, allocator_);
1505 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1506 if (
pointer == target->pointer)
1507 return target->schema;
1512 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1513 if (schema == target->schema)
1514 return target->pointer;
1518 static const size_t kInitialSchemaMapSize = 64;
1519 static const size_t kInitialSchemaRefSize = 64;
1550 typename SchemaDocumentType,
1561 typedef typename EncodingType::Ch
Ch;
1571 const SchemaDocumentType& schemaDocument,
1572 StateAllocator* allocator = 0,
1573 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1574 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1576 schemaDocument_(&schemaDocument),
1577 root_(schemaDocument.GetRoot()),
1578 outputHandler_(GetNullHandler()),
1579 stateAllocator_(allocator),
1580 ownStateAllocator_(0),
1581 schemaStack_(allocator, schemaStackCapacity),
1582 documentStack_(allocator, documentStackCapacity),
1598 const SchemaDocumentType& schemaDocument,
1599 OutputHandler& outputHandler,
1600 StateAllocator* allocator = 0,
1601 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1602 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1604 schemaDocument_(&schemaDocument),
1605 root_(schemaDocument.GetRoot()),
1606 outputHandler_(outputHandler),
1607 stateAllocator_(allocator),
1608 ownStateAllocator_(0),
1609 schemaStack_(allocator, schemaStackCapacity),
1610 documentStack_(allocator, documentStackCapacity),
1626 while (!schemaStack_.Empty())
1628 documentStack_.Clear();
1638 return schemaStack_.Empty() ?
PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
1643 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1648 return documentStack_.Empty() ?
PointerType() :
PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(
Ch));
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)
1704 return valid_ = outputHandler_.StartObject();
1708 if (!valid_)
return false;
1709 AppendToken(str, len);
1710 if (!CurrentSchema().
Key(CurrentContext(), str, len, copy))
return valid_ =
false;
1712 return valid_ = outputHandler_.Key(str, len, copy);
1716 if (!valid_)
return false;
1718 if (!CurrentSchema().
EndObject(CurrentContext(), memberCount))
return valid_ =
false;
1725 return valid_ = outputHandler_.StartArray();
1729 if (!valid_)
return false;
1731 if (!CurrentSchema().
EndArray(CurrentContext(), elementCount))
return valid_ =
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_
1746 &GetStateAllocator());
1752 StateAllocator::Free(v);
1766 StateAllocator::Free(h);
1770 return GetStateAllocator().Malloc(size);
1774 return StateAllocator::Free(p);
1778 typedef typename SchemaType::Context Context;
1783 const SchemaDocumentType& schemaDocument,
1788 StateAllocator* allocator = 0,
1789 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1790 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1792 schemaDocument_(&schemaDocument),
1794 outputHandler_(GetNullHandler()),
1795 stateAllocator_(allocator),
1796 ownStateAllocator_(0),
1797 schemaStack_(allocator, schemaStackCapacity),
1798 documentStack_(allocator, documentStackCapacity),
1806 StateAllocator& GetStateAllocator() {
1807 if (!stateAllocator_)
1808 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator());
1809 return *stateAllocator_;
1813 if (schemaStack_.Empty())
1816 if (CurrentContext().inArray)
1819 if (!CurrentSchema().BeginValue(CurrentContext()))
1822 SizeType count = CurrentContext().patternPropertiesSchemaCount;
1823 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
1824 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
1825 bool valueUniqueness = CurrentContext().valueUniqueness;
1826 if (CurrentContext().valueSchema)
1827 PushSchema(*CurrentContext().valueSchema);
1830 CurrentContext().objectPatternValidatorType = patternValidatorType;
1831 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
1832 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
1833 va =
static_cast<ISchemaValidator**
>(
MallocState(
sizeof(ISchemaValidator*) * count));
1834 for (
SizeType i = 0; i < count; i++)
1838 CurrentContext().arrayUniqueness = valueUniqueness;
1844 if (!CurrentSchema().EndValue(CurrentContext()))
1847 #if RAPIDJSON_SCHEMA_VERBOSE
1849 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
1851 *documentStack_.template Push<Ch>() =
'\0';
1852 documentStack_.template Pop<Ch>(1);
1853 internal::PrintValidatorPointers(depth_, sb.
GetString(), documentStack_.template Bottom<Ch>());
1856 uint64_t h = CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(CurrentContext().hasher)->
GetHashCode() : 0;
1860 if (!schemaStack_.Empty()) {
1861 Context& context = CurrentContext();
1862 if (context.valueUniqueness) {
1863 HashCodeArray*
a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
1865 CurrentContext().arrayElementHashCodes =
a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
1867 if (itr->GetUint64() == h)
1869 a->PushBack(h, GetStateAllocator());
1874 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
1880 void AppendToken(
const Ch* str,
SizeType len) {
1881 documentStack_.template Reserve<Ch>(1 + len * 2);
1882 *documentStack_.template PushUnsafe<Ch>() =
'/';
1883 for (
SizeType i = 0; i < len; i++) {
1884 if (str[i] ==
'~') {
1885 *documentStack_.template PushUnsafe<Ch>() =
'~';
1886 *documentStack_.template PushUnsafe<Ch>() =
'0';
1888 else if (str[i] ==
'/') {
1889 *documentStack_.template PushUnsafe<Ch>() =
'~';
1890 *documentStack_.template PushUnsafe<Ch>() =
'1';
1893 *documentStack_.template PushUnsafe<Ch>() = str[i];
1897 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, &schema); }
1899 RAPIDJSON_FORCEINLINE
void PopSchema() {
1900 Context*
c = schemaStack_.template Pop<Context>(1);
1901 if (HashCodeArray*
a =
static_cast<HashCodeArray*
>(
c->arrayElementHashCodes)) {
1902 a->~HashCodeArray();
1903 StateAllocator::Free(
a);
1908 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
1909 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
1910 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
1912 static OutputHandler& GetNullHandler() {
1913 static OutputHandler nullHandler;
1917 static const size_t kDefaultSchemaStackCapacity = 1024;
1918 static const size_t kDefaultDocumentStackCapacity = 256;
1919 const SchemaDocumentType* schemaDocument_;
1921 OutputHandler& outputHandler_;
1922 StateAllocator* stateAllocator_;
1923 StateAllocator* ownStateAllocator_;
1927 #if RAPIDJSON_SCHEMA_VERBOSE
1948 unsigned parseFlags,
1949 typename InputStream,
1950 typename SourceEncoding,
1956 typedef typename InputStream::Ch
Ch;
1963 SchemaValidatingReader(InputStream& is,
const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
1965 template <
typename Handler>
1969 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
1971 isValid_ = validator.
IsValid();
1974 invalidSchemaKeyword_ = 0;
1983 return parseResult_;
1994 const SchemaDocumentType& sd_;
1998 const Ch* invalidSchemaKeyword_;
2006 #endif // RAPIDJSON_SCHEMA_H_