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);
105 #endif // RAPIDJSON_SCHEMA_VERBOSE 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>
140 virtual bool IsValid()
const = 0;
146 template <
typename SchemaType>
162 template <
typename SchemaType>
166 typedef typename SchemaType::SValue
SValue;
206 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
207 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
219 template<
typename Encoding,
typename Allocator>
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>
395 template <
typename SchemaDocumentType>
398 typedef typename SchemaDocumentType::ValueType
ValueType;
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))
1112 out = static_cast<SizeType>(v->GetUint64());
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; }
1170 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX 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>
1498 template <
typename ValueT,
typename Allocator = CrtAllocator>
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;
1728 Allocator *allocator_;
1729 Allocator *ownAllocator_;
1758 typename SchemaDocumentType,
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());
1976 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->
GetError());
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(),
2000 static_cast<GenericSchemaValidator*>(subvalidator)->
GetError(), GetStateAllocator());
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());
2031 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->
GetError());
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,
2386 errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
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,
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_;
2494 #endif // RAPIDJSON_SCHEMA_H_ void DisallowedItem(SizeType index)
virtual const SchemaDocumentType * GetRemoteDocument(const Ch *uri, SizeType length)=0
virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)=0
const Ch * invalidKeyword
bool EndArray(SizeType elementCount)
void StartDependencyErrors()
char * u64toa(uint64_t value, char *buffer)
virtual void * CreateHasher()
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
virtual ~ISchemaStateFactory()
bool StartArray(Context &context) const
const CharType(& source)[N]
virtual uint64_t GetHashCode(void *hasher)
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
bool Int(Context &context, int i) const
const Ch * GetInvalidSchemaKeyword() const
virtual void NotMultipleOf(int64_t actual, const SValue &expected)=0
void DoesNotMatch(const Ch *str, SizeType length)
virtual bool IsValid() const
Checks whether the current state is valid.
void DuplicateItems(SizeType index1, SizeType index2)
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
SchemaDocumentType::Ch Ch
void StartDisallowedType()
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
bool Uint(Context &context, unsigned u) const
Represents an in-memory output stream.
const PointerType & GetInvalidDocumentPointer() const
bool EndObject(SizeType memberCount)
const SchemaType ** patternPropertiesSchemas
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
void Reset()
Reset the internal states.
size_t GetSize() const
Get the size of string in bytes in the string buffer.
const ValueType & GetError() const
const GenericValue * ConstValueIterator
Constant value iterator for iterating in array.
C-runtime library allocator.
SchemaDocumentType::ValueType ValueType
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType)=0
internal::Schema< GenericSchemaDocument > SchemaType
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
virtual bool IsValid() const =0
void * arrayElementHashCodes
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &)=0
internal::AnyOfResult2< M1, M2 >::type AnyOf(M1 m1, M2 m2)
void AddMissingProperty(const SValue &name)
SchemaValidationContext< SchemaDocumentType > Context
Schema< SchemaDocumentType > SchemaType
virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType)=0
ValueType & GetError()
Gets the error object.
virtual void * CreateHasher()=0
virtual void DestroySchemaValidator(ISchemaValidator *validator)
SchemaDocumentType::SchemaType SchemaType
virtual void AddMissingProperty(const SValue &name)=0
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
PolymorphicMatcher< internal::PropertyMatcher< Class, PropertyType > > Property(PropertyType(Class::*property)() const, const PropertyMatcher &matcher)
A helper class for parsing with validation.
GenericValue< EncodingType, Allocator > URIType
const ParseResult & GetParseResult() const
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
virtual void TooManyItems(SizeType actualCount, SizeType expectedCount)=0
virtual void AddMissingDependentProperty(const SValue &targetName)=0
ValueType::EncodingType EncodingType
bool Null(Context &context) const
void copy(key &AA, const key &A)
bool EndArray(Context &context, SizeType elementCount) const
GenericValue< SourceEncoding, StackAllocator > ValueType
GenericStringRef< Ch > StringRefType
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
virtual void DisallowedValue()=0
SizeType patternPropertiesValidatorCount
SchemaDocumentType::PointerType PointerType
bool String(Context &context, const Ch *str, SizeType length, bool) const
virtual void Disallowed()=0
#define RAPIDJSON_STRING_(name,...)
const SchemaType * schema
virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual void * MallocState(size_t size)=0
SchemaValidatorFactoryType & factory
virtual void StartDisallowedType()=0
bool Key(const Ch *str, SizeType len, bool copy)
bool BeginValue(Context &context) const
const ValueType & GetError() const
virtual ~IValidationErrorHandler()
virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount)=0
PatternValidatorType objectPatternValidatorType
virtual void DisallowedItem(SizeType index)=0
Default implementation of Handler.
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
virtual bool EndDependencyErrors()=0
mdb_size_t count(MDB_cursor *cur)
virtual void DisallowedProperty(const Ch *name, SizeType length)=0
Reference to a constant string (not taking a copy)
void EndMissingDependentProperties(const SValue &sourceName)
virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)=0
bool String(const Ch *str, SizeType len, bool)
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
void TooShort(const Ch *str, SizeType length, SizeType expected)
virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount)=0
SizeType arrayElementIndex
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
bool Bool(Context &context, bool) const
unsigned __int64 uint64_t
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s)
virtual void DoesNotMatch(const Ch *str, SizeType length)=0
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
void TooManyItems(SizeType actualCount, SizeType expectedCount)
std::unique_ptr< void, terminate > context
Unique ZMQ context handle, calls zmq_term on destruction.
void NotMultipleOf(int64_t actual, const SValue &expected)
#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)
bool StartObject(Context &context) const
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
bool EndMissingProperties()
virtual bool EndMissingProperties()=0
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
#define RAPIDJSON_SCHEMA_VERBOSE
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
uint64_t GetHashCode() const
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
#define RAPIDJSON_DELETE(x)
! customization point for global delete
ErrorHandlerType & error_handler
void TooLong(const Ch *str, SizeType length, SizeType expected)
virtual ~ISchemaValidator()
IValidationErrorHandler< SchemaType > ErrorHandlerType
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
GenericValue< EncodingType, StateAllocator > ValueType
SchemaDocumentType::AllocatorType AllocatorType
char * u32toa(uint32_t value, char *buffer)
void StartMissingProperties()
virtual void TooLong(const Ch *str, SizeType length, SizeType expected)=0
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
PatternValidatorType valuePatternValidatorType
virtual void FreeState(void *p)
A type-unsafe stack for storing different types of data.
virtual void DuplicateItems(SizeType index1, SizeType index2)=0
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
virtual void DestroryHasher(void *hasher)=0
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
~SchemaValidationContext()
const SchemaType * valueSchema
virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count)=0
Schema< SchemaDocumentType > SchemaType
const URIType & GetURI() const
bool EndArray(SizeType elementCount)
void NotMultipleOf(uint64_t actual, const SValue &expected)
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
bool RawNumber(const Ch *str, SizeType len, bool)
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
const T & move(const T &t)
void DisallowedProperty(const Ch *name, SizeType length)
void NotMultipleOf(double actual, const SValue &expected)
const PointerType & GetInvalidSchemaPointer() const
virtual void EndMissingDependentProperties(const SValue &sourceName)=0
const GenericPointer< typename T::ValueType > T2 value
virtual void DestroryHasher(void *hasher)
void * memcpy(void *a, const void *b, size_t c)
SizeType patternPropertiesSchemaCount
GenericMemberIterator< false, EncodingType, StateAllocator >::Iterator MemberIterator
Member iterator for iterating in object.
ISchemaValidator ** validators
virtual void DestroySchemaValidator(ISchemaValidator *validator)=0
SchemaType::EncodingType EncodingType
GenericPointer< ValueType, Allocator > PointerType
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
virtual void StartMissingProperties()=0
const SchemaType & GetRoot() const
Get the root schema.
SchemaDocumentType::PointerType PointerType
bool EndObject(Context &context, SizeType memberCount) const
bool Double(Context &context, double d) const
Regular expression engine with subset of ECMAscript grammar.
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
const Ch * GetString() const
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
bool Key(Context &context, const Ch *str, SizeType len, bool) const
void TooFewItems(SizeType actualCount, SizeType expectedCount)
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root)
Result of parsing (wraps ParseErrorCode)
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
virtual void FreeState(void *p)=0
IValidationErrorHandler< Schema > ErrorHandler
bool EndDependencyErrors()
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
const SValue & GetURI() const
virtual void StartMissingDependentProperties()=0
virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count)=0
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
virtual void StartDependencyErrors()=0
GenericValue< EncodingType, AllocatorType > SValue
virtual void TooShort(const Ch *str, SizeType length, SizeType expected)=0
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
virtual void * MallocState(size_t size)
virtual uint64_t GetHashCode(void *hasher)=0
void AddMissingDependentProperty(const SValue &targetName)
const GenericPointer< typename T::ValueType > & pointer
virtual ~IGenericRemoteSchemaDocumentProvider()
bool EndObject(SizeType memberCount)
SchemaType::SValue SValue
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator)
~GenericSchemaDocument()
Destructor.
~GenericSchemaValidator()
Destructor.
SchemaType::ValueType ValueType
bool RawNumber(const Ch *str, SizeType length, bool copy)
ValueType::EncodingType EncodingType
ISchemaValidator ** patternPropertiesValidators
SchemaDocumentType::PointerType PointerType
error
Tracks LMDB error codes.
virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator)=0
virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count)=0
GenericSchemaValidator< SchemaDocument > SchemaValidator
#define RAPIDJSON_ASSERT(x)
Assertion.
SchemaType::SValue SValue
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
bool operator()(Handler &handler)
bool Uint64(Context &context, uint64_t u) const
bool Int64(Context &context, int64_t i) const
bool Key(const Ch *str, SizeType len, bool copy)
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
void StartMissingDependentProperties()
bool String(const Ch *str, SizeType length, bool copy)
const PointerType & GetPointer() const
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
virtual void TooFewItems(SizeType actualCount, SizeType expectedCount)=0
internal::AllOfResult2< M1, M2 >::type AllOf(M1 m1, M2 m2)