15 #ifndef RAPIDJSON_SCHEMA_H_ 16 #define RAPIDJSON_SCHEMA_H_ 20 #include "stringbuffer.h" 25 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) 26 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 28 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 31 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) 32 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 34 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 37 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 38 #include "internal/regex.h" 39 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 43 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX 44 #define RAPIDJSON_SCHEMA_HAS_REGEX 1 46 #define RAPIDJSON_SCHEMA_HAS_REGEX 0 49 #ifndef RAPIDJSON_SCHEMA_VERBOSE 50 #define RAPIDJSON_SCHEMA_VERBOSE 0 56 RAPIDJSON_DIAG_OFF(effc++)
60 RAPIDJSON_DIAG_OFF(weak-vtables)
61 RAPIDJSON_DIAG_OFF(exit-time-destructors)
62 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
63 RAPIDJSON_DIAG_OFF(variadic-macros)
64 #elif defined(_MSC_VER) 65 RAPIDJSON_DIAG_OFF(4512)
73 #if RAPIDJSON_SCHEMA_VERBOSE 77 inline void PrintInvalidKeywordData(
const char* keyword) {
78 printf(
" Fail keyword: '%s'\n", keyword);
81 inline void PrintInvalidKeywordData(
const wchar_t* keyword) {
82 wprintf(L
" Fail keyword: '%ls'\n", keyword);
85 inline void PrintInvalidDocumentData(
const char* document) {
86 printf(
" Fail document: '%s'\n", document);
89 inline void PrintInvalidDocumentData(
const wchar_t* document) {
90 wprintf(L
" Fail document: '%ls'\n", document);
93 inline void PrintValidatorPointersData(
const char* s,
const char* d,
unsigned depth) {
94 printf(
" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4,
" ", s, depth * 4,
" ", d);
97 inline void PrintValidatorPointersData(
const wchar_t* s,
const wchar_t* d,
unsigned depth) {
98 wprintf(L
" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
101 inline void PrintSchemaIdsData(
const char* base,
const char* local,
const char* resolved) {
102 printf(
" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
105 inline void PrintSchemaIdsData(
const wchar_t* base,
const wchar_t* local,
const wchar_t* resolved) {
106 wprintf(L
" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
109 inline void PrintMethodData(
const char* method) {
110 printf(
"%s\n", method);
113 inline void PrintMethodData(
const char* method,
bool b) {
114 printf(
"%s, Data: '%s'\n", method, b ?
"true" :
"false");
117 inline void PrintMethodData(
const char* method, int64_t i) {
118 printf(
"%s, Data: '%" PRId64
"'\n", method, i);
121 inline void PrintMethodData(
const char* method, uint64_t u) {
122 printf(
"%s, Data: '%" PRIu64
"'\n", method, u);
125 inline void PrintMethodData(
const char* method,
double d) {
126 printf(
"%s, Data: '%lf'\n", method, d);
129 inline void PrintMethodData(
const char* method,
const char* s) {
130 printf(
"%s, Data: '%s'\n", method, s);
133 inline void PrintMethodData(
const char* method,
const wchar_t* s) {
134 wprintf(L
"%hs, Data: '%ls'\n", method, s);
137 inline void PrintMethodData(
const char* method,
const char* s1,
const char* s2) {
138 printf(
"%s, Data: '%s', '%s'\n", method, s1, s2);
141 inline void PrintMethodData(
const char* method,
const wchar_t* s1,
const wchar_t* s2) {
142 wprintf(L
"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
147 #endif // RAPIDJSON_SCHEMA_VERBOSE 149 #ifndef RAPIDJSON_SCHEMA_PRINT 150 #if RAPIDJSON_SCHEMA_VERBOSE 151 #define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__) 153 #define RAPIDJSON_SCHEMA_PRINT(name, ...) 160 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\ 161 RAPIDJSON_MULTILINEMACRO_BEGIN\ 162 context.invalidCode = code;\ 163 context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\ 164 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\ 166 RAPIDJSON_MULTILINEMACRO_END 177 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS 178 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags 185 kValidateNoFlags = 0,
186 kValidateContinueOnErrorFlag = 1,
187 kValidateReadFlag = 2,
188 kValidateWriteFlag = 4,
208 enum OpenApiVersion {
209 kVersionUnknown = -1,
219 Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {}
221 if (oapi == kVersion20) draft = kDraft04;
222 else if (oapi == kVersion30) draft = kDraft05;
223 else if (oapi == kVersion31) draft = kDraft2020_12;
224 else draft = kDraft04;
227 bool IsSupported()
const {
228 return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
237 template <
typename ValueType,
typename Allocator>
242 template <
typename SchemaDocumentType>
251 virtual bool IsValid()
const = 0;
252 virtual void SetValidateFlags(
unsigned flags) = 0;
253 virtual unsigned GetValidateFlags()
const = 0;
259 template <
typename SchemaType>
263 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType&,
const bool inheritContinueOnErrors) = 0;
265 virtual void* CreateHasher() = 0;
266 virtual uint64_t GetHashCode(
void* hasher) = 0;
267 virtual void DestroryHasher(
void* hasher) = 0;
268 virtual void* MallocState(
size_t size) = 0;
269 virtual void FreeState(
void* p) = 0;
275 template <
typename SchemaType>
278 typedef typename SchemaType::Ch Ch;
279 typedef typename SchemaType::SValue SValue;
283 virtual void NotMultipleOf(int64_t actual,
const SValue& expected) = 0;
284 virtual void NotMultipleOf(uint64_t actual,
const SValue& expected) = 0;
285 virtual void NotMultipleOf(
double actual,
const SValue& expected) = 0;
286 virtual void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
287 virtual void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
288 virtual void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) = 0;
289 virtual void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
290 virtual void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
291 virtual void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) = 0;
293 virtual void TooLong(
const Ch* str,
SizeType length,
SizeType expected) = 0;
294 virtual void TooShort(
const Ch* str,
SizeType length,
SizeType expected) = 0;
295 virtual void DoesNotMatch(
const Ch* str,
SizeType length) = 0;
297 virtual void DisallowedItem(
SizeType index) = 0;
299 virtual void TooManyItems(
SizeType actualCount,
SizeType expectedCount) = 0;
302 virtual void TooManyProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
303 virtual void TooFewProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
304 virtual void StartMissingProperties() = 0;
305 virtual void AddMissingProperty(
const SValue& name) = 0;
306 virtual bool EndMissingProperties() = 0;
308 virtual void DisallowedProperty(
const Ch* name,
SizeType length) = 0;
310 virtual void StartDependencyErrors() = 0;
311 virtual void StartMissingDependentProperties() = 0;
312 virtual void AddMissingDependentProperty(
const SValue& targetName) = 0;
313 virtual void EndMissingDependentProperties(
const SValue& sourceName) = 0;
314 virtual void AddDependencySchemaError(
const SValue& souceName,
ISchemaValidator* subvalidator) = 0;
315 virtual bool EndDependencyErrors() = 0;
318 virtual void StartDisallowedType() = 0;
319 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
320 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
325 virtual void Disallowed() = 0;
326 virtual void DisallowedWhenWriting() = 0;
327 virtual void DisallowedWhenReading() = 0;
335 template<
typename Encoding,
typename Allocator>
338 typedef typename Encoding::Ch Ch;
340 Hasher(Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
342 bool Null() {
return WriteType(
kNullType); }
344 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
345 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
346 bool Int64(int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
347 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
350 if (d < 0) n.u.i =
static_cast<int64_t
>(d);
351 else n.u.u =
static_cast<uint64_t
>(d);
353 return WriteNumber(n);
356 bool RawNumber(
const Ch* str,
SizeType len,
bool) {
361 bool String(
const Ch* str,
SizeType len,
bool) {
366 bool StartObject() {
return true; }
367 bool Key(
const Ch* str,
SizeType len,
bool copy) {
return String(str, len, copy); }
368 bool EndObject(
SizeType memberCount) {
370 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
371 for (
SizeType i = 0; i < memberCount; i++)
372 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
373 *stack_.template Push<uint64_t>() = h;
377 bool StartArray() {
return true; }
378 bool EndArray(
SizeType elementCount) {
380 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
381 for (
SizeType i = 0; i < elementCount; i++)
383 *stack_.template Push<uint64_t>() = h;
387 bool IsValid()
const {
return stack_.GetSize() ==
sizeof(uint64_t); }
389 uint64_t GetHashCode()
const {
391 return *stack_.template Top<uint64_t>();
395 static const size_t kDefaultSize = 256;
404 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
406 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
408 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
411 const unsigned char* d =
static_cast<const unsigned char*
>(data);
412 for (
size_t i = 0; i < len; i++)
414 *stack_.template Push<uint64_t>() = h;
418 static uint64_t Hash(uint64_t h, uint64_t d) {
431 template <
typename SchemaDocumentType>
436 typedef typename SchemaType::ValueType ValueType;
437 typedef typename ValueType::Ch Ch;
439 enum PatternValidatorType {
440 kPatternValidatorOnly,
441 kPatternValidatorWithProperty,
442 kPatternValidatorWithAdditionalProperty
445 SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh,
const SchemaType* s,
unsigned fl = 0) :
454 arrayElementHashCodes(),
457 patternPropertiesValidators(),
458 patternPropertiesValidatorCount(),
459 patternPropertiesSchemas(),
460 patternPropertiesSchemaCount(),
461 valuePatternValidatorType(kPatternValidatorOnly),
464 valueUniqueness(
false),
465 arrayUniqueness(
false)
471 factory.DestroryHasher(hasher);
473 for (
SizeType i = 0; i < validatorCount; i++) {
475 factory.DestroySchemaValidator(validators[i]);
478 factory.FreeState(validators);
480 if (patternPropertiesValidators) {
481 for (
SizeType i = 0; i < patternPropertiesValidatorCount; i++) {
482 if (patternPropertiesValidators[i]) {
483 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
486 factory.FreeState(patternPropertiesValidators);
488 if (patternPropertiesSchemas)
489 factory.FreeState(patternPropertiesSchemas);
491 factory.FreeState(propertyExist);
494 SchemaValidatorFactoryType& factory;
495 ErrorHandlerType& error_handler;
496 const SchemaType* schema;
498 const SchemaType* valueSchema;
499 const Ch* invalidKeyword;
502 void* arrayElementHashCodes;
506 SizeType patternPropertiesValidatorCount;
507 const SchemaType** patternPropertiesSchemas;
508 SizeType patternPropertiesSchemaCount;
509 PatternValidatorType valuePatternValidatorType;
510 PatternValidatorType objectPatternValidatorType;
514 bool valueUniqueness;
515 bool arrayUniqueness;
521 template <
typename SchemaDocumentType>
524 typedef typename SchemaDocumentType::ValueType ValueType;
525 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
526 typedef typename SchemaDocumentType::PointerType PointerType;
527 typedef typename ValueType::EncodingType EncodingType;
528 typedef typename EncodingType::Ch Ch;
536 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator,
const UriType&
id = UriType()) :
537 allocator_(allocator),
538 uri_(schemaDocument->GetURI(), *allocator),
540 spec_(schemaDocument->GetSpecification()),
541 pointer_(p, allocator),
542 typeless_(schemaDocument->GetTypeless()),
546 type_((1 << kTotalSchemaType) - 1),
548 notValidatorIndex_(),
550 additionalPropertiesSchema_(),
551 patternProperties_(),
552 patternPropertyCount_(),
556 additionalProperties_(
true),
559 hasSchemaDependencies_(),
560 additionalItemsSchema_(),
566 additionalItems_(
true),
571 exclusiveMinimum_(
false),
572 exclusiveMaximum_(
false),
573 defaultValueLength_(0),
579 p.StringifyUriFragment(sb);
580 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Schema", sb.GetString(),
id.GetString());
582 typedef typename ValueType::ConstValueIterator ConstValueIterator;
583 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
589 if (
this != typeless_) {
590 typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
591 SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
592 new (entry) SchemaEntry(pointer_,
this,
true, allocator_);
593 schemaDocument->AddSchemaRefs(
this);
596 if (!value.IsObject())
601 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
602 if (
const ValueType* v = GetMember(value, GetIdString())) {
604 UriType local(*v, allocator);
605 id_ = local.Resolve(id_, allocator);
606 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), v->GetString(), id_.GetString());
610 if (
const ValueType* v = GetMember(value, GetTypeString())) {
614 else if (v->IsArray())
615 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
619 if (
const ValueType* v = GetMember(value, GetEnumString())) {
620 if (v->IsArray() && v->Size() > 0) {
621 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
622 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
624 char buffer[256u + 24];
626 EnumHasherType h(&hasherAllocator, 256);
628 enum_[enumCount_++] = h.GetHashCode();
634 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
637 if (schemaDocument && spec_.oapi != kVersion20) {
638 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
639 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
641 if (
const ValueType* v = GetMember(value, GetNotString())) {
642 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
643 notValidatorIndex_ = validatorCount_;
650 const ValueType* properties = GetMember(value, GetPropertiesString());
651 const ValueType* required = GetMember(value, GetRequiredString());
652 const ValueType* dependencies = GetMember(value, GetDependenciesString());
657 if (properties && properties->IsObject())
658 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
659 AddUniqueElement(allProperties, itr->name);
661 if (required && required->IsArray())
662 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
664 AddUniqueElement(allProperties, *itr);
667 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
668 if (dependencies && dependencies->IsObject())
669 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
670 AddUniqueElement(allProperties, itr->name);
671 if (itr->value.IsArray())
672 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
674 AddUniqueElement(allProperties, *i);
677 if (allProperties.Size() > 0) {
678 propertyCount_ = allProperties.Size();
679 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
680 for (
SizeType i = 0; i < propertyCount_; i++) {
681 new (&properties_[i]) Property();
682 properties_[i].name = allProperties[i];
683 properties_[i].schema = typeless_;
688 if (properties && properties->IsObject()) {
689 PointerType q = p.Append(GetPropertiesString(), allocator_);
690 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
692 if (FindPropertyIndex(itr->name, &index))
693 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
698 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
699 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
700 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
701 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
702 patternPropertyCount_ = 0;
704 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
705 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
706 PointerType r = q.Append(itr->name, allocator_);
707 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
708 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
709 patternPropertyCount_++;
713 if (required && required->IsArray())
714 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
715 if (itr->IsString()) {
717 if (FindPropertyIndex(*itr, &index)) {
718 properties_[index].required =
true;
724 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
725 if (dependencies && dependencies->IsObject()) {
726 PointerType q = p.Append(GetDependenciesString(), allocator_);
727 hasDependencies_ =
true;
728 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
730 if (FindPropertyIndex(itr->name, &sourceIndex)) {
731 if (itr->value.IsArray()) {
732 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
733 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
734 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
736 if (FindPropertyIndex(*targetItr, &targetIndex))
737 properties_[sourceIndex].dependencies[targetIndex] =
true;
740 else if (itr->value.IsObject()) {
741 hasSchemaDependencies_ =
true;
742 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
743 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
750 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
752 additionalProperties_ = v->GetBool();
753 else if (v->IsObject())
754 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
757 AssignIfExist(minProperties_, value, GetMinPropertiesString());
758 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
761 if (
const ValueType* v = GetMember(value, GetItemsString())) {
762 PointerType q = p.Append(GetItemsString(), allocator_);
764 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
765 else if (v->IsArray()) {
766 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
768 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
769 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
773 AssignIfExist(minItems_, value, GetMinItemsString());
774 AssignIfExist(maxItems_, value, GetMaxItemsString());
777 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
778 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
780 additionalItems_ = v->GetBool();
781 else if (v->IsObject())
782 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
785 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
788 AssignIfExist(minLength_, value, GetMinLengthString());
789 AssignIfExist(maxLength_, value, GetMaxLengthString());
791 if (
const ValueType* v = GetMember(value, GetPatternString()))
792 pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
795 if (
const ValueType* v = GetMember(value, GetMinimumString()))
797 minimum_.CopyFrom(*v, *allocator_);
799 if (
const ValueType* v = GetMember(value, GetMaximumString()))
801 maximum_.CopyFrom(*v, *allocator_);
803 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
804 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
806 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
807 if (v->IsNumber() && v->GetDouble() > 0.0)
808 multipleOf_.CopyFrom(*v, *allocator_);
811 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
813 defaultValueLength_ = v->GetStringLength();
818 if (spec_.oapi != kVersionNone)
819 AssignIfExist(readOnly_, value, GetReadOnlyString());
820 if (spec_.oapi >= kVersion30)
821 AssignIfExist(writeOnly_, value, GetWriteOnlyString());
822 if (readOnly_ && writeOnly_)
827 if (spec_.oapi >= kVersion30) {
828 AssignIfExist(nullable_, value, GetNullableString());
830 AddType(GetNullString());
835 AllocatorType::Free(enum_);
837 for (
SizeType i = 0; i < propertyCount_; i++)
838 properties_[i].~Property();
839 AllocatorType::Free(properties_);
841 if (patternProperties_) {
842 for (
SizeType i = 0; i < patternPropertyCount_; i++)
843 patternProperties_[i].~PatternProperty();
844 AllocatorType::Free(patternProperties_);
846 AllocatorType::Free(itemsTuple_);
847 #if RAPIDJSON_SCHEMA_HAS_REGEX 849 pattern_->~RegexType();
850 AllocatorType::Free(pattern_);
855 const SValue& GetURI()
const {
859 const UriType& GetId()
const {
867 const PointerType& GetPointer()
const {
871 bool BeginValue(Context& context)
const {
872 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::BeginValue");
873 if (context.inArray) {
875 context.valueUniqueness =
true;
878 context.valueSchema = itemsList_;
879 else if (itemsTuple_) {
880 if (context.arrayElementIndex < itemsTupleCount_)
881 context.valueSchema = itemsTuple_[context.arrayElementIndex];
882 else if (additionalItemsSchema_)
883 context.valueSchema = additionalItemsSchema_;
884 else if (additionalItems_)
885 context.valueSchema = typeless_;
887 context.error_handler.DisallowedItem(context.arrayElementIndex);
889 context.valueSchema = typeless_;
891 context.arrayElementIndex++;
896 context.valueSchema = typeless_;
898 context.arrayElementIndex++;
903 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
904 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndValue");
906 if (context.patternPropertiesValidatorCount > 0) {
907 bool otherValid =
false;
908 SizeType count = context.patternPropertiesValidatorCount;
909 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
910 otherValid = context.patternPropertiesValidators[--count]->IsValid();
912 bool patternValid =
true;
913 for (
SizeType i = 0; i < count; i++)
914 if (!context.patternPropertiesValidators[i]->IsValid()) {
915 patternValid =
false;
919 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
921 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
925 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
926 if (!patternValid || !otherValid) {
927 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
931 else if (!patternValid && !otherValid) {
932 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
938 if (enum_ && context.hasher) {
939 const uint64_t h = context.factory.GetHashCode(context.hasher);
940 for (
SizeType i = 0; i < enumCount_; i++)
949 if (context.validatorCount > 0) {
951 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
952 if (!context.validators[i]->IsValid()) {
953 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
957 if (anyOf_.schemas) {
958 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
959 if (context.validators[i]->IsValid())
961 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
966 if (oneOf_.schemas) {
967 bool oneValid =
false;
969 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
970 if (context.validators[i]->IsValid()) {
972 context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
976 firstMatch = i - oneOf_.begin;
980 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
985 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
986 context.error_handler.Disallowed();
994 bool Null(Context& context)
const {
995 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Null");
996 if (!(type_ & (1 << kNullSchemaType))) {
997 DisallowedType(context, GetNullString());
1000 return CreateParallelValidator(context);
1003 bool Bool(Context& context,
bool b)
const {
1004 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Bool", b);
1005 if (!CheckBool(context, b))
1007 return CreateParallelValidator(context);
1010 bool Int(Context& context,
int i)
const {
1011 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int", (int64_t)i);
1012 if (!CheckInt(context, i))
1014 return CreateParallelValidator(context);
1017 bool Uint(Context& context,
unsigned u)
const {
1018 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint", (uint64_t)u);
1019 if (!CheckUint(context, u))
1021 return CreateParallelValidator(context);
1024 bool Int64(Context& context, int64_t i)
const {
1025 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int64", i);
1026 if (!CheckInt(context, i))
1028 return CreateParallelValidator(context);
1031 bool Uint64(Context& context, uint64_t u)
const {
1032 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint64", u);
1033 if (!CheckUint(context, u))
1035 return CreateParallelValidator(context);
1038 bool Double(Context& context,
double d)
const {
1039 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Double", d);
1040 if (!(type_ & (1 << kNumberSchemaType))) {
1041 DisallowedType(context, GetNumberString());
1045 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1048 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1051 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1054 return CreateParallelValidator(context);
1057 bool String(Context& context,
const Ch* str,
SizeType length,
bool)
const {
1058 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::String", str);
1059 if (!(type_ & (1 << kStringSchemaType))) {
1060 DisallowedType(context, GetStringString());
1064 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
1066 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
1067 if (count < minLength_) {
1068 context.error_handler.TooShort(str, length, minLength_);
1071 if (count > maxLength_) {
1072 context.error_handler.TooLong(str, length, maxLength_);
1078 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
1079 context.error_handler.DoesNotMatch(str, length);
1083 return CreateParallelValidator(context);
1086 bool StartObject(Context& context)
const {
1087 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartObject");
1088 if (!(type_ & (1 << kObjectSchemaType))) {
1089 DisallowedType(context, GetObjectString());
1093 if (hasDependencies_ || hasRequired_) {
1094 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
1095 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
1098 if (patternProperties_) {
1099 SizeType count = patternPropertyCount_ + 1;
1100 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
1101 context.patternPropertiesSchemaCount = 0;
1102 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
1105 return CreateParallelValidator(context);
1108 bool Key(Context& context,
const Ch* str,
SizeType len,
bool)
const {
1109 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Key", str);
1111 if (patternProperties_) {
1112 context.patternPropertiesSchemaCount = 0;
1113 for (
SizeType i = 0; i < patternPropertyCount_; i++)
1114 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
1115 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
1116 context.valueSchema = typeless_;
1121 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
1122 if (context.patternPropertiesSchemaCount > 0) {
1123 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
1124 context.valueSchema = typeless_;
1125 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
1128 context.valueSchema = properties_[index].schema;
1130 if (context.propertyExist)
1131 context.propertyExist[index] =
true;
1136 if (additionalPropertiesSchema_) {
1137 if (context.patternPropertiesSchemaCount > 0) {
1138 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
1139 context.valueSchema = typeless_;
1140 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
1143 context.valueSchema = additionalPropertiesSchema_;
1146 else if (additionalProperties_) {
1147 context.valueSchema = typeless_;
1151 if (context.patternPropertiesSchemaCount == 0) {
1153 context.valueSchema = typeless_;
1154 context.error_handler.DisallowedProperty(str, len);
1161 bool EndObject(Context& context,
SizeType memberCount)
const {
1162 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndObject");
1164 context.error_handler.StartMissingProperties();
1165 for (
SizeType index = 0; index < propertyCount_; index++)
1166 if (properties_[index].required && !context.propertyExist[index])
1167 if (properties_[index].schema->defaultValueLength_ == 0 )
1168 context.error_handler.AddMissingProperty(properties_[index].name);
1169 if (context.error_handler.EndMissingProperties())
1173 if (memberCount < minProperties_) {
1174 context.error_handler.TooFewProperties(memberCount, minProperties_);
1178 if (memberCount > maxProperties_) {
1179 context.error_handler.TooManyProperties(memberCount, maxProperties_);
1183 if (hasDependencies_) {
1184 context.error_handler.StartDependencyErrors();
1185 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1186 const Property& source = properties_[sourceIndex];
1187 if (context.propertyExist[sourceIndex]) {
1188 if (source.dependencies) {
1189 context.error_handler.StartMissingDependentProperties();
1190 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1191 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1192 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1193 context.error_handler.EndMissingDependentProperties(source.name);
1195 else if (source.dependenciesSchema) {
1196 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1197 if (!dependenciesValidator->IsValid())
1198 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1202 if (context.error_handler.EndDependencyErrors())
1209 bool StartArray(Context& context)
const {
1210 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartArray");
1211 context.arrayElementIndex = 0;
1212 context.inArray =
true;
1214 if (!(type_ & (1 << kArraySchemaType))) {
1215 DisallowedType(context, GetArrayString());
1219 return CreateParallelValidator(context);
1222 bool EndArray(Context& context,
SizeType elementCount)
const {
1223 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndArray");
1224 context.inArray =
false;
1226 if (elementCount < minItems_) {
1227 context.error_handler.TooFewItems(elementCount, minItems_);
1231 if (elementCount > maxItems_) {
1232 context.error_handler.TooManyItems(elementCount, maxItems_);
1239 static const ValueType& GetValidateErrorKeyword(
ValidateErrorCode validateErrorCode) {
1240 switch (validateErrorCode) {
1275 default:
return GetNullString();
1281 #define RAPIDJSON_STRING_(name, ...) \ 1282 static const ValueType& Get##name##String() {\ 1283 static const Ch s[] = { __VA_ARGS__, '\0' };\ 1284 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\ 1288 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1289 RAPIDJSON_STRING_(Boolean,
'b',
'o',
'o',
'l',
'e',
'a',
'n')
1290 RAPIDJSON_STRING_(Object,
'o',
'b',
'j',
'e',
'c',
't')
1291 RAPIDJSON_STRING_(Array,
'a',
'r',
'r',
'a',
'y')
1292 RAPIDJSON_STRING_(String,
's',
't',
'r',
'i',
'n',
'g')
1293 RAPIDJSON_STRING_(Number,
'n',
'u',
'm',
'b',
'e',
'r')
1294 RAPIDJSON_STRING_(Integer,
'i',
'n',
't',
'e',
'g',
'e',
'r')
1295 RAPIDJSON_STRING_(
Type,
't',
'y',
'p',
'e')
1296 RAPIDJSON_STRING_(Enum,
'e',
'n',
'u',
'm')
1297 RAPIDJSON_STRING_(AllOf,
'a',
'l',
'l',
'O',
'f')
1298 RAPIDJSON_STRING_(AnyOf,
'a',
'n',
'y',
'O',
'f')
1299 RAPIDJSON_STRING_(OneOf,
'o',
'n',
'e',
'O',
'f')
1300 RAPIDJSON_STRING_(Not,
'n',
'o',
't')
1301 RAPIDJSON_STRING_(Properties,
'p',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1302 RAPIDJSON_STRING_(Required,
'r',
'e',
'q',
'u',
'i',
'r',
'e',
'd')
1303 RAPIDJSON_STRING_(Dependencies,
'd',
'e',
'p',
'e',
'n',
'd',
'e',
'n',
'c',
'i',
'e',
's')
1304 RAPIDJSON_STRING_(PatternProperties,
'p',
'a',
't',
't',
'e',
'r',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1305 RAPIDJSON_STRING_(AdditionalProperties,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1306 RAPIDJSON_STRING_(MinProperties,
'm',
'i',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1307 RAPIDJSON_STRING_(MaxProperties,
'm',
'a',
'x',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1308 RAPIDJSON_STRING_(Items,
'i',
't',
'e',
'm',
's')
1309 RAPIDJSON_STRING_(MinItems,
'm',
'i',
'n',
'I',
't',
'e',
'm',
's')
1310 RAPIDJSON_STRING_(MaxItems,
'm',
'a',
'x',
'I',
't',
'e',
'm',
's')
1311 RAPIDJSON_STRING_(AdditionalItems,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'I',
't',
'e',
'm',
's')
1312 RAPIDJSON_STRING_(UniqueItems,
'u',
'n',
'i',
'q',
'u',
'e',
'I',
't',
'e',
'm',
's')
1313 RAPIDJSON_STRING_(MinLength,
'm',
'i',
'n',
'L',
'e',
'n',
'g',
't',
'h')
1314 RAPIDJSON_STRING_(MaxLength,
'm',
'a',
'x',
'L',
'e',
'n',
'g',
't',
'h')
1315 RAPIDJSON_STRING_(Pattern,
'p',
'a',
't',
't',
'e',
'r',
'n')
1316 RAPIDJSON_STRING_(Minimum,
'm',
'i',
'n',
'i',
'm',
'u',
'm')
1317 RAPIDJSON_STRING_(Maximum,
'm',
'a',
'x',
'i',
'm',
'u',
'm')
1318 RAPIDJSON_STRING_(ExclusiveMinimum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'i',
'n',
'i',
'm',
'u',
'm')
1319 RAPIDJSON_STRING_(ExclusiveMaximum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'a',
'x',
'i',
'm',
'u',
'm')
1320 RAPIDJSON_STRING_(MultipleOf,
'm',
'u',
'l',
't',
'i',
'p',
'l',
'e',
'O',
'f')
1321 RAPIDJSON_STRING_(DefaultValue,
'd',
'e',
'f',
'a',
'u',
'l',
't')
1322 RAPIDJSON_STRING_(Schema,
'$',
's',
'c',
'h',
'e',
'm',
'a')
1323 RAPIDJSON_STRING_(Ref,
'$',
'r',
'e',
'f')
1324 RAPIDJSON_STRING_(Id,
'i',
'd')
1325 RAPIDJSON_STRING_(Swagger,
's',
'w',
'a',
'g',
'g',
'e',
'r')
1326 RAPIDJSON_STRING_(OpenApi,
'o',
'p',
'e',
'n',
'a',
'p',
'i')
1327 RAPIDJSON_STRING_(ReadOnly,
'r',
'e',
'a',
'd',
'O',
'n',
'l',
'y')
1328 RAPIDJSON_STRING_(WriteOnly,
'w',
'r',
'i',
't',
'e',
'O',
'n',
'l',
'y')
1329 RAPIDJSON_STRING_(Nullable,
'n',
'u',
'l',
'l',
'a',
'b',
'l',
'e')
1331 #undef RAPIDJSON_STRING_ 1334 enum SchemaValueType {
1345 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1347 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 1348 typedef std::basic_regex<Ch> RegexType;
1350 typedef char RegexType;
1353 struct SchemaArray {
1354 SchemaArray() : schemas(), count() {}
1355 ~SchemaArray() { AllocatorType::Free(schemas); }
1356 const SchemaType** schemas;
1361 template <
typename V1,
typename V2>
1362 void AddUniqueElement(V1& a,
const V2& v) {
1363 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1366 V1 c(v, *allocator_);
1367 a.PushBack(c, *allocator_);
1370 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1371 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1372 return itr != value.MemberEnd() ? &(itr->value) : 0;
1375 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1376 if (
const ValueType* v = GetMember(value, name))
1381 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
1382 if (
const ValueType* v = GetMember(value, name))
1383 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1384 out = static_cast<SizeType>(v->GetUint64());
1387 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1388 if (
const ValueType* v = GetMember(value, name)) {
1389 if (v->IsArray() && v->Size() > 0) {
1390 PointerType q = p.Append(name, allocator_);
1391 out.count = v->Size();
1392 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1393 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
1394 for (
SizeType i = 0; i < out.count; i++)
1395 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1396 out.begin = validatorCount_;
1397 validatorCount_ += out.count;
1402 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1403 template <
typename ValueType>
1404 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1405 if (value.IsString()) {
1406 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1407 if (!r->IsValid()) {
1410 AllocatorType::Free(r);
1418 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1420 return rs.Search(str);
1422 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 1423 template <
typename ValueType>
1424 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1425 if (value.IsString()) {
1426 RegexType *r =
static_cast<RegexType*
>(allocator_->Malloc(
sizeof(RegexType)));
1428 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1430 catch (
const std::regex_error& e) {
1432 AllocatorType::Free(r);
1438 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1439 std::match_results<const Ch*> r;
1440 return std::regex_search(str, str + length, r, *pattern);
1443 template <
typename ValueType>
1444 RegexType* CreatePattern(
const ValueType&) {
1448 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1449 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX 1451 void AddType(
const ValueType& type) {
1452 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1453 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1454 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1455 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1456 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1457 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1458 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1464 bool CreateParallelValidator(Context& context)
const {
1465 if (enum_ || context.arrayUniqueness)
1466 context.hasher = context.factory.CreateHasher();
1468 if (validatorCount_) {
1471 std::memset(context.validators, 0,
sizeof(
ISchemaValidator*) * validatorCount_);
1472 context.validatorCount = validatorCount_;
1476 CreateSchemaValidators(context, allOf_,
false);
1479 CreateSchemaValidators(context, anyOf_,
false);
1482 CreateSchemaValidators(context, oneOf_,
false);
1485 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_,
false);
1487 if (hasSchemaDependencies_) {
1488 for (
SizeType i = 0; i < propertyCount_; i++)
1489 if (properties_[i].dependenciesSchema)
1490 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema,
false);
1495 if (readOnly_ && (context.flags & kValidateWriteFlag)) {
1496 context.error_handler.DisallowedWhenWriting();
1499 if (writeOnly_ && (context.flags & kValidateReadFlag)) {
1500 context.error_handler.DisallowedWhenReading();
1507 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas,
const bool inheritContinueOnErrors)
const {
1508 for (
SizeType i = 0; i < schemas.count; i++)
1509 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1513 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1514 SizeType len = name.GetStringLength();
1515 const Ch* str = name.GetString();
1516 for (
SizeType index = 0; index < propertyCount_; index++)
1517 if (properties_[index].name.GetStringLength() == len &&
1518 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1526 bool CheckBool(Context& context,
bool)
const {
1527 if (!(type_ & (1 << kBooleanSchemaType))) {
1528 DisallowedType(context, GetBooleanString());
1534 bool CheckInt(Context& context, int64_t i)
const {
1535 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1536 DisallowedType(context, GetIntegerString());
1540 if (!minimum_.IsNull()) {
1541 if (minimum_.IsInt64()) {
1542 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1543 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1547 else if (minimum_.IsUint64()) {
1548 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1551 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1555 if (!maximum_.IsNull()) {
1556 if (maximum_.IsInt64()) {
1557 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1558 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1562 else if (maximum_.IsUint64()) { }
1564 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1568 if (!multipleOf_.IsNull()) {
1569 if (multipleOf_.IsUint64()) {
1570 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1571 context.error_handler.NotMultipleOf(i, multipleOf_);
1575 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1582 bool CheckUint(Context& context, uint64_t i)
const {
1583 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1584 DisallowedType(context, GetIntegerString());
1588 if (!minimum_.IsNull()) {
1589 if (minimum_.IsUint64()) {
1590 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1591 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1595 else if (minimum_.IsInt64())
1597 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1601 if (!maximum_.IsNull()) {
1602 if (maximum_.IsUint64()) {
1603 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1604 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1608 else if (maximum_.IsInt64()) {
1609 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1612 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1616 if (!multipleOf_.IsNull()) {
1617 if (multipleOf_.IsUint64()) {
1618 if (i % multipleOf_.GetUint64() != 0) {
1619 context.error_handler.NotMultipleOf(i, multipleOf_);
1623 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1630 bool CheckDoubleMinimum(Context& context,
double d)
const {
1631 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1632 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1638 bool CheckDoubleMaximum(Context& context,
double d)
const {
1639 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1640 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1646 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1647 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1648 double q = std::floor(a / b);
1649 double r = a - q * b;
1651 context.error_handler.NotMultipleOf(d, multipleOf_);
1657 void DisallowedType(Context& context,
const ValueType& actualType)
const {
1658 ErrorHandler& eh = context.error_handler;
1659 eh.StartDisallowedType();
1661 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1662 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1663 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1664 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1665 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1667 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1668 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1670 eh.EndDisallowedType(actualType);
1674 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1675 ~Property() { AllocatorType::Free(dependencies); }
1677 const SchemaType* schema;
1678 const SchemaType* dependenciesSchema;
1679 SizeType dependenciesValidatorIndex;
1684 struct PatternProperty {
1685 PatternProperty() : schema(), pattern() {}
1686 ~PatternProperty() {
1688 pattern->~RegexType();
1689 AllocatorType::Free(pattern);
1692 const SchemaType* schema;
1696 AllocatorType* allocator_;
1700 PointerType pointer_;
1701 const SchemaType* typeless_;
1707 const SchemaType* not_;
1712 Property* properties_;
1713 const SchemaType* additionalPropertiesSchema_;
1714 PatternProperty* patternProperties_;
1719 bool additionalProperties_;
1720 bool hasDependencies_;
1722 bool hasSchemaDependencies_;
1724 const SchemaType* additionalItemsSchema_;
1725 const SchemaType* itemsList_;
1726 const SchemaType** itemsTuple_;
1730 bool additionalItems_;
1733 RegexType* pattern_;
1740 bool exclusiveMinimum_;
1741 bool exclusiveMaximum_;
1750 template<
typename Stack,
typename Ch>
1752 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1753 *documentStack.template Push<Ch>() =
'/';
1755 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1756 for (
size_t i = 0; i < length; i++)
1757 *documentStack.template Push<Ch>() =
static_cast<Ch
>(buffer[i]);
1762 template <
typename Stack>
1764 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1766 char *buffer = documentStack.template Push<char>(1 + 10);
1768 const char* end = internal::u32toa(index, buffer);
1769 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1772 char *buffer = documentStack.template Push<char>(1 + 20);
1774 const char* end = internal::u64toa(index, buffer);
1775 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1785 template <
typename SchemaDocumentType>
1788 typedef typename SchemaDocumentType::Ch Ch;
1789 typedef typename SchemaDocumentType::ValueType ValueType;
1790 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
1793 virtual const SchemaDocumentType* GetRemoteDocument(
const Ch* uri,
SizeType length) = 0;
1799 return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
1815 template <
typename ValueT,
typename Allocator = CrtAllocator>
1818 typedef ValueT ValueType;
1820 typedef Allocator AllocatorType;
1821 typedef typename ValueType::EncodingType EncodingType;
1822 typedef typename EncodingType::Ch Ch;
1829 template <
typename,
typename,
typename>
1845 IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
1846 const PointerType& pointer = PointerType(),
1848 remoteProvider_(remoteProvider),
1849 allocator_(allocator),
1853 schemaMap_(allocator, kInitialSchemaMapSize),
1854 schemaRef_(allocator, kInitialSchemaRefSize),
1859 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::GenericSchemaDocument");
1864 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1865 docId_ = UriType(uri_, allocator_);
1867 typeless_ =
static_cast<SchemaType*
>(allocator_->Malloc(
sizeof(SchemaType)));
1868 new (typeless_) SchemaType(
this, PointerType(), ValueType(
kObjectType).Move(), ValueType(
kObjectType).Move(), allocator_, docId_);
1872 SetSchemaSpecification(document);
1878 if (pointer.GetTokenCount() == 0) {
1879 CreateSchemaRecursive(&root_, pointer, document, document, docId_);
1881 else if (
const ValueType* v = pointer.Get(document)) {
1882 CreateSchema(&root_, pointer, *v, document, docId_);
1886 pointer.StringifyUriFragment(sb);
1892 schemaRef_.ShrinkToFit();
1895 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 1896 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1898 remoteProvider_(rhs.remoteProvider_),
1899 allocator_(rhs.allocator_),
1900 ownAllocator_(rhs.ownAllocator_),
1902 typeless_(rhs.typeless_),
1903 schemaMap_(std::move(rhs.schemaMap_)),
1904 schemaRef_(std::move(rhs.schemaRef_)),
1905 uri_(std::move(rhs.uri_)),
1906 docId_(std::move(rhs.docId_)),
1908 error_(std::move(rhs.error_)),
1909 currentError_(std::move(rhs.currentError_))
1911 rhs.remoteProvider_ = 0;
1913 rhs.ownAllocator_ = 0;
1920 while (!schemaMap_.Empty())
1921 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1924 typeless_->~SchemaType();
1925 Allocator::Free(typeless_);
1931 currentError_.SetNull();
1936 const GValue& GetURI()
const {
return uri_; }
1938 const Specification& GetSpecification()
const {
return spec_; }
1939 bool IsSupportedSpecification()
const {
return spec_.IsSupported(); }
1944 SchemaDraft draft = GetSchemaDraft(document);
1945 if (draft != kDraftNone)
1948 OpenApiVersion oapi = GetOpenApiVersion(document);
1949 if (oapi != kVersionNone)
1956 const SchemaType&
GetRoot()
const {
return *root_; }
1960 const GValue&
GetError()
const {
return error_; }
1962 static const StringRefType& GetSchemaErrorKeyword(
SchemaErrorCode schemaErrorCode) {
1963 switch (schemaErrorCode) {
1977 default:
return GetNullString();
1984 AddCurrentError(code, location);
1990 currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1991 AddCurrentError(code, location);
1997 currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1998 currentError_.AddMember(GetOffsetString(), static_cast<SizeType>(pointer.GetParseErrorOffset() /
sizeof(Ch)), *allocator_);
1999 AddCurrentError(code, location);
2004 GenericSchemaDocument(
const GenericSchemaDocument&);
2006 GenericSchemaDocument& operator=(
const GenericSchemaDocument&);
2010 struct SchemaEntry {
2011 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
2014 schema->~SchemaType();
2015 Allocator::Free(schema);
2018 PointerType pointer;
2023 void AddErrorInstanceLocation(GValue& result,
const PointerType& location) {
2025 location.StringifyUriFragment(sb);
2026 GValue instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)), *allocator_);
2027 result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2030 void AddError(GValue& keyword, GValue& error) {
2032 if (member == error_.MemberEnd())
2033 error_.AddMember(keyword, error, *allocator_);
2035 if (member->value.IsObject()) {
2037 errors.PushBack(member->value, *allocator_);
2038 member->value = errors;
2040 member->value.PushBack(error, *allocator_);
2044 void AddCurrentError(
const SchemaErrorCode code,
const PointerType& location) {
2045 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2046 currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2047 AddErrorInstanceLocation(currentError_, location);
2048 AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2051 #define RAPIDJSON_STRING_(name, ...) \ 2052 static const StringRefType& Get##name##String() {\ 2053 static const Ch s[] = { __VA_ARGS__, '\0' };\ 2054 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \ 2058 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2059 RAPIDJSON_STRING_(ErrorCode,
'e',
'r',
'r',
'o',
'r',
'C',
'o',
'd',
'e')
2060 RAPIDJSON_STRING_(
Value,
'v',
'a',
'l',
'u',
'e')
2061 RAPIDJSON_STRING_(Offset,
'o',
'f',
'f',
's',
'e',
't')
2063 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
2064 RAPIDJSON_STRING_(SpecUnknown,
'S',
'p',
'e',
'c',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2065 RAPIDJSON_STRING_(SpecUnsupported,
'S',
'p',
'e',
'c',
'U',
'n',
's',
'u',
'p',
'p',
'o',
'r',
't',
'e',
'd')
2066 RAPIDJSON_STRING_(SpecIllegal,
'S',
'p',
'e',
'c',
'I',
'l',
'l',
'e',
'g',
'a',
'l')
2067 RAPIDJSON_STRING_(StartUnknown,
'S',
't',
'a',
'r',
't',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2068 RAPIDJSON_STRING_(RefPlainName,
'R',
'e',
'f',
'P',
'l',
'a',
'i',
'n',
'N',
'a',
'm',
'e')
2069 RAPIDJSON_STRING_(RefInvalid,
'R',
'e',
'f',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2070 RAPIDJSON_STRING_(RefPointerInvalid,
'R',
'e',
'f',
'P',
'o',
'i',
'n',
't',
'e',
'r',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2071 RAPIDJSON_STRING_(RefUnknown,
'R',
'e',
'f',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2072 RAPIDJSON_STRING_(RefCyclical,
'R',
'e',
'f',
'C',
'y',
'c',
'l',
'i',
'c',
'a',
'l')
2073 RAPIDJSON_STRING_(RefNoRemoteProvider,
'R',
'e',
'f',
'N',
'o',
'R',
'e',
'm',
'o',
't',
'e',
'P',
'r',
'o',
'v',
'i',
'd',
'e',
'r')
2074 RAPIDJSON_STRING_(RefNoRemoteSchema,
'R',
'e',
'f',
'N',
'o',
'R',
'e',
'm',
'o',
't',
'e',
'S',
'c',
'h',
'e',
'm',
'a')
2075 RAPIDJSON_STRING_(ReadOnlyAndWriteOnly,
'R',
'e',
'a',
'd',
'O',
'n',
'l',
'y',
'A',
'n',
'd',
'W',
'r',
'i',
't',
'e',
'O',
'n',
'l',
'y')
2076 RAPIDJSON_STRING_(RegexInvalid,
'R',
'e',
'g',
'e',
'x',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2078 #undef RAPIDJSON_STRING_ 2081 static SchemaDraft GetSchemaDraft(
const ValueType& document) {
2082 static const Ch kDraft03String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'3',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2083 static const Ch kDraft04String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'4',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2084 static const Ch kDraft05String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'5',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2085 static const Ch kDraft06String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'6',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2086 static const Ch kDraft07String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'7',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2087 static const Ch kDraft2019_09String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'1',
'9',
'-',
'0',
'9',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2088 static const Ch kDraft2020_12String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'2',
'0',
'-',
'1',
'2',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2090 if (!document.IsObject()) {
2095 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
2096 if (itr != document.MemberEnd()) {
2097 if (!itr->value.IsString())
return kDraftUnknown;
2098 const UriType draftUri(itr->value);
2100 if (draftUri.Match(UriType(kDraft04String),
false))
return kDraft04;
2101 if (draftUri.Match(UriType(kDraft05String),
false))
return kDraft05;
2102 if (draftUri.Match(UriType(kDraft06String),
false))
return kDraft06;
2103 if (draftUri.Match(UriType(kDraft07String),
false))
return kDraft07;
2104 if (draftUri.Match(UriType(kDraft03String),
false))
return kDraft03;
2105 if (draftUri.Match(UriType(kDraft2019_09String),
false))
return kDraft2019_09;
2106 if (draftUri.Match(UriType(kDraft2020_12String),
false))
return kDraft2020_12;
2107 return kDraftUnknown;
2115 static OpenApiVersion GetOpenApiVersion(
const ValueType& document) {
2116 static const Ch kVersion20String[] = {
'2',
'.',
'0',
'\0' };
2117 static const Ch kVersion30String[] = {
'3',
'.',
'0',
'.',
'\0' };
2118 static const Ch kVersion31String[] = {
'3',
'.',
'1',
'.',
'\0' };
2119 static SizeType len = internal::StrLen<Ch>(kVersion30String);
2121 if (!document.IsObject()) {
2122 return kVersionNone;
2126 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
2127 if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
2128 if (itr != document.MemberEnd()) {
2129 if (!itr->value.IsString())
return kVersionUnknown;
2130 const ValueType kVersion20Value(kVersion20String);
2131 if (kVersion20Value == itr->value)
return kVersion20;
2132 const ValueType kVersion30Value(kVersion30String);
2133 if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len))
return kVersion30;
2134 const ValueType kVersion31Value(kVersion31String);
2135 if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len))
return kVersion31;
2136 return kVersionUnknown;
2139 return kVersionNone;
2144 void SetSchemaSpecification(
const ValueType& document) {
2146 SchemaDraft docDraft = GetSchemaDraft(document);
2147 OpenApiVersion docOapi = GetOpenApiVersion(document);
2149 if (docDraft != kDraftNone && docOapi != kVersionNone)
2152 if (docDraft != kDraftNone)
2154 else if (docOapi != kVersionNone)
2157 if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2159 else if (!spec_.IsSupported())
2164 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2166 UriType newid = UriType(CreateSchema(schema, pointer, v, document,
id), allocator_);
2168 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
2169 CreateSchemaRecursive(0, pointer.
Append(itr->name, allocator_), itr->value, document, newid);
2172 for (
SizeType i = 0; i < v.Size(); i++)
2173 CreateSchemaRecursive(0, pointer.
Append(i, allocator_), v[i], document, id);
2177 const UriType& CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2180 pointer.StringifyUriFragment(sb);
2181 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::CreateSchema", sb.GetString(),
id.GetString());
2183 if (
const SchemaType* sc = GetSchema(pointer)) {
2186 AddSchemaRefs(const_cast<SchemaType*>(sc));
2188 else if (!HandleRefSchema(pointer, schema, v, document,
id)) {
2190 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_,
id);
2198 *schema = typeless_;
2199 AddSchemaRefs(typeless_);
2206 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2207 typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2208 if (itr == v.MemberEnd())
2212 source.StringifyUriFragment(sb);
2213 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::HandleRefSchema", sb.GetString(),
id.GetString());
2215 new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2217 if (itr->value.IsString()) {
2218 SizeType len = itr->value.GetStringLength();
2223 UriType scopeId = UriType(
id, allocator_);
2224 UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2225 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), itr->value.GetString(), ref.GetString());
2228 PointerType basePointer = PointerType();
2229 const ValueType *base = FindId(document, ref, basePointer, docId_,
false);
2232 if (!remoteProvider_)
2235 if (
const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
2236 const Ch* s = ref.GetFragString();
2237 len = ref.GetFragStringLength();
2238 if (len <= 1 || s[1] ==
'/') {
2240 const PointerType pointer(s, len, allocator_);
2241 if (!pointer.IsValid())
2245 if (
const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
2248 AddSchemaRefs(const_cast<SchemaType *>(sc));
2261 const Ch* s = ref.GetFragString();
2262 len = ref.GetFragStringLength();
2263 if (len <= 1 || s[1] ==
'/') {
2265 const PointerType relPointer(s, len, allocator_);
2266 if (!relPointer.IsValid())
2270 if (
const ValueType *pv = relPointer.Get(*base)) {
2272 PointerType pointer(basePointer, allocator_);
2273 for (
SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2274 pointer = pointer.
Append(relPointer.GetTokens()[i], allocator_);
2275 if (IsCyclicRef(pointer))
2280 size_t unresolvedTokenIndex;
2281 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2282 CreateSchema(schema, pointer, *pv, document, scopeId);
2291 PointerType pointer(allocator_);
2292 if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2296 else if (
const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_),
true, basePointer)) {
2297 if (IsCyclicRef(pointer))
2302 size_t unresolvedTokenIndex;
2303 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2304 CreateSchema(schema, pointer, *pv, document, scopeId);
2316 *schema = typeless_;
2317 AddSchemaRefs(typeless_);
2325 ValueType* FindId(
const ValueType& doc,
const UriType& finduri, PointerType& resptr,
const UriType& baseuri,
bool full,
const PointerType& here = PointerType())
const {
2327 ValueType* resval = 0;
2328 UriType tempuri = UriType(finduri, allocator_);
2329 UriType localuri = UriType(baseuri, allocator_);
2332 typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
2333 if (m != doc.MemberEnd() && m->value.GetType() ==
kStringType) {
2334 localuri = UriType(m->value, allocator_).
Resolve(baseuri, allocator_);
2337 if (localuri.Match(finduri, full)) {
2338 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
2339 resval =
const_cast<ValueType *
>(&doc);
2344 for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
2346 resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
2352 for (
typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
2354 resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
2364 void AddSchemaRefs(SchemaType* schema) {
2365 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::AddSchemaRefs");
2366 while (!schemaRef_.Empty()) {
2367 SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
2368 SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
2369 new (entry) SchemaEntry(**ref, schema,
false, allocator_);
2374 bool IsCyclicRef(
const PointerType& pointer)
const {
2375 for (
const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
2376 if (pointer == **ref)
2381 const SchemaType* GetSchema(
const PointerType& pointer)
const {
2382 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2383 if (pointer == target->pointer)
2384 return target->schema;
2388 PointerType GetPointer(
const SchemaType* schema)
const {
2389 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2390 if (schema == target->schema)
2391 return target->pointer;
2392 return PointerType();
2395 const SchemaType* GetTypeless()
const {
return typeless_; }
2397 static const size_t kInitialSchemaMapSize = 64;
2398 static const size_t kInitialSchemaRefSize = 64;
2400 IRemoteSchemaDocumentProviderType* remoteProvider_;
2401 Allocator *allocator_;
2402 Allocator *ownAllocator_;
2403 const SchemaType* root_;
2404 SchemaType* typeless_;
2411 GValue currentError_;
2435 typename SchemaDocumentType,
2443 typedef typename SchemaDocumentType::SchemaType SchemaType;
2444 typedef typename SchemaDocumentType::PointerType PointerType;
2445 typedef typename SchemaType::EncodingType EncodingType;
2447 typedef typename EncodingType::Ch Ch;
2459 const SchemaDocumentType& schemaDocument,
2460 StateAllocator* allocator = 0,
2461 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2462 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2464 schemaDocument_(&schemaDocument),
2465 root_(schemaDocument.GetRoot()),
2466 stateAllocator_(allocator),
2467 ownStateAllocator_(0),
2468 schemaStack_(allocator, schemaStackCapacity),
2469 documentStack_(allocator, documentStackCapacity),
2473 missingDependents_(),
2475 flags_(kValidateDefaultFlags),
2478 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator");
2489 const SchemaDocumentType& schemaDocument,
2490 OutputHandler& outputHandler,
2491 StateAllocator* allocator = 0,
2492 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2493 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2495 schemaDocument_(&schemaDocument),
2496 root_(schemaDocument.GetRoot()),
2497 stateAllocator_(allocator),
2498 ownStateAllocator_(0),
2499 schemaStack_(allocator, schemaStackCapacity),
2500 documentStack_(allocator, documentStackCapacity),
2501 outputHandler_(&outputHandler),
2504 missingDependents_(),
2506 flags_(kValidateDefaultFlags),
2509 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (output handler)");
2520 while (!schemaStack_.Empty())
2522 documentStack_.Clear();
2529 currentError_.SetNull();
2530 missingDependents_.SetNull();
2538 virtual unsigned GetValidateFlags()
const {
2542 virtual bool IsValid()
const {
2543 if (!valid_)
return false;
2544 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return false;
2551 const ValueType& GetError()
const {
return error_; }
2556 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2562 if (!schemaStack_.Empty())
return CurrentContext().invalidKeyword;
2563 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return (
const Ch*)GetErrorsString();
2570 if (!schemaStack_.Empty())
return CurrentContext().invalidCode;
2571 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return kValidateErrors;
2578 if (documentStack_.Empty()) {
2579 return PointerType();
2582 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
2586 void NotMultipleOf(int64_t actual,
const SValue& expected) {
2589 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
2592 void NotMultipleOf(
double actual,
const SValue& expected) {
2595 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
2597 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2599 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2601 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2603 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
2605 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2607 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
2609 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2611 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2613 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2615 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
2617 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2622 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2626 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2628 void DoesNotMatch(
const Ch* str,
SizeType length) {
2629 currentError_.SetObject();
2630 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2634 void DisallowedItem(
SizeType index) {
2635 currentError_.SetObject();
2636 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2641 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2645 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2649 duplicates.PushBack(index1, GetStateAllocator());
2650 duplicates.PushBack(index2, GetStateAllocator());
2651 currentError_.SetObject();
2652 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2658 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2662 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2664 void StartMissingProperties() {
2665 currentError_.SetArray();
2667 void AddMissingProperty(
const SValue& name) {
2668 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2670 bool EndMissingProperties() {
2671 if (currentError_.Empty())
2674 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2675 currentError_ = error;
2679 void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) {
2680 for (
SizeType i = 0; i < count; ++i)
2681 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2683 void DisallowedProperty(
const Ch* name,
SizeType length) {
2684 currentError_.SetObject();
2685 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2689 void StartDependencyErrors() {
2690 currentError_.SetObject();
2692 void StartMissingDependentProperties() {
2693 missingDependents_.SetArray();
2695 void AddMissingDependentProperty(
const SValue& targetName) {
2696 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2698 void EndMissingDependentProperties(
const SValue& sourceName) {
2699 if (!missingDependents_.Empty()) {
2703 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2704 AddErrorCode(error, code);
2705 AddErrorInstanceLocation(error,
false);
2707 PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(
kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2708 AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2710 wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2711 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2714 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2715 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2716 static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2718 bool EndDependencyErrors() {
2719 if (currentError_.ObjectEmpty())
2722 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2723 currentError_ = error;
2729 currentError_.SetObject();
2730 AddCurrentError(code);
2732 void StartDisallowedType() {
2733 currentError_.SetArray();
2735 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2736 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2738 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2740 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2741 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2742 currentError_ = error;
2745 void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) {
2752 void NoneOf(ISchemaValidator** subvalidators,
SizeType count) {
2755 void NotOneOf(ISchemaValidator** subvalidators,
SizeType count) {
2760 matches.PushBack(index1, GetStateAllocator());
2761 matches.PushBack(index2, GetStateAllocator());
2762 currentError_.SetObject();
2763 currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
2767 currentError_.SetObject();
2770 void DisallowedWhenWriting() {
2771 currentError_.SetObject();
2774 void DisallowedWhenReading() {
2775 currentError_.SetObject();
2779 #define RAPIDJSON_STRING_(name, ...) \ 2780 static const StringRefType& Get##name##String() {\ 2781 static const Ch s[] = { __VA_ARGS__, '\0' };\ 2782 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \ 2786 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2787 RAPIDJSON_STRING_(SchemaRef,
's',
'c',
'h',
'e',
'm',
'a',
'R',
'e',
'f')
2788 RAPIDJSON_STRING_(Expected,
'e',
'x',
'p',
'e',
'c',
't',
'e',
'd')
2789 RAPIDJSON_STRING_(Actual,
'a',
'c',
't',
'u',
'a',
'l')
2790 RAPIDJSON_STRING_(Disallowed,
'd',
'i',
's',
'a',
'l',
'l',
'o',
'w',
'e',
'd')
2791 RAPIDJSON_STRING_(Missing,
'm',
'i',
's',
's',
'i',
'n',
'g')
2792 RAPIDJSON_STRING_(Errors,
'e',
'r',
'r',
'o',
'r',
's')
2793 RAPIDJSON_STRING_(ErrorCode,
'e',
'r',
'r',
'o',
'r',
'C',
'o',
'd',
'e')
2794 RAPIDJSON_STRING_(ErrorMessage,
'e',
'r',
'r',
'o',
'r',
'M',
'e',
's',
's',
'a',
'g',
'e')
2795 RAPIDJSON_STRING_(Duplicates,
'd',
'u',
'p',
'l',
'i',
'c',
'a',
't',
'e',
's')
2796 RAPIDJSON_STRING_(Matches,
'm',
'a',
't',
'c',
'h',
'e',
's')
2798 #undef RAPIDJSON_STRING_ 2800 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ 2801 if (!valid_) return false; \ 2802 if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\ 2803 *documentStack_.template Push<Ch>() = '\0';\ 2804 documentStack_.template Pop<Ch>(1);\ 2805 RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\ 2810 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ 2811 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\ 2812 if (context->hasher)\ 2813 static_cast<HasherType*>(context->hasher)->method arg2;\ 2814 if (context->validators)\ 2815 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ 2816 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\ 2817 if (context->patternPropertiesValidators)\ 2818 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ 2819 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\ 2822 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ 2823 valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\ 2826 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ 2827 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ 2828 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ 2829 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) 2831 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2832 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2833 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2834 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2835 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2836 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2837 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2838 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
2839 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2840 bool String(
const Ch* str,
SizeType length,
bool copy)
2841 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2843 bool StartObject() {
2844 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartObject");
2845 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2846 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2847 valid_ = !outputHandler_ || outputHandler_->StartObject();
2851 bool Key(
const Ch* str,
SizeType len,
bool copy) {
2852 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::Key", str);
2853 if (!valid_)
return false;
2854 AppendToken(str, len);
2855 if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
2859 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2860 valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2864 bool EndObject(
SizeType memberCount) {
2865 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndObject");
2866 if (!valid_)
return false;
2867 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2868 if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
2872 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2876 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartArray");
2877 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2878 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2879 valid_ = !outputHandler_ || outputHandler_->StartArray();
2883 bool EndArray(
SizeType elementCount) {
2884 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndArray");
2885 if (!valid_)
return false;
2886 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2887 if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
2891 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2894 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ 2895 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ 2896 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ 2899 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root,
const bool inheritContinueOnErrors) {
2900 *documentStack_.template Push<Ch>() =
'\0';
2901 documentStack_.template Pop<Ch>(1);
2904 &GetStateAllocator());
2905 sv->
SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(
unsigned)kValidateContinueOnErrorFlag);
2909 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2912 StateAllocator::Free(v);
2915 virtual void* CreateHasher() {
2919 virtual uint64_t GetHashCode(
void* hasher) {
2920 return static_cast<HasherType*
>(hasher)->GetHashCode();
2923 virtual void DestroryHasher(
void* hasher) {
2926 StateAllocator::Free(h);
2929 virtual void* MallocState(
size_t size) {
2930 return GetStateAllocator().Malloc(size);
2933 virtual void FreeState(
void* p) {
2934 StateAllocator::Free(p);
2939 typedef typename SchemaType::Context Context;
2944 const SchemaDocumentType& schemaDocument,
2945 const SchemaType& root,
2946 const char* basePath,
size_t basePathSize,
2948 StateAllocator* allocator = 0,
2949 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2950 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2952 schemaDocument_(&schemaDocument),
2954 stateAllocator_(allocator),
2955 ownStateAllocator_(0),
2956 schemaStack_(allocator, schemaStackCapacity),
2957 documentStack_(allocator, documentStackCapacity),
2961 missingDependents_(),
2963 flags_(kValidateDefaultFlags),
2966 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath :
"");
2967 if (basePath && basePathSize)
2968 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2971 StateAllocator& GetStateAllocator() {
2972 if (!stateAllocator_)
2973 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2974 return *stateAllocator_;
2977 bool GetContinueOnErrors()
const {
2978 return flags_ & kValidateContinueOnErrorFlag;
2982 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::BeginValue");
2983 if (schemaStack_.Empty())
2986 if (CurrentContext().inArray)
2989 if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2992 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2993 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2994 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2995 bool valueUniqueness = CurrentContext().valueUniqueness;
2997 PushSchema(*CurrentContext().valueSchema);
3000 CurrentContext().objectPatternValidatorType = patternValidatorType;
3001 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3002 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3003 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
3004 std::memset(va, 0,
sizeof(ISchemaValidator*) * count);
3005 for (
SizeType i = 0; i < count; i++)
3006 va[validatorCount++] = CreateSchemaValidator(*sa[i],
true);
3009 CurrentContext().arrayUniqueness = valueUniqueness;
3015 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndValue");
3016 if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3020 schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3021 *documentStack_.template Push<Ch>() =
'\0';
3022 documentStack_.template Pop<Ch>(1);
3023 RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3024 void* hasher = CurrentContext().hasher;
3025 uint64_t h = hasher && CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(hasher)->GetHashCode() : 0;
3029 if (!schemaStack_.Empty()) {
3030 Context& context = CurrentContext();
3032 if (hasher && context.valueUniqueness) {
3033 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
3035 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
3037 if (itr->GetUint64() == h) {
3038 DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
3040 if (GetContinueOnErrors()) {
3041 a->PushBack(h, GetStateAllocator());
3042 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/');
3046 a->PushBack(h, GetStateAllocator());
3051 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
3057 void AppendToken(
const Ch* str,
SizeType len) {
3058 documentStack_.template Reserve<Ch>(1 + len * 2);
3059 *documentStack_.template PushUnsafe<Ch>() =
'/';
3060 for (
SizeType i = 0; i < len; i++) {
3061 if (str[i] ==
'~') {
3062 *documentStack_.template PushUnsafe<Ch>() =
'~';
3063 *documentStack_.template PushUnsafe<Ch>() =
'0';
3065 else if (str[i] ==
'/') {
3066 *documentStack_.template PushUnsafe<Ch>() =
'~';
3067 *documentStack_.template PushUnsafe<Ch>() =
'1';
3070 *documentStack_.template PushUnsafe<Ch>() = str[i];
3074 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema, flags_); }
3076 RAPIDJSON_FORCEINLINE
void PopSchema() {
3077 Context* c = schemaStack_.template Pop<Context>(1);
3078 if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
3079 a->~HashCodeArray();
3080 StateAllocator::Free(a);
3085 void AddErrorInstanceLocation(ValueType& result,
bool parent) {
3087 PointerType instancePointer = GetInvalidDocumentPointer();
3088 ((parent && instancePointer.GetTokenCount() > 0)
3089 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3090 : instancePointer).StringifyUriFragment(sb);
3091 ValueType instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
3092 GetStateAllocator());
3093 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3096 void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
3098 SizeType len = CurrentSchema().GetURI().GetStringLength();
3099 if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len *
sizeof(Ch));
3100 if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
3101 else GetInvalidSchemaPointer().StringifyUriFragment(sb);
3102 ValueType schemaRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
3103 GetStateAllocator());
3104 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3108 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3111 void AddError(ValueType& keyword, ValueType& error) {
3113 if (member == error_.MemberEnd())
3114 error_.AddMember(keyword, error, GetStateAllocator());
3116 if (member->value.IsObject()) {
3118 errors.PushBack(member->value, GetStateAllocator());
3119 member->value = errors;
3121 member->value.PushBack(error, GetStateAllocator());
3126 AddErrorCode(currentError_, code);
3127 AddErrorInstanceLocation(currentError_, parent);
3128 AddErrorSchemaLocation(currentError_);
3129 AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(),
false).Move(), currentError_);
3132 void MergeError(ValueType& other) {
3134 AddError(it->name, it->value);
3138 void AddNumberError(
const ValidateErrorCode code, ValueType& actual,
const SValue& expected,
3139 const typename SchemaType::ValueType& (*exclusive)() = 0) {
3140 currentError_.SetObject();
3141 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
3142 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
3144 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
3145 AddCurrentError(code);
3149 ISchemaValidator** subvalidators,
SizeType count) {
3151 for (
SizeType i = 0; i < count; ++i)
3152 errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
3153 currentError_.SetObject();
3154 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
3155 AddCurrentError(code);
3158 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
3159 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
3160 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
3162 static const size_t kDefaultSchemaStackCapacity = 1024;
3163 static const size_t kDefaultDocumentStackCapacity = 256;
3164 const SchemaDocumentType* schemaDocument_;
3165 const SchemaType& root_;
3166 StateAllocator* stateAllocator_;
3167 StateAllocator* ownStateAllocator_;
3170 OutputHandler* outputHandler_;
3172 ValueType currentError_;
3173 ValueType missingDependents_;
3195 unsigned parseFlags,
3196 typename InputStream,
3197 typename SourceEncoding,
3198 typename SchemaDocumentType = SchemaDocument,
3202 typedef typename SchemaDocumentType::PointerType PointerType;
3203 typedef typename InputStream::Ch Ch;
3213 template <
typename Handler>
3214 bool operator()(Handler& handler) {
3217 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
3219 isValid_ = validator.IsValid();
3221 invalidSchemaPointer_ = PointerType();
3222 invalidSchemaKeyword_ = 0;
3223 invalidDocumentPointer_ = PointerType();
3231 error_.CopyFrom(validator.
GetError(), allocator_);
3234 return parseResult_;
3237 const ParseResult& GetParseResult()
const {
return parseResult_; }
3238 bool IsValid()
const {
return isValid_; }
3239 const PointerType& GetInvalidSchemaPointer()
const {
return invalidSchemaPointer_; }
3240 const Ch* GetInvalidSchemaKeyword()
const {
return invalidSchemaKeyword_; }
3241 const PointerType& GetInvalidDocumentPointer()
const {
return invalidDocumentPointer_; }
3242 const ValueType& GetError()
const {
return error_; }
3247 const SchemaDocumentType& sd_;
3250 PointerType invalidSchemaPointer_;
3251 const Ch* invalidSchemaKeyword_;
3252 PointerType invalidDocumentPointer_;
3254 StackAllocator allocator_;
3262 #endif // RAPIDJSON_SCHEMA_H_ $ref is remote but the remote provider did not return a schema
Definition: error.h:230
Object has more members than 'maxProperties' value.
Definition: error.h:181
Array is longer than the 'maxItems' value.
Definition: error.h:176
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:415
Array is shorter than the 'minItems' value.
Definition: error.h:177
Property must not be both 'readOnly' and 'writeOnly'.
Definition: error.h:235
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437
Property did not match any of the sub-schemas specified by 'oneOf'.
Definition: error.h:191
void ResetError()
Reset the error state.
Definition: schema.h:2527
Both JSON schema draft and OpenAPI version found in document.
Definition: error.h:234
$ref is remote but there is no remote provider
Definition: error.h:229
Number is greater than or equal to the 'maximum' value.
Definition: error.h:168
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:320
Property matched the sub-schema specified by 'not'.
Definition: error.h:195
object
Definition: rapidjson.h:733
Default implementation of Handler.
Definition: fwd.h:85
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:2577
JSON schema document.
Definition: fwd.h:136
Definition: schema.h:1751
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
(Constant) member iterator for a JSON object value
Definition: document.h:186
array
Definition: rapidjson.h:734
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:2561
Property has a type that is not allowed by the schema.
Definition: error.h:189
~GenericSchemaValidator()
Destructor.
Definition: schema.h:2513
See other errors.
Definition: error.h:185
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition: pointer.h:235
A type-unsafe stack for storing different types of data.
Definition: stack.h:37
Object has missing property or schema dependencies.
Definition: error.h:186
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:3211
ValueType & GetError()
End of Implementation of ISchemaValidator.
Definition: schema.h:2550
false
Definition: rapidjson.h:731
Invalid regular expression in 'pattern' or 'patternProperties'.
Definition: error.h:231
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition: stringbuffer.h:82
Object has additional members that are not allowed by the schema.
Definition: error.h:184
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:110
Result of parsing (wraps ParseErrorCode)
Definition: error.h:106
void Reset()
Reset the internal states.
Definition: schema.h:2519
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:2555
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1956
Property did not match any of the sub-schemas specified by 'anyOf'.
Definition: error.h:194
String does not match the 'pattern' regular expression.
Definition: error.h:174
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:712
Number is greater than the 'maximum' value.
Definition: error.h:167
void SchemaErrorPointer(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length, const PointerType &pointer)
Method for error with invalid pointer.
Definition: schema.h:1995
string
Definition: rapidjson.h:735
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: fwd.h:88
Property is write-only but has been provided when validation is for reading.
Definition: error.h:198
$ref is cyclical
Definition: error.h:228
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
GValue & GetError()
Gets the error object.
Definition: schema.h:1959
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition: schema.h:2488
JSON schema draft or OpenAPI version is not supported.
Definition: error.h:233
SchemaErrorCode
Error codes when validating.
Definition: error.h:220
void SchemaError(const SchemaErrorCode code, const PointerType &location)
Default error method.
Definition: schema.h:1982
number
Definition: rapidjson.h:736
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:716
Property did not match all of the sub-schemas specified by 'allOf'.
Definition: error.h:193
Object is missing one or more members required by the schema.
Definition: error.h:183
Definition: allocators.h:423
C-runtime library allocator.
Definition: allocators.h:83
ValidateErrorCode GetInvalidSchemaCode() const
Gets the error code of invalid schema.
Definition: schema.h:2569
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0, const PointerType &pointer=PointerType(), const Specification &spec=Specification(kDraft04))
Constructor.
Definition: schema.h:1844
GenericUri Resolve(const GenericUri &baseuri, Allocator *allocator=0)
Resolve this URI against another (base) URI in accordance with URI resolution rules.
Definition: uri.h:156
Array has additional items that are not allowed by the schema.
Definition: error.h:179
A helper class for parsing with validation.
Definition: schema.h:3200
Represents an in-memory output stream.
Definition: fwd.h:59
$ref fragment must be a JSON pointer
Definition: error.h:224
Number is less than or equal to the 'minimum' value.
Definition: error.h:170
Property has a value that is not one of its allowed enumerated values.
Definition: error.h:188
$ref fragment is not a valid JSON pointer at offset
Definition: error.h:226
void SetValidateFlags(unsigned flags)
Implementation of ISchemaValidator.
Definition: schema.h:2535
Pointer to start of schema does not resolve to a location in the document.
Definition: error.h:223
#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS
User-defined kValidateDefaultFlags definition.
Definition: schema.h:178
String is longer than the 'maxLength' value.
Definition: error.h:173
void SchemaErrorValue(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length)
Method for error with single string value insert.
Definition: schema.h:1988
Property matched more than one of the sub-schemas specified by 'oneOf'.
Definition: error.h:192
true
Definition: rapidjson.h:732
Reference to a constant string (not taking a copy)
Definition: document.h:346
Top level error code when kValidateContinueOnErrorsFlag set.
Definition: error.h:163
Array has duplicate items but 'uniqueItems' is true.
Definition: error.h:178
Number is less than the 'minimum' value.
Definition: error.h:169
$ref must not be an empty string
Definition: error.h:225
String is longer than the 'maxLength' value.
Definition: error.h:172
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1919
Type
Type of JSON value.
Definition: rapidjson.h:729
Default memory allocator used by the parser and DOM.
Definition: allocators.h:130
$ref does not resolve to a location in the target document
Definition: error.h:227
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:2458
Property is read-only but has been provided when validation is for writing.
Definition: error.h:197
Object has less members than 'minProperties' value.
Definition: error.h:182
Number is not a multiple of the 'multipleOf' value.
Definition: error.h:166
JSON Schema Validator.
Definition: fwd.h:145
JSON schema draft or OpenAPI version is not recognized.
Definition: error.h:232
No error.
Definition: error.h:164
null
Definition: rapidjson.h:730
ValidateErrorCode
Error codes when validating.
Definition: error.h:162
static const Specification GetSpecification(const ValueType &document)
Static method to get the specification of any schema document.
Definition: schema.h:1943