15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
23 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
24 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
26 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
29 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
30 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
32 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
35 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
37 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
41 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
42 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
44 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
47 #ifndef RAPIDJSON_SCHEMA_VERBOSE
48 #define RAPIDJSON_SCHEMA_VERBOSE 0
51 #if RAPIDJSON_SCHEMA_VERBOSE
58 RAPIDJSON_DIAG_OFF(effc++)
62 RAPIDJSON_DIAG_OFF(weak-vtables)
63 RAPIDJSON_DIAG_OFF(exit-
time-destructors)
64 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
65 RAPIDJSON_DIAG_OFF(variadic-macros)
66 #elif defined(_MSC_VER)
67 RAPIDJSON_DIAG_OFF(4512)
75 #if RAPIDJSON_SCHEMA_VERBOSE
79 inline void PrintInvalidKeyword(
const char* keyword) {
80 printf(
"Fail keyword: %s\n", keyword);
83 inline void PrintInvalidKeyword(
const wchar_t* keyword) {
84 wprintf(L
"Fail keyword: %ls\n", keyword);
87 inline void PrintInvalidDocument(
const char* document) {
88 printf(
"Fail document: %s\n\n", document);
91 inline void PrintInvalidDocument(
const wchar_t* document) {
92 wprintf(L
"Fail document: %ls\n\n", document);
95 inline void PrintValidatorPointers(
unsigned depth,
const char* s,
const char* d) {
96 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
99 inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
100 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
110 #if RAPIDJSON_SCHEMA_VERBOSE
111 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
113 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
116 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
117 RAPIDJSON_MULTILINEMACRO_BEGIN\
118 context.invalidKeyword = keyword.GetString();\
119 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
121 RAPIDJSON_MULTILINEMACRO_END
126 template <
typename ValueType,
typename Allocator>
131 template <
typename SchemaDocumentType>
146 template <
typename SchemaType>
162 template <
typename SchemaType>
165 typedef typename SchemaType::Ch
Ch;
166 typedef typename SchemaType::SValue
SValue;
219 template<
typename Encoding,
typename Allocator>
222 typedef typename Encoding::Ch
Ch;
224 Hasher(
Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
228 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
229 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
230 bool Int64(
int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
231 bool Uint64(
uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
234 if (d < 0) n.u.i =
static_cast<int64_t>(d);
235 else n.u.u =
static_cast<uint64_t>(d);
237 return WriteNumber(n);
254 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
255 for (
SizeType i = 0; i < memberCount; i++)
256 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
257 *stack_.template Push<uint64_t>() = h;
264 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
265 for (
SizeType i = 0; i < elementCount; i++)
267 *stack_.template Push<uint64_t>() = h;
275 return *stack_.template Top<uint64_t>();
279 static const size_t kDefaultSize = 256;
288 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
290 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
292 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
295 const unsigned char* d =
static_cast<const unsigned char*
>(data);
296 for (
size_t i = 0; i < len; i++)
298 *stack_.template Push<uint64_t>() = h;
309 Stack<Allocator> stack_;
315 template <
typename SchemaDocumentType>
321 typedef typename ValueType::Ch
Ch;
395 template <
typename SchemaDocumentType>
398 typedef typename SchemaDocumentType::ValueType
ValueType;
402 typedef typename EncodingType::Ch
Ch;
410 allocator_(allocator),
411 uri_(schemaDocument->
GetURI(), *allocator),
413 typeless_(schemaDocument->GetTypeless()),
417 type_((1 << kTotalSchemaType) - 1),
419 notValidatorIndex_(),
421 additionalPropertiesSchema_(),
422 patternProperties_(),
423 patternPropertyCount_(),
427 additionalProperties_(
true),
430 hasSchemaDependencies_(),
431 additionalItemsSchema_(),
437 additionalItems_(
true),
442 exclusiveMinimum_(
false),
443 exclusiveMaximum_(
false),
444 defaultValueLength_(0)
446 typedef typename SchemaDocumentType::ValueType
ValueType;
447 typedef typename ValueType::ConstValueIterator ConstValueIterator;
448 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
450 if (!
value.IsObject())
457 else if (v->IsArray())
458 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
463 if (v->IsArray() && v->Size() > 0) {
464 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(
uint64_t) * v->Size()));
465 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
467 char buffer[256 + 24];
469 EnumHasherType h(&hasherAllocator, 256);
471 enum_[enumCount_++] = h.GetHashCode();
475 if (schemaDocument) {
476 AssignIfExist(allOf_, *schemaDocument, p,
value, GetAllOfString(), document);
477 AssignIfExist(anyOf_, *schemaDocument, p,
value, GetAnyOfString(), document);
478 AssignIfExist(oneOf_, *schemaDocument, p,
value, GetOneOfString(), document);
482 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
483 notValidatorIndex_ = validatorCount_;
489 const ValueType* properties = GetMember(
value, GetPropertiesString());
490 const ValueType* required = GetMember(
value, GetRequiredString());
491 const ValueType* dependencies = GetMember(
value, GetDependenciesString());
496 if (properties && properties->IsObject())
497 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
498 AddUniqueElement(allProperties, itr->name);
500 if (required && required->IsArray())
501 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
503 AddUniqueElement(allProperties, *itr);
505 if (dependencies && dependencies->IsObject())
506 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
507 AddUniqueElement(allProperties, itr->name);
508 if (itr->value.IsArray())
509 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
511 AddUniqueElement(allProperties, *i);
514 if (allProperties.Size() > 0) {
515 propertyCount_ = allProperties.Size();
516 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(
Property) * propertyCount_));
517 for (
SizeType i = 0; i < propertyCount_; i++) {
519 properties_[i].name = allProperties[i];
520 properties_[i].schema = typeless_;
525 if (properties && properties->IsObject()) {
526 PointerType q = p.Append(GetPropertiesString(), allocator_);
527 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
529 if (FindPropertyIndex(itr->name, &index))
530 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
534 if (
const ValueType* v = GetMember(
value, GetPatternPropertiesString())) {
535 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
536 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
537 patternPropertyCount_ = 0;
539 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
540 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
541 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
542 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
543 patternPropertyCount_++;
547 if (required && required->IsArray())
548 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
549 if (itr->IsString()) {
551 if (FindPropertyIndex(*itr, &index)) {
552 properties_[index].required =
true;
557 if (dependencies && dependencies->IsObject()) {
558 PointerType q = p.Append(GetDependenciesString(), allocator_);
559 hasDependencies_ =
true;
560 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
562 if (FindPropertyIndex(itr->name, &sourceIndex)) {
563 if (itr->value.IsArray()) {
564 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
565 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
566 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
568 if (FindPropertyIndex(*targetItr, &targetIndex))
569 properties_[sourceIndex].dependencies[targetIndex] =
true;
572 else if (itr->value.IsObject()) {
573 hasSchemaDependencies_ =
true;
574 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
575 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
582 if (
const ValueType* v = GetMember(
value, GetAdditionalPropertiesString())) {
584 additionalProperties_ = v->GetBool();
585 else if (v->IsObject())
586 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
589 AssignIfExist(minProperties_,
value, GetMinPropertiesString());
590 AssignIfExist(maxProperties_,
value, GetMaxPropertiesString());
594 PointerType q = p.Append(GetItemsString(), allocator_);
596 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
597 else if (v->IsArray()) {
598 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
600 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
601 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
605 AssignIfExist(minItems_,
value, GetMinItemsString());
606 AssignIfExist(maxItems_,
value, GetMaxItemsString());
608 if (
const ValueType* v = GetMember(
value, GetAdditionalItemsString())) {
610 additionalItems_ = v->GetBool();
611 else if (v->IsObject())
612 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
615 AssignIfExist(uniqueItems_,
value, GetUniqueItemsString());
618 AssignIfExist(minLength_,
value, GetMinLengthString());
619 AssignIfExist(maxLength_,
value, GetMaxLengthString());
622 pattern_ = CreatePattern(*v);
627 minimum_.CopyFrom(*v, *allocator_);
631 maximum_.CopyFrom(*v, *allocator_);
633 AssignIfExist(exclusiveMinimum_,
value, GetExclusiveMinimumString());
634 AssignIfExist(exclusiveMaximum_,
value, GetExclusiveMaximumString());
637 if (v->IsNumber() && v->GetDouble() > 0.0)
638 multipleOf_.CopyFrom(*v, *allocator_);
641 if (
const ValueType* v = GetMember(
value, GetDefaultValueString()))
643 defaultValueLength_ = v->GetStringLength();
648 AllocatorType::Free(enum_);
650 for (
SizeType i = 0; i < propertyCount_; i++)
652 AllocatorType::Free(properties_);
654 if (patternProperties_) {
655 for (
SizeType i = 0; i < patternPropertyCount_; i++)
656 patternProperties_[i].~PatternProperty();
657 AllocatorType::Free(patternProperties_);
659 AllocatorType::Free(itemsTuple_);
660 #if RAPIDJSON_SCHEMA_HAS_REGEX
662 pattern_->~RegexType();
663 AllocatorType::Free(pattern_);
679 context.valueUniqueness =
true;
682 context.valueSchema = itemsList_;
683 else if (itemsTuple_) {
684 if (
context.arrayElementIndex < itemsTupleCount_)
686 else if (additionalItemsSchema_)
687 context.valueSchema = additionalItemsSchema_;
688 else if (additionalItems_)
689 context.valueSchema = typeless_;
696 context.valueSchema = typeless_;
704 if (
context.patternPropertiesValidatorCount > 0) {
705 bool otherValid =
false;
708 otherValid =
context.patternPropertiesValidators[--
count]->IsValid();
710 bool patternValid =
true;
712 if (!
context.patternPropertiesValidators[i]->IsValid()) {
713 patternValid =
false;
724 if (!patternValid || !otherValid) {
729 else if (!patternValid && !otherValid) {
737 for (
SizeType i = 0; i < enumCount_; i++)
740 context.error_handler.DisallowedValue();
746 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
747 if (!
context.validators[i]->IsValid()) {
748 context.error_handler.NotAllOf(&
context.validators[allOf_.begin], allOf_.count);
752 if (anyOf_.schemas) {
753 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
754 if (
context.validators[i]->IsValid())
756 context.error_handler.NoneOf(&
context.validators[anyOf_.begin], anyOf_.count);
761 if (oneOf_.schemas) {
762 bool oneValid =
false;
763 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
764 if (
context.validators[i]->IsValid()) {
766 context.error_handler.NotOneOf(&
context.validators[oneOf_.begin], oneOf_.count);
772 context.error_handler.NotOneOf(&
context.validators[oneOf_.begin], oneOf_.count);
777 if (not_ &&
context.validators[notValidatorIndex_]->IsValid()) {
778 context.error_handler.Disallowed();
786 if (!(type_ & (1 << kNullSchemaType))) {
787 DisallowedType(
context, GetNullString());
790 return CreateParallelValidator(
context);
794 if (!(type_ & (1 << kBooleanSchemaType))) {
795 DisallowedType(
context, GetBooleanString());
798 return CreateParallelValidator(
context);
804 return CreateParallelValidator(
context);
810 return CreateParallelValidator(
context);
816 return CreateParallelValidator(
context);
822 return CreateParallelValidator(
context);
826 if (!(type_ & (1 << kNumberSchemaType))) {
827 DisallowedType(
context, GetNumberString());
831 if (!minimum_.IsNull() && !CheckDoubleMinimum(
context, d))
834 if (!maximum_.IsNull() && !CheckDoubleMaximum(
context, d))
837 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(
context, d))
840 return CreateParallelValidator(
context);
844 if (!(type_ & (1 << kStringSchemaType))) {
845 DisallowedType(
context, GetStringString());
849 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
851 if (internal::CountStringCodePoint<EncodingType>(str, length, &
count)) {
852 if (
count < minLength_) {
853 context.error_handler.TooShort(str, length, minLength_);
856 if (
count > maxLength_) {
857 context.error_handler.TooLong(str, length, maxLength_);
863 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
864 context.error_handler.DoesNotMatch(str, length);
868 return CreateParallelValidator(
context);
872 if (!(type_ & (1 << kObjectSchemaType))) {
873 DisallowedType(
context, GetObjectString());
877 if (hasDependencies_ || hasRequired_) {
878 context.propertyExist =
static_cast<bool*
>(
context.factory.MallocState(
sizeof(
bool) * propertyCount_));
879 std::memset(
context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
882 if (patternProperties_) {
885 context.patternPropertiesSchemaCount = 0;
889 return CreateParallelValidator(
context);
893 if (patternProperties_) {
894 context.patternPropertiesSchemaCount = 0;
895 for (
SizeType i = 0; i < patternPropertyCount_; i++)
896 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
897 context.patternPropertiesSchemas[
context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
898 context.valueSchema = typeless_;
903 if (FindPropertyIndex(
ValueType(str, len).Move(), &index)) {
904 if (
context.patternPropertiesSchemaCount > 0) {
905 context.patternPropertiesSchemas[
context.patternPropertiesSchemaCount++] = properties_[index].schema;
906 context.valueSchema = typeless_;
910 context.valueSchema = properties_[index].schema;
913 context.propertyExist[index] =
true;
918 if (additionalPropertiesSchema_) {
919 if (additionalPropertiesSchema_ &&
context.patternPropertiesSchemaCount > 0) {
920 context.patternPropertiesSchemas[
context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
921 context.valueSchema = typeless_;
925 context.valueSchema = additionalPropertiesSchema_;
928 else if (additionalProperties_) {
929 context.valueSchema = typeless_;
933 if (
context.patternPropertiesSchemaCount == 0) {
934 context.error_handler.DisallowedProperty(str, len);
943 context.error_handler.StartMissingProperties();
944 for (
SizeType index = 0; index < propertyCount_; index++)
945 if (properties_[index].required && !
context.propertyExist[index])
946 if (properties_[index].schema->defaultValueLength_ == 0 )
947 context.error_handler.AddMissingProperty(properties_[index].
name);
948 if (
context.error_handler.EndMissingProperties())
952 if (memberCount < minProperties_) {
953 context.error_handler.TooFewProperties(memberCount, minProperties_);
957 if (memberCount > maxProperties_) {
958 context.error_handler.TooManyProperties(memberCount, maxProperties_);
962 if (hasDependencies_) {
963 context.error_handler.StartDependencyErrors();
964 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
966 if (
context.propertyExist[sourceIndex]) {
967 if (
source.dependencies) {
968 context.error_handler.StartMissingDependentProperties();
969 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
970 if (
source.dependencies[targetIndex] && !
context.propertyExist[targetIndex])
971 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].
name);
972 context.error_handler.EndMissingDependentProperties(
source.name);
974 else if (
source.dependenciesSchema) {
976 if (!dependenciesValidator->
IsValid())
977 context.error_handler.AddDependencySchemaError(
source.name, dependenciesValidator);
981 if (
context.error_handler.EndDependencyErrors())
989 if (!(type_ & (1 << kArraySchemaType))) {
990 DisallowedType(
context, GetArrayString());
997 return CreateParallelValidator(
context);
1003 if (elementCount < minItems_) {
1004 context.error_handler.TooFewItems(elementCount, minItems_);
1008 if (elementCount > maxItems_) {
1009 context.error_handler.TooManyItems(elementCount, maxItems_);
1017 #define RAPIDJSON_STRING_(name, ...) \
1018 static const ValueType& Get##name##String() {\
1019 static const Ch s[] = { __VA_ARGS__, '\0' };\
1020 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1037 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1039 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1040 RAPIDJSON_STRING_(PatternProperties, 'p', '
a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1041 RAPIDJSON_STRING_(AdditionalProperties, '
a', 'd', 'd', 'i', 't', 'i', 'o', 'n', '
a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1042 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1043 RAPIDJSON_STRING_(MaxProperties, 'm', '
a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1047 RAPIDJSON_STRING_(AdditionalItems, '
a', 'd', 'd', 'i', 't', 'i', 'o', 'n', '
a', 'l', 'I', 't', 'e', 'm', 's')
1048 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1054 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1055 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', '
a', 'x', 'i', 'm', 'u', 'm')
1056 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1059 #undef RAPIDJSON_STRING_
1062 enum SchemaValueType {
1073 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1075 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1076 typedef std::basic_regex<Ch> RegexType;
1078 typedef char RegexType;
1081 struct SchemaArray {
1082 SchemaArray() : schemas(),
count() {}
1083 ~SchemaArray() { AllocatorType::Free(schemas); }
1089 template <
typename V1,
typename V2>
1090 void AddUniqueElement(V1&
a,
const V2& v) {
1091 for (
typename V1::ConstValueIterator itr =
a.Begin(); itr !=
a.End(); ++itr)
1094 V1 c(v, *allocator_);
1095 a.PushBack(c, *allocator_);
1099 typename ValueType::ConstMemberIterator itr =
value.FindMember(
name);
1100 return itr !=
value.MemberEnd() ? &(itr->value) : 0;
1111 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1117 if (v->IsArray() && v->Size() > 0) {
1119 out.count = v->Size();
1120 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(
out.count *
sizeof(
const Schema*)));
1123 schemaDocument.CreateSchema(&
out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1124 out.begin = validatorCount_;
1125 validatorCount_ +=
out.count;
1130 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1131 template <
typename ValueType>
1133 if (
value.IsString()) {
1134 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(
value.GetString(), allocator_);
1135 if (!r->IsValid()) {
1137 AllocatorType::Free(r);
1145 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1146 GenericRegexSearch<RegexType> rs(*pattern);
1147 return rs.Search(str);
1149 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1150 template <
typename ValueType>
1152 if (
value.IsString())
1154 return new (allocator_->Malloc(
sizeof(RegexType))) RegexType(
value.GetString(), std::size_t(
value.GetStringLength()), std::regex_constants::ECMAScript);
1156 catch (
const std::regex_error&) {
1161 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1162 std::match_results<const Ch*> r;
1163 return std::regex_search(str, str + length, r, *pattern);
1166 template <
typename ValueType>
1167 RegexType* CreatePattern(
const ValueType&) {
return 0; }
1169 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1173 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1174 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1175 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1176 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1177 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1178 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1179 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1183 if (enum_ ||
context.arrayUniqueness)
1186 if (validatorCount_) {
1188 context.validators =
static_cast<ISchemaValidator**
>(
context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1189 context.validatorCount = validatorCount_;
1192 CreateSchemaValidators(
context, allOf_);
1195 CreateSchemaValidators(
context, anyOf_);
1198 CreateSchemaValidators(
context, oneOf_);
1201 context.validators[notValidatorIndex_] =
context.factory.CreateSchemaValidator(*not_);
1203 if (hasSchemaDependencies_) {
1204 for (
SizeType i = 0; i < propertyCount_; i++)
1205 if (properties_[i].dependenciesSchema)
1206 context.validators[properties_[i].dependenciesValidatorIndex] =
context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1213 void CreateSchemaValidators(
Context&
context,
const SchemaArray& schemas)
const {
1214 for (
SizeType i = 0; i < schemas.count; i++)
1215 context.validators[schemas.begin + i] =
context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1221 const Ch* str =
name.GetString();
1222 for (
SizeType index = 0; index < propertyCount_; index++)
1223 if (properties_[index].
name.GetStringLength() == len &&
1224 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(
Ch) * len) == 0))
1233 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1234 DisallowedType(
context, GetIntegerString());
1238 if (!minimum_.IsNull()) {
1239 if (minimum_.IsInt64()) {
1240 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1241 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1245 else if (minimum_.IsUint64()) {
1246 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1249 else if (!CheckDoubleMinimum(
context,
static_cast<double>(i)))
1253 if (!maximum_.IsNull()) {
1254 if (maximum_.IsInt64()) {
1255 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1256 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1260 else if (maximum_.IsUint64()) { }
1262 else if (!CheckDoubleMaximum(
context,
static_cast<double>(i)))
1266 if (!multipleOf_.IsNull()) {
1267 if (multipleOf_.IsUint64()) {
1268 if (
static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1269 context.error_handler.NotMultipleOf(i, multipleOf_);
1273 else if (!CheckDoubleMultipleOf(
context,
static_cast<double>(i)))
1281 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1282 DisallowedType(
context, GetIntegerString());
1286 if (!minimum_.IsNull()) {
1287 if (minimum_.IsUint64()) {
1288 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1289 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1293 else if (minimum_.IsInt64())
1295 else if (!CheckDoubleMinimum(
context,
static_cast<double>(i)))
1299 if (!maximum_.IsNull()) {
1300 if (maximum_.IsUint64()) {
1301 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1302 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1306 else if (maximum_.IsInt64()) {
1307 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1310 else if (!CheckDoubleMaximum(
context,
static_cast<double>(i)))
1314 if (!multipleOf_.IsNull()) {
1315 if (multipleOf_.IsUint64()) {
1316 if (i % multipleOf_.GetUint64() != 0) {
1317 context.error_handler.NotMultipleOf(i, multipleOf_);
1321 else if (!CheckDoubleMultipleOf(
context,
static_cast<double>(i)))
1329 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1330 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1337 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1338 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1345 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1346 double q = std::floor(
a / b);
1347 double r =
a - q * b;
1349 context.error_handler.NotMultipleOf(d, multipleOf_);
1357 eh.StartDisallowedType();
1359 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1360 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1361 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1362 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1363 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1365 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1366 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1368 eh.EndDisallowedType(actualType);
1372 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1373 ~
Property() { AllocatorType::Free(dependencies); }
1377 SizeType dependenciesValidatorIndex;
1382 struct PatternProperty {
1383 PatternProperty() : schema(), pattern() {}
1384 ~PatternProperty() {
1386 pattern->~RegexType();
1387 AllocatorType::Free(pattern);
1409 const SchemaType* additionalPropertiesSchema_;
1410 PatternProperty* patternProperties_;
1415 bool additionalProperties_;
1416 bool hasDependencies_;
1418 bool hasSchemaDependencies_;
1426 bool additionalItems_;
1429 RegexType* pattern_;
1436 bool exclusiveMinimum_;
1437 bool exclusiveMaximum_;
1442 template<
typename Stack,
typename Ch>
1445 *documentStack.template Push<Ch>() =
'/';
1447 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ?
u32toa(index, buffer) :
u64toa(index, buffer)) - buffer);
1448 for (
size_t i = 0; i < length; i++)
1449 *documentStack.template Push<Ch>() =
static_cast<Ch
>(buffer[i]);
1454 template <
typename Stack>
1458 char *buffer = documentStack.template Push<char>(1 + 10);
1461 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1464 char *buffer = documentStack.template Push<char>(1 + 20);
1467 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1477 template <
typename SchemaDocumentType>
1480 typedef typename SchemaDocumentType::Ch
Ch;
1498 template <
typename ValueT,
typename Allocator = CrtAllocator>
1505 typedef typename EncodingType::Ch
Ch;
1510 template <
typename,
typename,
typename>
1525 remoteProvider_(remoteProvider),
1526 allocator_(allocator),
1530 schemaMap_(allocator, kInitialSchemaMapSize),
1531 schemaRef_(allocator, kInitialSchemaRefSize)
1537 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1544 CreateSchemaRecursive(&root_,
PointerType(), document, document);
1547 while (!schemaRef_.Empty()) {
1548 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1549 if (
const SchemaType* s = GetSchema(refEntry->target)) {
1550 if (refEntry->schema)
1551 *refEntry->schema = s;
1554 if (!GetSchema(refEntry->source)) {
1555 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source,
const_cast<SchemaType*
>(s),
false, allocator_);
1558 else if (refEntry->schema)
1559 *refEntry->schema = typeless_;
1561 refEntry->~SchemaRefEntry();
1566 schemaRef_.ShrinkToFit();
1569 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1572 remoteProvider_(rhs.remoteProvider_),
1573 allocator_(rhs.allocator_),
1574 ownAllocator_(rhs.ownAllocator_),
1576 typeless_(rhs.typeless_),
1581 rhs.remoteProvider_ = 0;
1583 rhs.ownAllocator_ = 0;
1590 while (!schemaMap_.Empty())
1591 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1594 typeless_->~SchemaType();
1595 Allocator::Free(typeless_);
1612 struct SchemaRefEntry {
1619 struct SchemaEntry {
1623 schema->~SchemaType();
1624 Allocator::Free(schema);
1634 *schema = typeless_;
1639 CreateSchema(schema,
pointer, v, document);
1641 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1642 CreateSchemaRecursive(0,
pointer.Append(itr->name, allocator_), itr->value, document);
1645 for (
SizeType i = 0; i < v.Size(); i++)
1646 CreateSchemaRecursive(0,
pointer.Append(i, allocator_), v[i], document);
1652 if (!HandleRefSchema(
pointer, schema, v, document)) {
1654 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(
pointer, s,
true, allocator_);
1662 static const Ch kRefString[] = {
'$',
'r',
'e',
'f',
'\0' };
1663 static const ValueType kRefValue(kRefString, 4);
1665 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1666 if (itr == v.MemberEnd())
1669 if (itr->value.IsString()) {
1670 SizeType len = itr->value.GetStringLength();
1672 const Ch* s = itr->value.GetString();
1674 while (i < len && s[i] !=
'#')
1678 if (remoteProvider_) {
1685 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(
source,
const_cast<SchemaType*
>(sc),
false, allocator_);
1692 else if (s[i] ==
'#') {
1696 if (HandleRefSchema(
source, schema, *nv, document))
1699 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(
source,
pointer, schema, allocator_);
1709 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1710 if (
pointer == target->pointer)
1711 return target->schema;
1716 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1717 if (schema == target->schema)
1718 return target->pointer;
1722 const SchemaType* GetTypeless()
const {
return typeless_; }
1724 static const size_t kInitialSchemaMapSize = 64;
1725 static const size_t kInitialSchemaRefSize = 64;
1758 typename SchemaDocumentType,
1771 typedef typename EncodingType::Ch
Ch;
1783 const SchemaDocumentType& schemaDocument,
1784 StateAllocator* allocator = 0,
1785 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1786 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1788 schemaDocument_(&schemaDocument),
1789 root_(schemaDocument.GetRoot()),
1790 stateAllocator_(allocator),
1791 ownStateAllocator_(0),
1792 schemaStack_(allocator, schemaStackCapacity),
1793 documentStack_(allocator, documentStackCapacity),
1797 missingDependents_(),
1813 const SchemaDocumentType& schemaDocument,
1814 OutputHandler& outputHandler,
1815 StateAllocator* allocator = 0,
1816 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1817 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1819 schemaDocument_(&schemaDocument),
1820 root_(schemaDocument.GetRoot()),
1821 stateAllocator_(allocator),
1822 ownStateAllocator_(0),
1823 schemaStack_(allocator, schemaStackCapacity),
1824 documentStack_(allocator, documentStackCapacity),
1825 outputHandler_(&outputHandler),
1828 missingDependents_(),
1844 while (!schemaStack_.Empty())
1846 documentStack_.Clear();
1848 currentError_.SetNull();
1849 missingDependents_.SetNull();
1863 return schemaStack_.Empty() ?
PointerType() : CurrentSchema().GetPointer();
1868 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1873 if (documentStack_.Empty()) {
1877 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(
Ch));
1882 AddNumberError(SchemaType::GetMultipleOfString(),
ValueType(actual).Move(), expected);
1885 AddNumberError(SchemaType::GetMultipleOfString(),
ValueType(actual).Move(), expected);
1888 AddNumberError(SchemaType::GetMultipleOfString(),
ValueType(actual).Move(), expected);
1891 AddNumberError(SchemaType::GetMaximumString(),
ValueType(actual).Move(), expected,
1892 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1895 AddNumberError(SchemaType::GetMaximumString(),
ValueType(actual).Move(), expected,
1896 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1899 AddNumberError(SchemaType::GetMaximumString(),
ValueType(actual).Move(), expected,
1900 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1903 AddNumberError(SchemaType::GetMinimumString(),
ValueType(actual).Move(), expected,
1904 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1907 AddNumberError(SchemaType::GetMinimumString(),
ValueType(actual).Move(), expected,
1908 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1911 AddNumberError(SchemaType::GetMinimumString(),
ValueType(actual).Move(), expected,
1912 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1916 AddNumberError(SchemaType::GetMaxLengthString(),
1917 ValueType(str, length, GetStateAllocator()).Move(),
SValue(expected).Move());
1920 AddNumberError(SchemaType::GetMinLengthString(),
1921 ValueType(str, length, GetStateAllocator()).Move(),
SValue(expected).Move());
1924 currentError_.SetObject();
1925 currentError_.AddMember(GetActualString(),
ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
1926 AddCurrentError(SchemaType::GetPatternString());
1930 currentError_.SetObject();
1931 currentError_.AddMember(GetDisallowedString(),
ValueType(index).Move(), GetStateAllocator());
1932 AddCurrentError(SchemaType::GetAdditionalItemsString(),
true);
1935 AddNumberError(SchemaType::GetMinItemsString(),
1939 AddNumberError(SchemaType::GetMaxItemsString(),
1944 duplicates.PushBack(index1, GetStateAllocator());
1945 duplicates.PushBack(index2, GetStateAllocator());
1946 currentError_.SetObject();
1947 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1948 AddCurrentError(SchemaType::GetUniqueItemsString(),
true);
1952 AddNumberError(SchemaType::GetMaxPropertiesString(),
1956 AddNumberError(SchemaType::GetMinPropertiesString(),
1960 currentError_.SetArray();
1963 currentError_.PushBack(
ValueType(
name, GetStateAllocator()).Move(), GetStateAllocator());
1966 if (currentError_.Empty())
1969 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1970 currentError_ =
error;
1971 AddCurrentError(SchemaType::GetRequiredString());
1979 currentError_.SetObject();
1980 currentError_.AddMember(GetDisallowedString(),
ValueType(
name, length, GetStateAllocator()).Move(), GetStateAllocator());
1981 AddCurrentError(SchemaType::GetAdditionalPropertiesString(),
true);
1985 currentError_.SetObject();
1988 missingDependents_.SetArray();
1991 missingDependents_.PushBack(
ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1994 if (!missingDependents_.Empty())
1995 currentError_.AddMember(
ValueType(sourceName, GetStateAllocator()).Move(),
1996 missingDependents_, GetStateAllocator());
1999 currentError_.AddMember(
ValueType(sourceName, GetStateAllocator()).Move(),
2003 if (currentError_.ObjectEmpty())
2006 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2007 currentError_ =
error;
2008 AddCurrentError(SchemaType::GetDependenciesString());
2013 currentError_.SetObject();
2014 AddCurrentError(SchemaType::GetEnumString());
2017 currentError_.SetArray();
2020 currentError_.PushBack(
ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2024 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2025 error.AddMember(GetActualString(),
ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2026 currentError_ =
error;
2027 AddCurrentError(SchemaType::GetTypeString());
2035 AddErrorArray(SchemaType::GetAnyOfString(), subvalidators,
count);
2038 AddErrorArray(SchemaType::GetOneOfString(), subvalidators,
count);
2041 currentError_.SetObject();
2042 AddCurrentError(SchemaType::GetNotString());
2045 #define RAPIDJSON_STRING_(name, ...) \
2046 static const StringRefType& Get##name##String() {\
2047 static const Ch s[] = { __VA_ARGS__, '\0' };\
2048 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2052 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2056 RAPIDJSON_STRING_(
Disallowed, 'd', 'i', 's', '
a', 'l', 'l', 'o', 'w', 'e', 'd')
2059 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', '
a', 't', 'e', 's')
2061 #undef RAPIDJSON_STRING_
2063 #if RAPIDJSON_SCHEMA_VERBOSE
2064 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2065 RAPIDJSON_MULTILINEMACRO_BEGIN\
2066 *documentStack_.template Push<Ch>() = '\0';\
2067 documentStack_.template Pop<Ch>(1);\
2068 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2069 RAPIDJSON_MULTILINEMACRO_END
2071 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2074 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2075 if (!valid_) return false; \
2076 if (!BeginValue() || !CurrentSchema().method arg1) {\
2077 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2078 return valid_ = false;\
2081 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2082 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2083 if (context->hasher)\
2084 static_cast<HasherType*>(context->hasher)->method arg2;\
2085 if (context->validators)\
2086 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2087 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2088 if (context->patternPropertiesValidators)\
2089 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2090 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2093 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2094 return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
2096 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2097 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2098 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2099 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2116 return valid_ = !outputHandler_ || outputHandler_->StartObject();
2120 if (!valid_)
return false;
2121 AppendToken(str, len);
2122 if (!CurrentSchema().
Key(CurrentContext(), str, len,
copy))
return valid_ =
false;
2124 return valid_ = !outputHandler_ || outputHandler_->Key(str, len,
copy);
2128 if (!valid_)
return false;
2130 if (!CurrentSchema().
EndObject(CurrentContext(), memberCount))
return valid_ =
false;
2137 return valid_ = !outputHandler_ || outputHandler_->StartArray();
2141 if (!valid_)
return false;
2143 if (!CurrentSchema().
EndArray(CurrentContext(), elementCount))
return valid_ =
false;
2147 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2148 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2149 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2150 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2155 #if RAPIDJSON_SCHEMA_VERBOSE
2158 &GetStateAllocator());
2164 StateAllocator::Free(v);
2178 StateAllocator::Free(h);
2182 return GetStateAllocator().Malloc(size);
2186 StateAllocator::Free(p);
2190 typedef typename SchemaType::Context Context;
2195 const SchemaDocumentType& schemaDocument,
2197 const char* basePath,
size_t basePathSize,
2201 StateAllocator* allocator = 0,
2202 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2203 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2205 schemaDocument_(&schemaDocument),
2207 stateAllocator_(allocator),
2208 ownStateAllocator_(0),
2209 schemaStack_(allocator, schemaStackCapacity),
2210 documentStack_(allocator, documentStackCapacity),
2214 missingDependents_(),
2220 if (basePath && basePathSize)
2221 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2224 StateAllocator& GetStateAllocator() {
2225 if (!stateAllocator_)
2226 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2227 return *stateAllocator_;
2231 if (schemaStack_.Empty())
2234 if (CurrentContext().inArray)
2237 if (!CurrentSchema().BeginValue(CurrentContext()))
2240 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2241 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2242 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2243 bool valueUniqueness = CurrentContext().valueUniqueness;
2245 PushSchema(*CurrentContext().valueSchema);
2248 CurrentContext().objectPatternValidatorType = patternValidatorType;
2249 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2250 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2251 va =
static_cast<ISchemaValidator**
>(
MallocState(
sizeof(ISchemaValidator*) *
count));
2256 CurrentContext().arrayUniqueness = valueUniqueness;
2262 if (!CurrentSchema().EndValue(CurrentContext()))
2265 #if RAPIDJSON_SCHEMA_VERBOSE
2267 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2269 *documentStack_.template Push<Ch>() =
'\0';
2270 documentStack_.template Pop<Ch>(1);
2271 internal::PrintValidatorPointers(depth_, sb.
GetString(), documentStack_.template Bottom<Ch>());
2274 uint64_t h = CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(CurrentContext().hasher)->
GetHashCode() : 0;
2278 if (!schemaStack_.Empty()) {
2279 Context&
context = CurrentContext();
2280 if (
context.valueUniqueness) {
2281 HashCodeArray*
a =
static_cast<HashCodeArray*
>(
context.arrayElementHashCodes);
2283 CurrentContext().arrayElementHashCodes =
a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
2285 if (itr->GetUint64() == h) {
2289 a->PushBack(h, GetStateAllocator());
2294 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
2300 void AppendToken(
const Ch* str,
SizeType len) {
2301 documentStack_.template Reserve<Ch>(1 + len * 2);
2302 *documentStack_.template PushUnsafe<Ch>() =
'/';
2303 for (
SizeType i = 0; i < len; i++) {
2304 if (str[i] ==
'~') {
2305 *documentStack_.template PushUnsafe<Ch>() =
'~';
2306 *documentStack_.template PushUnsafe<Ch>() =
'0';
2308 else if (str[i] ==
'/') {
2309 *documentStack_.template PushUnsafe<Ch>() =
'~';
2310 *documentStack_.template PushUnsafe<Ch>() =
'1';
2313 *documentStack_.template PushUnsafe<Ch>() = str[i];
2317 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema); }
2319 RAPIDJSON_FORCEINLINE
void PopSchema() {
2320 Context* c = schemaStack_.template Pop<Context>(1);
2321 if (HashCodeArray*
a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
2322 a->~HashCodeArray();
2323 StateAllocator::Free(
a);
2328 void AddErrorLocation(
ValueType& result,
bool parent) {
2331 ((parent && instancePointer.GetTokenCount() > 0)
2332 ?
PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2333 : instancePointer).StringifyUriFragment(sb);
2335 GetStateAllocator());
2336 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2338 memcpy(sb.
Push(CurrentSchema().GetURI().GetStringLength()),
2339 CurrentSchema().GetURI().GetString(),
2340 CurrentSchema().GetURI().GetStringLength() *
sizeof(
Ch));
2343 GetStateAllocator());
2344 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2349 if (member == error_.MemberEnd())
2350 error_.AddMember(keyword,
error, GetStateAllocator());
2352 if (member->value.IsObject()) {
2354 errors.PushBack(member->value, GetStateAllocator());
2355 member->value = errors;
2357 member->value.PushBack(
error, GetStateAllocator());
2361 void AddCurrentError(
const typename SchemaType::ValueType& keyword,
bool parent =
false) {
2362 AddErrorLocation(currentError_, parent);
2363 AddError(
ValueType(keyword, GetStateAllocator(),
false).Move(), currentError_);
2368 AddError(it->name, it->value);
2372 void AddNumberError(
const typename SchemaType::ValueType& keyword,
ValueType& actual,
const SValue& expected,
2373 const typename SchemaType::ValueType& (*exclusive)() = 0) {
2374 currentError_.SetObject();
2375 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2376 currentError_.AddMember(GetExpectedString(),
ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2378 currentError_.AddMember(
ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
2379 AddCurrentError(keyword);
2382 void AddErrorArray(
const typename SchemaType::ValueType& keyword,
2387 currentError_.SetObject();
2388 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2389 AddCurrentError(keyword);
2392 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
2393 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
2394 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
2396 static const size_t kDefaultSchemaStackCapacity = 1024;
2397 static const size_t kDefaultDocumentStackCapacity = 256;
2398 const SchemaDocumentType* schemaDocument_;
2400 StateAllocator* stateAllocator_;
2401 StateAllocator* ownStateAllocator_;
2404 OutputHandler* outputHandler_;
2409 #if RAPIDJSON_SCHEMA_VERBOSE
2430 unsigned parseFlags,
2431 typename InputStream,
2432 typename SourceEncoding,
2438 typedef typename InputStream::Ch
Ch;
2448 template <
typename Handler>
2452 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2454 isValid_ = validator.
IsValid();
2457 invalidSchemaKeyword_ = 0;
2465 error_.CopyFrom(validator.
GetError(), allocator_);
2468 return parseResult_;
2480 const SchemaDocumentType& sd_;
2484 const Ch* invalidSchemaKeyword_;
2486 StackAllocator allocator_;
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
C-runtime library allocator.
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
const SchemaType & GetRoot() const
Get the root schema.
~GenericSchemaDocument()
Destructor.
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
GenericValue< EncodingType, Allocator > URIType
internal::Schema< GenericSchemaDocument > SchemaType
ValueType::EncodingType EncodingType
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
GenericPointer< ValueType, Allocator > PointerType
const URIType & GetURI() const
virtual void DestroryHasher(void *hasher)
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
const ValueType & GetError() const
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
void TooLong(const Ch *str, SizeType length, SizeType expected)
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
void DisallowedItem(SizeType index)
bool String(const Ch *str, SizeType length, bool copy)
SchemaType::SValue SValue
~GenericSchemaValidator()
Destructor.
void StartMissingProperties()
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
GenericValue< EncodingType, StateAllocator > ValueType
void DisallowedProperty(const Ch *name, SizeType length)
void Reset()
Reset the internal states.
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
virtual void FreeState(void *p)
bool EndMissingProperties()
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
void NotMultipleOf(uint64_t actual, const SValue &expected)
GenericStringRef< Ch > StringRefType
bool EndArray(SizeType elementCount)
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
bool Key(const Ch *str, SizeType len, bool copy)
void StartDependencyErrors()
void TooShort(const Ch *str, SizeType length, SizeType expected)
void TooManyItems(SizeType actualCount, SizeType expectedCount)
ValueType & GetError()
Gets the error object.
virtual void * MallocState(size_t size)
void DuplicateItems(SizeType index1, SizeType index2)
void AddMissingDependentProperty(const SValue &targetName)
void AddMissingProperty(const SValue &name)
virtual bool IsValid() const
Checks whether the current state is valid.
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
void StartDisallowedType()
bool EndObject(SizeType memberCount)
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
void NotMultipleOf(int64_t actual, const SValue &expected)
bool EndDependencyErrors()
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
virtual void * CreateHasher()
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
virtual uint64_t GetHashCode(void *hasher)
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
void StartMissingDependentProperties()
SchemaDocumentType::SchemaType SchemaType
SchemaType::EncodingType EncodingType
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
SchemaDocumentType::PointerType PointerType
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
virtual void DestroySchemaValidator(ISchemaValidator *validator)
bool RawNumber(const Ch *str, SizeType length, bool copy)
void NotMultipleOf(double actual, const SValue &expected)
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root)
void DoesNotMatch(const Ch *str, SizeType length)
void TooFewItems(SizeType actualCount, SizeType expectedCount)
void EndMissingDependentProperties(const SValue &sourceName)
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
Represents an in-memory output stream.
size_t GetSize() const
Get the size of string in bytes in the string buffer.
const Ch * GetString() const
GenericMemberIterator< false, Encoding, Allocator >::Iterator MemberIterator
Member iterator for iterating in object.
const GenericValue * ConstValueIterator
Constant value iterator for iterating in array.
virtual ~IGenericRemoteSchemaDocumentProvider()
virtual const SchemaDocumentType * GetRemoteDocument(const Ch *uri, SizeType length)=0
SchemaDocumentType::Ch Ch
Default memory allocator used by the parser and DOM.
A helper class for parsing with validation.
SchemaDocumentType::PointerType PointerType
const PointerType & GetInvalidDocumentPointer() const
bool operator()(Handler &handler)
const ValueType & GetError() const
const PointerType & GetInvalidSchemaPointer() const
const Ch * GetInvalidSchemaKeyword() const
const ParseResult & GetParseResult() const
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
GenericValue< SourceEncoding, StackAllocator > ValueType
Regular expression engine with subset of ECMAscript grammar.
bool Key(const Ch *str, SizeType len, bool copy)
bool EndObject(SizeType memberCount)
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
bool String(const Ch *str, SizeType len, bool)
uint64_t GetHashCode() const
bool EndArray(SizeType elementCount)
bool RawNumber(const Ch *str, SizeType len, bool)
virtual void DestroySchemaValidator(ISchemaValidator *validator)=0
virtual void FreeState(void *p)=0
virtual void * CreateHasher()=0
virtual void DestroryHasher(void *hasher)=0
virtual void * MallocState(size_t size)=0
virtual uint64_t GetHashCode(void *hasher)=0
virtual ~ISchemaStateFactory()
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &)=0
virtual bool IsValid() const =0
virtual ~ISchemaValidator()
virtual void EndMissingDependentProperties(const SValue &sourceName)=0
virtual void DisallowedItem(SizeType index)=0
virtual void NotMultipleOf(int64_t actual, const SValue &expected)=0
SchemaType::SValue SValue
virtual void AddMissingDependentProperty(const SValue &targetName)=0
virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount)=0
virtual bool EndMissingProperties()=0
virtual void DuplicateItems(SizeType index1, SizeType index2)=0
virtual void AddMissingProperty(const SValue &name)=0
virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator)=0
virtual void Disallowed()=0
virtual void TooShort(const Ch *str, SizeType length, SizeType expected)=0
virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual void AboveMaximum(double actual, const SValue &expected, bool exclusive)=0
virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType)=0
virtual void DisallowedProperty(const Ch *name, SizeType length)=0
virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual ~IValidationErrorHandler()
virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual bool EndDependencyErrors()=0
virtual void BelowMinimum(double actual, const SValue &expected, bool exclusive)=0
virtual void TooManyItems(SizeType actualCount, SizeType expectedCount)=0
virtual void DoesNotMatch(const Ch *str, SizeType length)=0
virtual void StartDisallowedType()=0
virtual void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual void StartDependencyErrors()=0
virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)=0
virtual void StartMissingProperties()=0
virtual void DisallowedValue()=0
virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType)=0
virtual void NotMultipleOf(uint64_t actual, const SValue &expected)=0
virtual void NotMultipleOf(double actual, const SValue &expected)=0
virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount)=0
virtual void TooLong(const Ch *str, SizeType length, SizeType expected)=0
virtual void StartMissingDependentProperties()=0
virtual void TooFewItems(SizeType actualCount, SizeType expectedCount)=0
bool Int64(Context &context, int64_t i) const
bool StartArray(Context &context) const
bool StartObject(Context &context) const
SchemaDocumentType::PointerType PointerType
bool Int(Context &context, int i) const
bool Uint64(Context &context, uint64_t u) const
IValidationErrorHandler< Schema > ErrorHandler
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator)
const PointerType & GetPointer() const
bool EndObject(Context &context, SizeType memberCount) const
SchemaDocumentType::AllocatorType AllocatorType
bool EndArray(Context &context, SizeType elementCount) const
bool Double(Context &context, double d) const
SchemaDocumentType::ValueType ValueType
const SValue & GetURI() const
bool String(Context &context, const Ch *str, SizeType length, bool) const
ValueType::EncodingType EncodingType
GenericValue< EncodingType, AllocatorType > SValue
bool Bool(Context &context, bool) const
bool Uint(Context &context, unsigned u) const
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Schema< SchemaDocumentType > SchemaType
SchemaValidationContext< SchemaDocumentType > Context
bool Null(Context &context) const
bool BeginValue(Context &context) const
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
A type-unsafe stack for storing different types of data.
Concept for allocating, resizing and freeing memory block.
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
void * memcpy(void *a, const void *b, size_t c)
#define RAPIDJSON_ASSERT(x)
Assertion.
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
char * u32toa(uint32_t value, char *buffer)
char * u64toa(uint64_t value, char *buffer)
mdb_size_t count(MDB_cursor *cur)
error
Tracks LMDB error codes.
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
void copy(key &AA, const key &A)
const T & move(const T &t)
PolymorphicMatcher< internal::PropertyMatcher< Class, PropertyType > > Property(PropertyType(Class::*property)() const, const PropertyMatcher &matcher)
internal::AnyOfResult2< M1, M2 >::type AnyOf(M1 m1, M2 m2)
internal::AllOfResult2< M1, M2 >::type AllOf(M1 m1, M2 m2)
const GenericPointer< typename T::ValueType > T2 value
const GenericPointer< typename T::ValueType > & pointer
const CharType(& source)[N]
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
#define RAPIDJSON_DELETE(x)
! customization point for global delete
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
GenericSchemaValidator< SchemaDocument > SchemaValidator
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
#define RAPIDJSON_SCHEMA_VERBOSE
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
#define RAPIDJSON_STRING_(name,...)
#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
unsigned __int64 uint64_t
Reference to a constant string (not taking a copy)
Result of parsing (wraps ParseErrorCode)
const SchemaType ** patternPropertiesSchemas
ISchemaValidator ** validators
SizeType arrayElementIndex
SizeType patternPropertiesValidatorCount
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
const SchemaType * valueSchema
IValidationErrorHandler< SchemaType > ErrorHandlerType
@ kPatternValidatorWithProperty
@ kPatternValidatorWithAdditionalProperty
void * arrayElementHashCodes
ISchemaValidator ** patternPropertiesValidators
SizeType patternPropertiesSchemaCount
Schema< SchemaDocumentType > SchemaType
const Ch * invalidKeyword
~SchemaValidationContext()
SchemaType::ValueType ValueType
PatternValidatorType valuePatternValidatorType
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s)
ErrorHandlerType & error_handler
PatternValidatorType objectPatternValidatorType
SchemaValidatorFactoryType & factory
const SchemaType * schema
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)