15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
20 #include "stringbuffer.h"
24 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
27 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
30 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
33 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
36 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
37 #include "internal/regex.h"
38 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
42 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
43 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
45 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
48 #ifndef RAPIDJSON_SCHEMA_VERBOSE
49 #define RAPIDJSON_SCHEMA_VERBOSE 0
52 #if RAPIDJSON_SCHEMA_VERBOSE
53 #include "stringbuffer.h"
59 RAPIDJSON_DIAG_OFF(effc++)
63 RAPIDJSON_DIAG_OFF(weak-vtables)
64 RAPIDJSON_DIAG_OFF(exit-time-destructors)
65 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
66 RAPIDJSON_DIAG_OFF(variadic-macros)
67 #elif defined(_MSC_VER)
68 RAPIDJSON_DIAG_OFF(4512)
71 RAPIDJSON_NAMESPACE_BEGIN
76 #if RAPIDJSON_SCHEMA_VERBOSE
80 inline void PrintInvalidKeyword(
const char* keyword) {
81 printf(
"Fail keyword: %s\n", keyword);
84 inline void PrintInvalidKeyword(
const wchar_t* keyword) {
85 wprintf(L
"Fail keyword: %ls\n", keyword);
88 inline void PrintInvalidDocument(
const char* document) {
89 printf(
"Fail document: %s\n\n", document);
92 inline void PrintInvalidDocument(
const wchar_t* document) {
93 wprintf(L
"Fail document: %ls\n\n", document);
96 inline void PrintValidatorPointers(
unsigned depth,
const char* s,
const char* d) {
97 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
100 inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
101 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
106 #endif // RAPIDJSON_SCHEMA_VERBOSE
111 #if RAPIDJSON_SCHEMA_VERBOSE
112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
118 RAPIDJSON_MULTILINEMACRO_BEGIN\
119 context.invalidCode = code;\
120 context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
121 RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
123 RAPIDJSON_MULTILINEMACRO_END
134 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
135 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
150 template <
typename ValueType,
typename Allocator>
151 class GenericSchemaDocument;
155 template <
typename SchemaDocumentType>
161 class ISchemaValidator {
163 virtual ~ISchemaValidator() {}
164 virtual bool IsValid()
const = 0;
165 virtual void SetValidateFlags(
unsigned flags) = 0;
166 virtual unsigned GetValidateFlags()
const = 0;
172 template <
typename SchemaType>
173 class ISchemaStateFactory {
175 virtual ~ISchemaStateFactory() {}
176 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType&,
const bool inheritContinueOnErrors) = 0;
177 virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
178 virtual void* CreateHasher() = 0;
179 virtual uint64_t GetHashCode(
void* hasher) = 0;
180 virtual void DestroryHasher(
void* hasher) = 0;
181 virtual void* MallocState(
size_t size) = 0;
182 virtual void FreeState(
void* p) = 0;
188 template <
typename SchemaType>
189 class IValidationErrorHandler {
191 typedef typename SchemaType::Ch Ch;
192 typedef typename SchemaType::SValue SValue;
194 virtual ~IValidationErrorHandler() {}
196 virtual void NotMultipleOf(int64_t actual,
const SValue& expected) = 0;
197 virtual void NotMultipleOf(uint64_t actual,
const SValue& expected) = 0;
198 virtual void NotMultipleOf(
double actual,
const SValue& expected) = 0;
199 virtual void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
200 virtual void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
201 virtual void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) = 0;
202 virtual void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
203 virtual void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
204 virtual void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) = 0;
206 virtual void TooLong(
const Ch* str,
SizeType length,
SizeType expected) = 0;
207 virtual void TooShort(
const Ch* str,
SizeType length,
SizeType expected) = 0;
208 virtual void DoesNotMatch(
const Ch* str,
SizeType length) = 0;
210 virtual void DisallowedItem(
SizeType index) = 0;
212 virtual void TooManyItems(
SizeType actualCount,
SizeType expectedCount) = 0;
215 virtual void TooManyProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
216 virtual void TooFewProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
217 virtual void StartMissingProperties() = 0;
218 virtual void AddMissingProperty(
const SValue& name) = 0;
219 virtual bool EndMissingProperties() = 0;
220 virtual void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) = 0;
221 virtual void DisallowedProperty(
const Ch* name,
SizeType length) = 0;
223 virtual void StartDependencyErrors() = 0;
224 virtual void StartMissingDependentProperties() = 0;
225 virtual void AddMissingDependentProperty(
const SValue& targetName) = 0;
226 virtual void EndMissingDependentProperties(
const SValue& sourceName) = 0;
227 virtual void AddDependencySchemaError(
const SValue& souceName, ISchemaValidator* subvalidator) = 0;
228 virtual bool EndDependencyErrors() = 0;
231 virtual void StartDisallowedType() = 0;
232 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
233 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
234 virtual void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) = 0;
235 virtual void NoneOf(ISchemaValidator** subvalidators,
SizeType count) = 0;
236 virtual void NotOneOf(ISchemaValidator** subvalidators,
SizeType count,
bool matched) = 0;
237 virtual void Disallowed() = 0;
245 template<
typename Encoding,
typename Allocator>
248 typedef typename Encoding::Ch Ch;
250 Hasher(
Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
252 bool Null() {
return WriteType(
kNullType); }
254 bool Int(
int i) { Number n; n.u.i = i; n.d = static_cast<double>(i);
return WriteNumber(n); }
255 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u);
return WriteNumber(n); }
256 bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i);
return WriteNumber(n); }
257 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u);
return WriteNumber(n); }
258 bool Double(
double d) {
260 if (d < 0) n.u.i = static_cast<int64_t>(d);
261 else n.u.u = static_cast<uint64_t>(d);
263 return WriteNumber(n);
266 bool RawNumber(
const Ch* str,
SizeType len,
bool) {
271 bool String(
const Ch* str,
SizeType len,
bool) {
276 bool StartObject() {
return true; }
277 bool Key(
const Ch* str,
SizeType len,
bool copy) {
return String(str, len, copy); }
278 bool EndObject(
SizeType memberCount) {
280 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
281 for (
SizeType i = 0; i < memberCount; i++)
282 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
283 *stack_.template Push<uint64_t>() = h;
287 bool StartArray() {
return true; }
288 bool EndArray(
SizeType elementCount) {
290 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
291 for (
SizeType i = 0; i < elementCount; i++)
293 *stack_.template Push<uint64_t>() = h;
297 bool IsValid()
const {
return stack_.GetSize() ==
sizeof(uint64_t); }
299 uint64_t GetHashCode()
const {
301 return *stack_.template Top<uint64_t>();
305 static const size_t kDefaultSize = 256;
314 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
316 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
318 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
321 const unsigned char* d = static_cast<const unsigned char*>(data);
322 for (
size_t i = 0; i < len; i++)
324 *stack_.template Push<uint64_t>() = h;
328 static uint64_t Hash(uint64_t h, uint64_t d) {
335 Stack<Allocator> stack_;
341 template <
typename SchemaDocumentType>
342 struct SchemaValidationContext {
343 typedef Schema<SchemaDocumentType> SchemaType;
344 typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
345 typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
346 typedef typename SchemaType::ValueType ValueType;
347 typedef typename ValueType::Ch Ch;
349 enum PatternValidatorType {
350 kPatternValidatorOnly,
351 kPatternValidatorWithProperty,
352 kPatternValidatorWithAdditionalProperty
355 SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh,
const SchemaType* s) :
363 arrayElementHashCodes(),
366 patternPropertiesValidators(),
367 patternPropertiesValidatorCount(),
368 patternPropertiesSchemas(),
369 patternPropertiesSchemaCount(),
370 valuePatternValidatorType(kPatternValidatorOnly),
373 valueUniqueness(false),
374 arrayUniqueness(false)
378 ~SchemaValidationContext() {
380 factory.DestroryHasher(hasher);
382 for (
SizeType i = 0; i < validatorCount; i++)
383 factory.DestroySchemaValidator(validators[i]);
384 factory.FreeState(validators);
386 if (patternPropertiesValidators) {
387 for (
SizeType i = 0; i < patternPropertiesValidatorCount; i++)
388 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
389 factory.FreeState(patternPropertiesValidators);
391 if (patternPropertiesSchemas)
392 factory.FreeState(patternPropertiesSchemas);
394 factory.FreeState(propertyExist);
397 SchemaValidatorFactoryType& factory;
398 ErrorHandlerType& error_handler;
399 const SchemaType* schema;
400 const SchemaType* valueSchema;
401 const Ch* invalidKeyword;
404 void* arrayElementHashCodes;
405 ISchemaValidator** validators;
407 ISchemaValidator** patternPropertiesValidators;
408 SizeType patternPropertiesValidatorCount;
409 const SchemaType** patternPropertiesSchemas;
410 SizeType patternPropertiesSchemaCount;
411 PatternValidatorType valuePatternValidatorType;
412 PatternValidatorType objectPatternValidatorType;
416 bool valueUniqueness;
417 bool arrayUniqueness;
423 template <
typename SchemaDocumentType>
426 typedef typename SchemaDocumentType::ValueType ValueType;
427 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
428 typedef typename SchemaDocumentType::PointerType PointerType;
429 typedef typename ValueType::EncodingType EncodingType;
430 typedef typename EncodingType::Ch Ch;
431 typedef SchemaValidationContext<SchemaDocumentType> Context;
432 typedef Schema<SchemaDocumentType> SchemaType;
433 typedef GenericValue<EncodingType, AllocatorType> SValue;
434 typedef IValidationErrorHandler<Schema> ErrorHandler;
435 friend class GenericSchemaDocument<ValueType, AllocatorType>;
437 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator) :
438 allocator_(allocator),
439 uri_(schemaDocument->GetURI(), *allocator),
440 pointer_(p, allocator),
441 typeless_(schemaDocument->GetTypeless()),
445 type_((1 << kTotalSchemaType) - 1),
447 notValidatorIndex_(),
449 additionalPropertiesSchema_(),
450 patternProperties_(),
451 patternPropertyCount_(),
455 additionalProperties_(true),
458 hasSchemaDependencies_(),
459 additionalItemsSchema_(),
465 additionalItems_(true),
470 exclusiveMinimum_(false),
471 exclusiveMaximum_(false),
472 defaultValueLength_(0)
474 typedef typename ValueType::ConstValueIterator ConstValueIterator;
475 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
477 if (!value.IsObject())
480 if (
const ValueType* v = GetMember(value, GetTypeString())) {
484 else if (v->IsArray())
485 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
489 if (
const ValueType* v = GetMember(value, GetEnumString())) {
490 if (v->IsArray() && v->Size() > 0) {
491 enum_ = static_cast<uint64_t*>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
492 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
493 typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
494 char buffer[256u + 24];
495 MemoryPoolAllocator<> hasherAllocator(buffer,
sizeof(buffer));
496 EnumHasherType h(&hasherAllocator, 256);
498 enum_[enumCount_++] = h.GetHashCode();
503 if (schemaDocument) {
504 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
505 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
506 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
508 if (
const ValueType* v = GetMember(value, GetNotString())) {
509 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
510 notValidatorIndex_ = validatorCount_;
517 const ValueType* properties = GetMember(value, GetPropertiesString());
518 const ValueType* required = GetMember(value, GetRequiredString());
519 const ValueType* dependencies = GetMember(value, GetDependenciesString());
524 if (properties && properties->IsObject())
525 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
526 AddUniqueElement(allProperties, itr->name);
528 if (required && required->IsArray())
529 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
531 AddUniqueElement(allProperties, *itr);
533 if (dependencies && dependencies->IsObject())
534 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
535 AddUniqueElement(allProperties, itr->name);
536 if (itr->value.IsArray())
537 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
539 AddUniqueElement(allProperties, *i);
542 if (allProperties.Size() > 0) {
543 propertyCount_ = allProperties.Size();
544 properties_ = static_cast<Property*>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
545 for (
SizeType i = 0; i < propertyCount_; i++) {
546 new (&properties_[i]) Property();
547 properties_[i].name = allProperties[i];
548 properties_[i].schema = typeless_;
553 if (properties && properties->IsObject()) {
554 PointerType q = p.Append(GetPropertiesString(), allocator_);
555 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
557 if (FindPropertyIndex(itr->name, &index))
558 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
562 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
563 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
564 patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
565 patternPropertyCount_ = 0;
567 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
568 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
569 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
570 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
571 patternPropertyCount_++;
575 if (required && required->IsArray())
576 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
577 if (itr->IsString()) {
579 if (FindPropertyIndex(*itr, &index)) {
580 properties_[index].required =
true;
585 if (dependencies && dependencies->IsObject()) {
586 PointerType q = p.Append(GetDependenciesString(), allocator_);
587 hasDependencies_ =
true;
588 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
590 if (FindPropertyIndex(itr->name, &sourceIndex)) {
591 if (itr->value.IsArray()) {
592 properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
593 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
594 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
596 if (FindPropertyIndex(*targetItr, &targetIndex))
597 properties_[sourceIndex].dependencies[targetIndex] =
true;
600 else if (itr->value.IsObject()) {
601 hasSchemaDependencies_ =
true;
602 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
603 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
610 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
612 additionalProperties_ = v->GetBool();
613 else if (v->IsObject())
614 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
617 AssignIfExist(minProperties_, value, GetMinPropertiesString());
618 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
621 if (
const ValueType* v = GetMember(value, GetItemsString())) {
622 PointerType q = p.Append(GetItemsString(), allocator_);
624 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
625 else if (v->IsArray()) {
626 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
628 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
629 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
633 AssignIfExist(minItems_, value, GetMinItemsString());
634 AssignIfExist(maxItems_, value, GetMaxItemsString());
636 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
638 additionalItems_ = v->GetBool();
639 else if (v->IsObject())
640 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
643 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
646 AssignIfExist(minLength_, value, GetMinLengthString());
647 AssignIfExist(maxLength_, value, GetMaxLengthString());
649 if (
const ValueType* v = GetMember(value, GetPatternString()))
650 pattern_ = CreatePattern(*v);
653 if (
const ValueType* v = GetMember(value, GetMinimumString()))
655 minimum_.CopyFrom(*v, *allocator_);
657 if (
const ValueType* v = GetMember(value, GetMaximumString()))
659 maximum_.CopyFrom(*v, *allocator_);
661 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
662 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
664 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
665 if (v->IsNumber() && v->GetDouble() > 0.0)
666 multipleOf_.CopyFrom(*v, *allocator_);
669 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
671 defaultValueLength_ = v->GetStringLength();
676 AllocatorType::Free(enum_);
678 for (
SizeType i = 0; i < propertyCount_; i++)
679 properties_[i].~Property();
680 AllocatorType::Free(properties_);
682 if (patternProperties_) {
683 for (
SizeType i = 0; i < patternPropertyCount_; i++)
684 patternProperties_[i].~PatternProperty();
685 AllocatorType::Free(patternProperties_);
687 AllocatorType::Free(itemsTuple_);
688 #if RAPIDJSON_SCHEMA_HAS_REGEX
690 pattern_->~RegexType();
691 AllocatorType::Free(pattern_);
696 const SValue& GetURI()
const {
700 const PointerType& GetPointer()
const {
704 bool BeginValue(Context& context)
const {
705 if (context.inArray) {
707 context.valueUniqueness =
true;
710 context.valueSchema = itemsList_;
711 else if (itemsTuple_) {
712 if (context.arrayElementIndex < itemsTupleCount_)
713 context.valueSchema = itemsTuple_[context.arrayElementIndex];
714 else if (additionalItemsSchema_)
715 context.valueSchema = additionalItemsSchema_;
716 else if (additionalItems_)
717 context.valueSchema = typeless_;
719 context.error_handler.DisallowedItem(context.arrayElementIndex);
721 context.valueSchema = typeless_;
723 context.arrayElementIndex++;
728 context.valueSchema = typeless_;
730 context.arrayElementIndex++;
735 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
737 if (context.patternPropertiesValidatorCount > 0) {
738 bool otherValid =
false;
739 SizeType count = context.patternPropertiesValidatorCount;
740 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
741 otherValid = context.patternPropertiesValidators[--count]->IsValid();
743 bool patternValid =
true;
744 for (
SizeType i = 0; i < count; i++)
745 if (!context.patternPropertiesValidators[i]->IsValid()) {
746 patternValid =
false;
750 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
752 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
756 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
757 if (!patternValid || !otherValid) {
758 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
762 else if (!patternValid && !otherValid) {
763 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
769 if (enum_ && context.hasher) {
770 const uint64_t h = context.factory.GetHashCode(context.hasher);
771 for (
SizeType i = 0; i < enumCount_; i++)
780 if (context.validatorCount > 0) {
782 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
783 if (!context.validators[i]->IsValid()) {
784 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
788 if (anyOf_.schemas) {
789 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
790 if (context.validators[i]->IsValid())
792 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
797 if (oneOf_.schemas) {
798 bool oneValid =
false;
799 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
800 if (context.validators[i]->IsValid()) {
802 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count,
true);
808 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count,
false);
813 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
814 context.error_handler.Disallowed();
822 bool Null(Context& context)
const {
823 if (!(type_ & (1 << kNullSchemaType))) {
824 DisallowedType(context, GetNullString());
827 return CreateParallelValidator(context);
830 bool Bool(Context& context,
bool)
const {
831 if (!(type_ & (1 << kBooleanSchemaType))) {
832 DisallowedType(context, GetBooleanString());
835 return CreateParallelValidator(context);
838 bool Int(Context& context,
int i)
const {
839 if (!CheckInt(context, i))
841 return CreateParallelValidator(context);
844 bool Uint(Context& context,
unsigned u)
const {
845 if (!CheckUint(context, u))
847 return CreateParallelValidator(context);
850 bool Int64(Context& context, int64_t i)
const {
851 if (!CheckInt(context, i))
853 return CreateParallelValidator(context);
856 bool Uint64(Context& context, uint64_t u)
const {
857 if (!CheckUint(context, u))
859 return CreateParallelValidator(context);
862 bool Double(Context& context,
double d)
const {
863 if (!(type_ & (1 << kNumberSchemaType))) {
864 DisallowedType(context, GetNumberString());
868 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
871 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
874 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
877 return CreateParallelValidator(context);
880 bool String(Context& context,
const Ch* str,
SizeType length,
bool)
const {
881 if (!(type_ & (1 << kStringSchemaType))) {
882 DisallowedType(context, GetStringString());
886 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
888 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
889 if (count < minLength_) {
890 context.error_handler.TooShort(str, length, minLength_);
893 if (count > maxLength_) {
894 context.error_handler.TooLong(str, length, maxLength_);
900 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
901 context.error_handler.DoesNotMatch(str, length);
905 return CreateParallelValidator(context);
908 bool StartObject(Context& context)
const {
909 if (!(type_ & (1 << kObjectSchemaType))) {
910 DisallowedType(context, GetObjectString());
914 if (hasDependencies_ || hasRequired_) {
915 context.propertyExist = static_cast<bool*>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
916 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
919 if (patternProperties_) {
920 SizeType count = patternPropertyCount_ + 1;
921 context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
922 context.patternPropertiesSchemaCount = 0;
923 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
926 return CreateParallelValidator(context);
929 bool Key(Context& context,
const Ch* str,
SizeType len,
bool)
const {
930 if (patternProperties_) {
931 context.patternPropertiesSchemaCount = 0;
932 for (
SizeType i = 0; i < patternPropertyCount_; i++)
933 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
934 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
935 context.valueSchema = typeless_;
940 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
941 if (context.patternPropertiesSchemaCount > 0) {
942 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
943 context.valueSchema = typeless_;
944 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
947 context.valueSchema = properties_[index].schema;
949 if (context.propertyExist)
950 context.propertyExist[index] =
true;
955 if (additionalPropertiesSchema_) {
956 if (context.patternPropertiesSchemaCount > 0) {
957 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
958 context.valueSchema = typeless_;
959 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
962 context.valueSchema = additionalPropertiesSchema_;
965 else if (additionalProperties_) {
966 context.valueSchema = typeless_;
970 if (context.patternPropertiesSchemaCount == 0) {
972 context.valueSchema = typeless_;
973 context.error_handler.DisallowedProperty(str, len);
980 bool EndObject(Context& context,
SizeType memberCount)
const {
982 context.error_handler.StartMissingProperties();
983 for (
SizeType index = 0; index < propertyCount_; index++)
984 if (properties_[index].required && !context.propertyExist[index])
985 if (properties_[index].schema->defaultValueLength_ == 0 )
986 context.error_handler.AddMissingProperty(properties_[index].name);
987 if (context.error_handler.EndMissingProperties())
991 if (memberCount < minProperties_) {
992 context.error_handler.TooFewProperties(memberCount, minProperties_);
996 if (memberCount > maxProperties_) {
997 context.error_handler.TooManyProperties(memberCount, maxProperties_);
1001 if (hasDependencies_) {
1002 context.error_handler.StartDependencyErrors();
1003 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1004 const Property& source = properties_[sourceIndex];
1005 if (context.propertyExist[sourceIndex]) {
1006 if (source.dependencies) {
1007 context.error_handler.StartMissingDependentProperties();
1008 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1009 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1010 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1011 context.error_handler.EndMissingDependentProperties(source.name);
1013 else if (source.dependenciesSchema) {
1014 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1015 if (!dependenciesValidator->IsValid())
1016 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1020 if (context.error_handler.EndDependencyErrors())
1027 bool StartArray(Context& context)
const {
1028 context.arrayElementIndex = 0;
1029 context.inArray =
true;
1031 if (!(type_ & (1 << kArraySchemaType))) {
1032 DisallowedType(context, GetArrayString());
1036 return CreateParallelValidator(context);
1039 bool EndArray(Context& context,
SizeType elementCount)
const {
1040 context.inArray =
false;
1042 if (elementCount < minItems_) {
1043 context.error_handler.TooFewItems(elementCount, minItems_);
1047 if (elementCount > maxItems_) {
1048 context.error_handler.TooManyItems(elementCount, maxItems_);
1055 static const ValueType& GetValidateErrorKeyword(
ValidateErrorCode validateErrorCode) {
1056 switch (validateErrorCode) {
1088 default:
return GetNullString();
1094 #define RAPIDJSON_STRING_(name, ...) \
1095 static const ValueType& Get##name##String() {\
1096 static const Ch s[] = { __VA_ARGS__, '\0' };\
1097 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1101 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1102 RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1103 RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1104 RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1105 RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1106 RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1107 RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1108 RAPIDJSON_STRING_(
Type, 't', 'y', 'p', 'e')
1109 RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1110 RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1111 RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1112 RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1113 RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1114 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1115 RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1116 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1117 RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1118 RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1119 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1120 RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1121 RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1122 RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1123 RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1124 RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1125 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1126 RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1127 RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1128 RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1129 RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1130 RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1131 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1132 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1133 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1134 RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1136 #undef RAPIDJSON_STRING_
1139 enum SchemaValueType {
1150 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1151 typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1152 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1153 typedef std::basic_regex<Ch> RegexType;
1155 typedef char RegexType;
1158 struct SchemaArray {
1159 SchemaArray() : schemas(), count() {}
1160 ~SchemaArray() { AllocatorType::Free(schemas); }
1161 const SchemaType** schemas;
1166 template <
typename V1,
typename V2>
1167 void AddUniqueElement(V1& a,
const V2& v) {
1168 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1171 V1 c(v, *allocator_);
1172 a.PushBack(c, *allocator_);
1175 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1176 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1177 return itr != value.MemberEnd() ? &(itr->value) : 0;
1180 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1181 if (
const ValueType* v = GetMember(value, name))
1186 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
1187 if (
const ValueType* v = GetMember(value, name))
1188 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1189 out = static_cast<SizeType>(v->GetUint64());
1192 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1193 if (
const ValueType* v = GetMember(value, name)) {
1194 if (v->IsArray() && v->Size() > 0) {
1195 PointerType q = p.Append(name, allocator_);
1196 out.count = v->Size();
1197 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1198 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
1199 for (
SizeType i = 0; i < out.count; i++)
1200 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1201 out.begin = validatorCount_;
1202 validatorCount_ += out.count;
1207 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1208 template <
typename ValueType>
1209 RegexType* CreatePattern(
const ValueType& value) {
1210 if (value.IsString()) {
1211 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1212 if (!r->IsValid()) {
1214 AllocatorType::Free(r);
1222 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1223 GenericRegexSearch<RegexType> rs(*pattern);
1224 return rs.Search(str);
1226 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1227 template <
typename ValueType>
1228 RegexType* CreatePattern(
const ValueType& value) {
1229 if (value.IsString()) {
1230 RegexType *r = static_cast<RegexType*>(allocator_->Malloc(
sizeof(RegexType)));
1232 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1234 catch (
const std::regex_error&) {
1235 AllocatorType::Free(r);
1241 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1242 std::match_results<const Ch*> r;
1243 return std::regex_search(str, str + length, r, *pattern);
1246 template <
typename ValueType>
1247 RegexType* CreatePattern(
const ValueType&) {
return 0; }
1249 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1250 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1252 void AddType(
const ValueType& type) {
1253 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1254 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1255 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1256 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1257 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1258 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1259 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1262 bool CreateParallelValidator(Context& context)
const {
1263 if (enum_ || context.arrayUniqueness)
1264 context.hasher = context.factory.CreateHasher();
1266 if (validatorCount_) {
1268 context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1269 context.validatorCount = validatorCount_;
1273 CreateSchemaValidators(context, allOf_,
false);
1276 CreateSchemaValidators(context, anyOf_,
false);
1279 CreateSchemaValidators(context, oneOf_,
false);
1282 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_,
false);
1284 if (hasSchemaDependencies_) {
1285 for (
SizeType i = 0; i < propertyCount_; i++)
1286 if (properties_[i].dependenciesSchema)
1287 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema,
false);
1294 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas,
const bool inheritContinueOnErrors)
const {
1295 for (
SizeType i = 0; i < schemas.count; i++)
1296 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1300 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1301 SizeType len = name.GetStringLength();
1302 const Ch* str = name.GetString();
1303 for (
SizeType index = 0; index < propertyCount_; index++)
1304 if (properties_[index].name.GetStringLength() == len &&
1305 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1313 bool CheckInt(Context& context, int64_t i)
const {
1314 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1315 DisallowedType(context, GetIntegerString());
1319 if (!minimum_.IsNull()) {
1320 if (minimum_.IsInt64()) {
1321 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1322 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1326 else if (minimum_.IsUint64()) {
1327 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1330 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1334 if (!maximum_.IsNull()) {
1335 if (maximum_.IsInt64()) {
1336 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1337 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1341 else if (maximum_.IsUint64()) { }
1343 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1347 if (!multipleOf_.IsNull()) {
1348 if (multipleOf_.IsUint64()) {
1349 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1350 context.error_handler.NotMultipleOf(i, multipleOf_);
1354 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1361 bool CheckUint(Context& context, uint64_t i)
const {
1362 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1363 DisallowedType(context, GetIntegerString());
1367 if (!minimum_.IsNull()) {
1368 if (minimum_.IsUint64()) {
1369 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1370 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1374 else if (minimum_.IsInt64())
1376 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1380 if (!maximum_.IsNull()) {
1381 if (maximum_.IsUint64()) {
1382 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1383 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1387 else if (maximum_.IsInt64()) {
1388 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1391 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1395 if (!multipleOf_.IsNull()) {
1396 if (multipleOf_.IsUint64()) {
1397 if (i % multipleOf_.GetUint64() != 0) {
1398 context.error_handler.NotMultipleOf(i, multipleOf_);
1402 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1409 bool CheckDoubleMinimum(Context& context,
double d)
const {
1410 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1411 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1417 bool CheckDoubleMaximum(Context& context,
double d)
const {
1418 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1419 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1425 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1426 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1427 double q = std::floor(a / b);
1428 double r = a - q * b;
1430 context.error_handler.NotMultipleOf(d, multipleOf_);
1436 void DisallowedType(Context& context,
const ValueType& actualType)
const {
1437 ErrorHandler& eh = context.error_handler;
1438 eh.StartDisallowedType();
1440 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1441 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1442 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1443 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1444 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1446 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1447 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1449 eh.EndDisallowedType(actualType);
1453 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1454 ~Property() { AllocatorType::Free(dependencies); }
1456 const SchemaType* schema;
1457 const SchemaType* dependenciesSchema;
1458 SizeType dependenciesValidatorIndex;
1463 struct PatternProperty {
1464 PatternProperty() : schema(), pattern() {}
1465 ~PatternProperty() {
1467 pattern->~RegexType();
1468 AllocatorType::Free(pattern);
1471 const SchemaType* schema;
1475 AllocatorType* allocator_;
1477 PointerType pointer_;
1478 const SchemaType* typeless_;
1484 const SchemaType* not_;
1489 Property* properties_;
1490 const SchemaType* additionalPropertiesSchema_;
1491 PatternProperty* patternProperties_;
1496 bool additionalProperties_;
1497 bool hasDependencies_;
1499 bool hasSchemaDependencies_;
1501 const SchemaType* additionalItemsSchema_;
1502 const SchemaType* itemsList_;
1503 const SchemaType** itemsTuple_;
1507 bool additionalItems_;
1510 RegexType* pattern_;
1517 bool exclusiveMinimum_;
1518 bool exclusiveMaximum_;
1523 template<
typename Stack,
typename Ch>
1524 struct TokenHelper {
1525 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(Stack& documentStack,
SizeType index) {
1526 *documentStack.template Push<Ch>() =
'/';
1528 size_t length = static_cast<size_t>((
sizeof(
SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1529 for (
size_t i = 0; i < length; i++)
1530 *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1535 template <
typename Stack>
1536 struct TokenHelper<Stack, char> {
1537 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(Stack& documentStack,
SizeType index) {
1539 char *buffer = documentStack.template Push<char>(1 + 10);
1541 const char* end = internal::u32toa(index, buffer);
1542 documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1545 char *buffer = documentStack.template Push<char>(1 + 20);
1547 const char* end = internal::u64toa(index, buffer);
1548 documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1558 template <
typename SchemaDocumentType>
1559 class IGenericRemoteSchemaDocumentProvider {
1561 typedef typename SchemaDocumentType::Ch Ch;
1563 virtual ~IGenericRemoteSchemaDocumentProvider() {}
1564 virtual const SchemaDocumentType* GetRemoteDocument(
const Ch* uri,
SizeType length) = 0;
1579 template <
typename ValueT,
typename Allocator = CrtAllocator>
1580 class GenericSchemaDocument {
1582 typedef ValueT ValueType;
1583 typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1585 typedef typename ValueType::EncodingType EncodingType;
1586 typedef typename EncodingType::Ch Ch;
1587 typedef internal::Schema<GenericSchemaDocument> SchemaType;
1588 typedef GenericPointer<ValueType, Allocator> PointerType;
1589 typedef GenericValue<EncodingType, Allocator> URIType;
1590 friend class internal::Schema<GenericSchemaDocument>;
1591 template <
typename,
typename,
typename>
1592 friend class GenericSchemaValidator;
1606 remoteProvider_(remoteProvider),
1607 allocator_(allocator),
1611 schemaMap_(allocator, kInitialSchemaMapSize),
1612 schemaRef_(allocator, kInitialSchemaRefSize)
1618 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1620 typeless_ = static_cast<SchemaType*>(allocator_->Malloc(
sizeof(SchemaType)));
1625 CreateSchemaRecursive(&root_,
PointerType(), document, document);
1628 while (!schemaRef_.Empty()) {
1629 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1630 if (
const SchemaType* s = GetSchema(refEntry->target)) {
1631 if (refEntry->schema)
1632 *refEntry->schema = s;
1635 if (!GetSchema(refEntry->source)) {
1636 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s),
false, allocator_);
1639 else if (refEntry->schema)
1640 *refEntry->schema = typeless_;
1642 refEntry->~SchemaRefEntry();
1647 schemaRef_.ShrinkToFit();
1650 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1653 remoteProvider_(rhs.remoteProvider_),
1654 allocator_(rhs.allocator_),
1655 ownAllocator_(rhs.ownAllocator_),
1657 typeless_(rhs.typeless_),
1658 schemaMap_(std::move(rhs.schemaMap_)),
1659 schemaRef_(std::move(rhs.schemaRef_)),
1660 uri_(std::move(rhs.uri_))
1662 rhs.remoteProvider_ = 0;
1664 rhs.ownAllocator_ = 0;
1671 while (!schemaMap_.Empty())
1672 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1675 typeless_->~SchemaType();
1676 Allocator::Free(typeless_);
1682 const URIType& GetURI()
const {
return uri_; }
1685 const SchemaType&
GetRoot()
const {
return *root_; }
1693 struct SchemaRefEntry {
1694 SchemaRefEntry(
const PointerType& s,
const PointerType& t,
const SchemaType** outSchema,
Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1697 const SchemaType** schema;
1700 struct SchemaEntry {
1701 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o,
Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1704 schema->~SchemaType();
1705 Allocator::Free(schema);
1708 PointerType pointer;
1713 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1715 *schema = typeless_;
1718 const SchemaType* s = GetSchema(pointer);
1720 CreateSchema(schema, pointer, v, document);
1722 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1723 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1726 for (
SizeType i = 0; i < v.Size(); i++)
1727 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1730 void CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1733 if (!HandleRefSchema(pointer, schema, v, document)) {
1734 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_);
1735 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s,
true, allocator_);
1742 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document) {
1743 static const Ch kRefString[] = {
'$',
'r',
'e',
'f',
'\0' };
1744 static const ValueType kRefValue(kRefString, 4);
1746 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1747 if (itr == v.MemberEnd())
1750 if (itr->value.IsString()) {
1751 SizeType len = itr->value.GetStringLength();
1753 const Ch* s = itr->value.GetString();
1755 while (i < len && s[i] !=
'#')
1759 if (remoteProvider_) {
1760 if (
const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1761 PointerType pointer(&s[i], len - i, allocator_);
1762 if (pointer.IsValid()) {
1763 if (
const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1766 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc),
false, allocator_);
1773 else if (s[i] ==
'#') {
1774 PointerType pointer(&s[i], len - i, allocator_);
1775 if (pointer.IsValid()) {
1776 if (
const ValueType* nv = pointer.Get(document))
1777 if (HandleRefSchema(source, schema, *nv, document))
1780 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1789 const SchemaType* GetSchema(
const PointerType& pointer)
const {
1790 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1791 if (pointer == target->pointer)
1792 return target->schema;
1796 PointerType GetPointer(
const SchemaType* schema)
const {
1797 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1798 if (schema == target->schema)
1799 return target->pointer;
1800 return PointerType();
1803 const SchemaType* GetTypeless()
const {
return typeless_; }
1805 static const size_t kInitialSchemaMapSize = 64;
1806 static const size_t kInitialSchemaRefSize = 64;
1808 IRemoteSchemaDocumentProviderType* remoteProvider_;
1811 const SchemaType* root_;
1812 SchemaType* typeless_;
1813 internal::Stack<Allocator> schemaMap_;
1814 internal::Stack<Allocator> schemaRef_;
1839 typename SchemaDocumentType,
1840 typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
1841 typename StateAllocator = CrtAllocator>
1842 class GenericSchemaValidator :
1843 public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1844 public internal::ISchemaValidator,
1845 public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
1847 typedef typename SchemaDocumentType::SchemaType SchemaType;
1848 typedef typename SchemaDocumentType::PointerType PointerType;
1849 typedef typename SchemaType::EncodingType EncodingType;
1850 typedef typename SchemaType::SValue SValue;
1851 typedef typename EncodingType::Ch Ch;
1852 typedef GenericStringRef<Ch> StringRefType;
1853 typedef GenericValue<EncodingType, StateAllocator> ValueType;
1863 const SchemaDocumentType& schemaDocument,
1864 StateAllocator* allocator = 0,
1865 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1866 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1868 schemaDocument_(&schemaDocument),
1869 root_(schemaDocument.GetRoot()),
1870 stateAllocator_(allocator),
1871 ownStateAllocator_(0),
1872 schemaStack_(allocator, schemaStackCapacity),
1873 documentStack_(allocator, documentStackCapacity),
1877 missingDependents_(),
1880 #if RAPIDJSON_SCHEMA_VERBOSE
1894 const SchemaDocumentType& schemaDocument,
1895 OutputHandler& outputHandler,
1896 StateAllocator* allocator = 0,
1897 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1898 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1900 schemaDocument_(&schemaDocument),
1901 root_(schemaDocument.GetRoot()),
1902 stateAllocator_(allocator),
1903 ownStateAllocator_(0),
1904 schemaStack_(allocator, schemaStackCapacity),
1905 documentStack_(allocator, documentStackCapacity),
1906 outputHandler_(&outputHandler),
1909 missingDependents_(),
1912 #if RAPIDJSON_SCHEMA_VERBOSE
1926 while (!schemaStack_.Empty())
1928 documentStack_.Clear();
1935 currentError_.SetNull();
1936 missingDependents_.SetNull();
1944 virtual unsigned GetValidateFlags()
const {
1951 if (!valid_)
return false;
1952 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return false;
1958 const ValueType& GetError()
const {
return error_; }
1963 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1969 if (!schemaStack_.Empty())
return CurrentContext().invalidKeyword;
1970 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return (
const Ch*)GetErrorsString();
1977 if (!schemaStack_.Empty())
return CurrentContext().invalidCode;
1978 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return kValidateErrors;
1985 if (documentStack_.Empty()) {
1986 return PointerType();
1989 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
1993 void NotMultipleOf(int64_t actual,
const SValue& expected) {
1996 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
1999 void NotMultipleOf(
double actual,
const SValue& expected) {
2002 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
2004 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2006 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2008 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2010 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
2012 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2014 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
2016 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2018 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2020 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2022 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
2024 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2029 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2033 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2035 void DoesNotMatch(
const Ch* str,
SizeType length) {
2036 currentError_.SetObject();
2037 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2041 void DisallowedItem(
SizeType index) {
2042 currentError_.SetObject();
2043 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2048 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2052 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2056 duplicates.PushBack(index1, GetStateAllocator());
2057 duplicates.PushBack(index2, GetStateAllocator());
2058 currentError_.SetObject();
2059 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2065 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2069 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2071 void StartMissingProperties() {
2072 currentError_.SetArray();
2074 void AddMissingProperty(
const SValue& name) {
2075 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2077 bool EndMissingProperties() {
2078 if (currentError_.Empty())
2081 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2082 currentError_ = error;
2086 void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) {
2087 for (
SizeType i = 0; i < count; ++i)
2088 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2090 void DisallowedProperty(
const Ch* name,
SizeType length) {
2091 currentError_.SetObject();
2092 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2096 void StartDependencyErrors() {
2097 currentError_.SetObject();
2099 void StartMissingDependentProperties() {
2100 missingDependents_.SetArray();
2102 void AddMissingDependentProperty(
const SValue& targetName) {
2103 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2105 void EndMissingDependentProperties(
const SValue& sourceName) {
2106 if (!missingDependents_.Empty()) {
2110 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2111 AddErrorCode(error, code);
2112 AddErrorInstanceLocation(error,
false);
2114 PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(
kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2115 AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2117 wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2118 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2121 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2122 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2123 static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2125 bool EndDependencyErrors() {
2126 if (currentError_.ObjectEmpty())
2129 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2130 currentError_ = error;
2136 currentError_.SetObject();
2137 AddCurrentError(code);
2139 void StartDisallowedType() {
2140 currentError_.SetArray();
2142 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2143 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2145 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2147 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2148 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2149 currentError_ = error;
2152 void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) {
2159 void NoneOf(ISchemaValidator** subvalidators,
SizeType count) {
2162 void NotOneOf(ISchemaValidator** subvalidators,
SizeType count,
bool matched =
false) {
2166 currentError_.SetObject();
2170 #define RAPIDJSON_STRING_(name, ...) \
2171 static const StringRefType& Get##name##String() {\
2172 static const Ch s[] = { __VA_ARGS__, '\0' };\
2173 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2177 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2178 RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2179 RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2180 RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2181 RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2182 RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2183 RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2184 RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2185 RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2186 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2188 #undef RAPIDJSON_STRING_
2190 #if RAPIDJSON_SCHEMA_VERBOSE
2191 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2192 RAPIDJSON_MULTILINEMACRO_BEGIN\
2193 *documentStack_.template Push<Ch>() = '\0';\
2194 documentStack_.template Pop<Ch>(1);\
2195 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2196 RAPIDJSON_MULTILINEMACRO_END
2198 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2201 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2202 if (!valid_) return false; \
2203 if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2204 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2205 return valid_ = false;\
2208 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2209 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2210 if (context->hasher)\
2211 static_cast<HasherType*>(context->hasher)->method arg2;\
2212 if (context->validators)\
2213 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2214 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2215 if (context->patternPropertiesValidators)\
2216 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2217 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2220 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2221 valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2224 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2225 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2226 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2227 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2229 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2230 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2231 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2232 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2233 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2234 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2235 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2236 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
2237 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2238 bool String(
const Ch* str,
SizeType length,
bool copy)
2239 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2241 bool StartObject() {
2242 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2243 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2244 return valid_ = !outputHandler_ || outputHandler_->StartObject();
2247 bool Key(
const Ch* str,
SizeType len,
bool copy) {
2248 if (!valid_)
return false;
2249 AppendToken(str, len);
2250 if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors())
return valid_ =
false;
2251 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2252 return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2255 bool EndObject(
SizeType memberCount) {
2256 if (!valid_)
return false;
2257 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2258 if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors())
return valid_ =
false;
2259 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2263 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2264 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2265 return valid_ = !outputHandler_ || outputHandler_->StartArray();
2268 bool EndArray(
SizeType elementCount) {
2269 if (!valid_)
return false;
2270 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2271 if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors())
return valid_ =
false;
2272 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2275 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2276 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2277 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2278 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2281 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root,
const bool inheritContinueOnErrors) {
2282 ISchemaValidator* sv =
new (GetStateAllocator().Malloc(
sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2283 #if RAPIDJSON_SCHEMA_VERBOSE
2286 &GetStateAllocator());
2287 sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(
unsigned)kValidateContinueOnErrorFlag);
2291 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2292 GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
2293 v->~GenericSchemaValidator();
2294 StateAllocator::Free(v);
2297 virtual void* CreateHasher() {
2298 return new (GetStateAllocator().Malloc(
sizeof(HasherType))) HasherType(&GetStateAllocator());
2301 virtual uint64_t GetHashCode(
void* hasher) {
2302 return static_cast<HasherType*>(hasher)->GetHashCode();
2305 virtual void DestroryHasher(
void* hasher) {
2306 HasherType* h = static_cast<HasherType*>(hasher);
2308 StateAllocator::Free(h);
2311 virtual void* MallocState(
size_t size) {
2312 return GetStateAllocator().Malloc(size);
2315 virtual void FreeState(
void* p) {
2316 StateAllocator::Free(p);
2320 typedef typename SchemaType::Context Context;
2321 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2322 typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2324 GenericSchemaValidator(
2325 const SchemaDocumentType& schemaDocument,
2326 const SchemaType& root,
2327 const char* basePath,
size_t basePathSize,
2328 #
if RAPIDJSON_SCHEMA_VERBOSE
2331 StateAllocator* allocator = 0,
2332 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2333 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2335 schemaDocument_(&schemaDocument),
2337 stateAllocator_(allocator),
2338 ownStateAllocator_(0),
2339 schemaStack_(allocator, schemaStackCapacity),
2340 documentStack_(allocator, documentStackCapacity),
2344 missingDependents_(),
2347 #if RAPIDJSON_SCHEMA_VERBOSE
2351 if (basePath && basePathSize)
2352 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2355 StateAllocator& GetStateAllocator() {
2356 if (!stateAllocator_)
2357 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2358 return *stateAllocator_;
2361 bool GetContinueOnErrors()
const {
2366 if (schemaStack_.Empty())
2369 if (CurrentContext().inArray)
2370 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2372 if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2375 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2376 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2377 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2378 bool valueUniqueness = CurrentContext().valueUniqueness;
2380 PushSchema(*CurrentContext().valueSchema);
2383 CurrentContext().objectPatternValidatorType = patternValidatorType;
2384 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2385 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2386 va = static_cast<ISchemaValidator**>(MallocState(
sizeof(ISchemaValidator*) * count));
2387 for (
SizeType i = 0; i < count; i++)
2388 va[validatorCount++] = CreateSchemaValidator(*sa[i],
true);
2391 CurrentContext().arrayUniqueness = valueUniqueness;
2397 if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
2400 #if RAPIDJSON_SCHEMA_VERBOSE
2401 GenericStringBuffer<EncodingType> sb;
2402 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2404 *documentStack_.template Push<Ch>() =
'\0';
2405 documentStack_.template Pop<Ch>(1);
2406 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2408 void* hasher = CurrentContext().hasher;
2409 uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
2413 if (!schemaStack_.Empty()) {
2414 Context& context = CurrentContext();
2416 if (hasher && context.valueUniqueness) {
2417 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
2419 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
2420 for (
typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
2421 if (itr->GetUint64() == h) {
2422 DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
2424 if (GetContinueOnErrors()) {
2425 a->PushBack(h, GetStateAllocator());
2426 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/');
2430 a->PushBack(h, GetStateAllocator());
2435 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
2441 void AppendToken(
const Ch* str,
SizeType len) {
2442 documentStack_.template Reserve<Ch>(1 + len * 2);
2443 *documentStack_.template PushUnsafe<Ch>() =
'/';
2444 for (
SizeType i = 0; i < len; i++) {
2445 if (str[i] ==
'~') {
2446 *documentStack_.template PushUnsafe<Ch>() =
'~';
2447 *documentStack_.template PushUnsafe<Ch>() =
'0';
2449 else if (str[i] ==
'/') {
2450 *documentStack_.template PushUnsafe<Ch>() =
'~';
2451 *documentStack_.template PushUnsafe<Ch>() =
'1';
2454 *documentStack_.template PushUnsafe<Ch>() = str[i];
2458 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema); }
2460 RAPIDJSON_FORCEINLINE
void PopSchema() {
2461 Context* c = schemaStack_.template Pop<Context>(1);
2462 if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
2463 a->~HashCodeArray();
2464 StateAllocator::Free(a);
2469 void AddErrorInstanceLocation(ValueType& result,
bool parent) {
2470 GenericStringBuffer<EncodingType> sb;
2471 PointerType instancePointer = GetInvalidDocumentPointer();
2472 ((parent && instancePointer.GetTokenCount() > 0)
2473 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2474 : instancePointer).StringifyUriFragment(sb);
2475 ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() /
sizeof(Ch)),
2476 GetStateAllocator());
2477 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2480 void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
2481 GenericStringBuffer<EncodingType> sb;
2482 SizeType len = CurrentSchema().GetURI().GetStringLength();
2483 if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len *
sizeof(Ch));
2484 if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
2485 else GetInvalidSchemaPointer().StringifyUriFragment(sb);
2486 ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() /
sizeof(Ch)),
2487 GetStateAllocator());
2488 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2492 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
2495 void AddError(ValueType& keyword, ValueType& error) {
2496 typename ValueType::MemberIterator member = error_.FindMember(keyword);
2497 if (member == error_.MemberEnd())
2498 error_.AddMember(keyword, error, GetStateAllocator());
2500 if (member->value.IsObject()) {
2502 errors.PushBack(member->value, GetStateAllocator());
2503 member->value = errors;
2505 member->value.PushBack(error, GetStateAllocator());
2510 AddErrorCode(currentError_, code);
2511 AddErrorInstanceLocation(currentError_, parent);
2512 AddErrorSchemaLocation(currentError_);
2513 AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(),
false).Move(), currentError_);
2516 void MergeError(ValueType& other) {
2517 for (
typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
2518 AddError(it->name, it->value);
2522 void AddNumberError(
const ValidateErrorCode code, ValueType& actual,
const SValue& expected,
2523 const typename SchemaType::ValueType& (*exclusive)() = 0) {
2524 currentError_.SetObject();
2525 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2526 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2528 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
2529 AddCurrentError(code);
2533 ISchemaValidator** subvalidators,
SizeType count) {
2535 for (
SizeType i = 0; i < count; ++i)
2536 errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
2537 currentError_.SetObject();
2538 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2539 AddCurrentError(code);
2542 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
2543 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
2544 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
2546 static const size_t kDefaultSchemaStackCapacity = 1024;
2547 static const size_t kDefaultDocumentStackCapacity = 256;
2548 const SchemaDocumentType* schemaDocument_;
2549 const SchemaType& root_;
2550 StateAllocator* stateAllocator_;
2551 StateAllocator* ownStateAllocator_;
2552 internal::Stack<StateAllocator> schemaStack_;
2553 internal::Stack<StateAllocator> documentStack_;
2554 OutputHandler* outputHandler_;
2556 ValueType currentError_;
2557 ValueType missingDependents_;
2560 #if RAPIDJSON_SCHEMA_VERBOSE
2565 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
2581 unsigned parseFlags,
2582 typename InputStream,
2583 typename SourceEncoding,
2585 typename StackAllocator = CrtAllocator>
2588 typedef typename SchemaDocumentType::PointerType PointerType;
2589 typedef typename InputStream::Ch Ch;
2599 template <
typename Handler>
2600 bool operator()(
Handler& handler) {
2603 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2605 isValid_ = validator.IsValid();
2607 invalidSchemaPointer_ = PointerType();
2608 invalidSchemaKeyword_ = 0;
2609 invalidDocumentPointer_ = PointerType();
2613 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
2614 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2615 invalidSchemaCode_ = validator.GetInvalidSchemaCode();
2616 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2617 error_.CopyFrom(validator.GetError(), allocator_);
2620 return parseResult_;
2623 const ParseResult& GetParseResult()
const {
return parseResult_; }
2624 bool IsValid()
const {
return isValid_; }
2625 const PointerType& GetInvalidSchemaPointer()
const {
return invalidSchemaPointer_; }
2626 const Ch* GetInvalidSchemaKeyword()
const {
return invalidSchemaKeyword_; }
2627 const PointerType& GetInvalidDocumentPointer()
const {
return invalidDocumentPointer_; }
2628 const ValueType& GetError()
const {
return error_; }
2633 const SchemaDocumentType& sd_;
2635 ParseResult parseResult_;
2636 PointerType invalidSchemaPointer_;
2637 const Ch* invalidSchemaKeyword_;
2638 PointerType invalidDocumentPointer_;
2640 StackAllocator allocator_;
2645 RAPIDJSON_NAMESPACE_END
2648 #endif // RAPIDJSON_SCHEMA_H_