15#ifndef RAPIDJSON_SCHEMA_H_
16#define RAPIDJSON_SCHEMA_H_
20#include "stringbuffer.h"
23#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
24#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
26#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
29#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
30#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
32#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
35#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
36#include "internal/regex.h"
37#elif RAPIDJSON_SCHEMA_USE_STDREGEX
41#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
42#define RAPIDJSON_SCHEMA_HAS_REGEX 1
44#define RAPIDJSON_SCHEMA_HAS_REGEX 0
47#ifndef RAPIDJSON_SCHEMA_VERBOSE
48#define RAPIDJSON_SCHEMA_VERBOSE 0
51#if RAPIDJSON_SCHEMA_VERBOSE
52#include "stringbuffer.h"
58RAPIDJSON_DIAG_OFF(effc++)
62RAPIDJSON_DIAG_OFF(weak-vtables)
63RAPIDJSON_DIAG_OFF(exit-time-destructors)
64RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
65RAPIDJSON_DIAG_OFF(variadic-macros)
66#elif defined(_MSC_VER)
67RAPIDJSON_DIAG_OFF(4512)
75#if RAPIDJSON_SCHEMA_VERBOSE
79inline void PrintInvalidKeyword(
const char* keyword) {
80 printf(
"Fail keyword: %s\n", keyword);
83inline void PrintInvalidKeyword(
const wchar_t* keyword) {
84 wprintf(L
"Fail keyword: %ls\n", keyword);
87inline void PrintInvalidDocument(
const char* document) {
88 printf(
"Fail document: %s\n\n", document);
91inline void PrintInvalidDocument(
const wchar_t* document) {
92 wprintf(L
"Fail document: %ls\n\n", document);
95inline void PrintValidatorPointers(
unsigned depth,
const char* s,
const char* d) {
96 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
99inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
100 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
110#if RAPIDJSON_SCHEMA_VERBOSE
111#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
113#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
116#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
117RAPIDJSON_MULTILINEMACRO_BEGIN\
118 context.invalidKeyword = keyword.GetString();\
119 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
121RAPIDJSON_MULTILINEMACRO_END
126template <
typename ValueType,
typename Allocator>
131template <
typename SchemaDocumentType>
140 virtual bool IsValid()
const = 0;
146template <
typename SchemaType>
152 virtual void* CreateHasher() = 0;
153 virtual uint64_t GetHashCode(
void* hasher) = 0;
154 virtual void DestroryHasher(
void* hasher) = 0;
155 virtual void* MallocState(
size_t size) = 0;
156 virtual void FreeState(
void* p) = 0;
162template <
typename SchemaType>
165 typedef typename SchemaType::Ch Ch;
166 typedef typename SchemaType::SValue SValue;
170 virtual void NotMultipleOf(int64_t actual,
const SValue& expected) = 0;
171 virtual void NotMultipleOf(uint64_t actual,
const SValue& expected) = 0;
172 virtual void NotMultipleOf(
double actual,
const SValue& expected) = 0;
173 virtual void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
174 virtual void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
175 virtual void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) = 0;
176 virtual void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
177 virtual void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
178 virtual void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) = 0;
180 virtual void TooLong(
const Ch* str,
SizeType length,
SizeType expected) = 0;
181 virtual void TooShort(
const Ch* str,
SizeType length,
SizeType expected) = 0;
182 virtual void DoesNotMatch(
const Ch* str,
SizeType length) = 0;
184 virtual void DisallowedItem(
SizeType index) = 0;
186 virtual void TooManyItems(
SizeType actualCount,
SizeType expectedCount) = 0;
189 virtual void TooManyProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
190 virtual void TooFewProperties(
SizeType actualCount,
SizeType expectedCount) = 0;
191 virtual void StartMissingProperties() = 0;
192 virtual void AddMissingProperty(
const SValue& name) = 0;
193 virtual bool EndMissingProperties() = 0;
195 virtual void DisallowedProperty(
const Ch* name,
SizeType length) = 0;
197 virtual void StartDependencyErrors() = 0;
198 virtual void StartMissingDependentProperties() = 0;
199 virtual void AddMissingDependentProperty(
const SValue& targetName) = 0;
200 virtual void EndMissingDependentProperties(
const SValue& sourceName) = 0;
201 virtual void AddDependencySchemaError(
const SValue& souceName,
ISchemaValidator* subvalidator) = 0;
202 virtual bool EndDependencyErrors() = 0;
204 virtual void DisallowedValue() = 0;
205 virtual void StartDisallowedType() = 0;
206 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
207 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
211 virtual void Disallowed() = 0;
219template<
typename Encoding,
typename Allocator>
222 typedef typename Encoding::Ch Ch;
224 Hasher(
Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
226 bool Null() {
return WriteType(
kNullType); }
228 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
229 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
230 bool Int64(int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
231 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
234 if (d < 0) n.u.i =
static_cast<int64_t
>(d);
235 else n.u.u =
static_cast<uint64_t
>(d);
237 return WriteNumber(n);
240 bool RawNumber(
const Ch* str,
SizeType len,
bool) {
245 bool String(
const Ch* str,
SizeType len,
bool) {
250 bool StartObject() {
return true; }
251 bool Key(
const Ch* str,
SizeType len,
bool copy) {
return String(str, len, copy); }
252 bool EndObject(
SizeType memberCount) {
254 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
255 for (
SizeType i = 0; i < memberCount; i++)
256 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
257 *stack_.template Push<uint64_t>() = h;
261 bool StartArray() {
return true; }
262 bool EndArray(
SizeType elementCount) {
264 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
265 for (
SizeType i = 0; i < elementCount; i++)
267 *stack_.template Push<uint64_t>() = h;
271 bool IsValid()
const {
return stack_.GetSize() ==
sizeof(uint64_t); }
273 uint64_t GetHashCode()
const {
275 return *stack_.template Top<uint64_t>();
279 static const size_t kDefaultSize = 256;
288 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
290 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
292 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
295 const unsigned char* d =
static_cast<const unsigned char*
>(data);
296 for (
size_t i = 0; i < len; i++)
298 *stack_.template Push<uint64_t>() = h;
302 static uint64_t Hash(uint64_t h, uint64_t d) {
309 Stack<Allocator> stack_;
315template <
typename SchemaDocumentType>
320 typedef typename SchemaType::ValueType ValueType;
321 typedef typename ValueType::Ch Ch;
323 enum PatternValidatorType {
324 kPatternValidatorOnly,
325 kPatternValidatorWithProperty,
326 kPatternValidatorWithAdditionalProperty
336 arrayElementHashCodes(),
339 patternPropertiesValidators(),
340 patternPropertiesValidatorCount(),
341 patternPropertiesSchemas(),
342 patternPropertiesSchemaCount(),
343 valuePatternValidatorType(kPatternValidatorOnly),
346 valueUniqueness(
false),
347 arrayUniqueness(
false)
353 factory.DestroryHasher(hasher);
355 for (
SizeType i = 0; i < validatorCount; i++)
356 factory.DestroySchemaValidator(validators[i]);
357 factory.FreeState(validators);
359 if (patternPropertiesValidators) {
360 for (
SizeType i = 0; i < patternPropertiesValidatorCount; i++)
361 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
362 factory.FreeState(patternPropertiesValidators);
364 if (patternPropertiesSchemas)
365 factory.FreeState(patternPropertiesSchemas);
367 factory.FreeState(propertyExist);
374 const Ch* invalidKeyword;
376 void* arrayElementHashCodes;
380 SizeType patternPropertiesValidatorCount;
382 SizeType patternPropertiesSchemaCount;
383 PatternValidatorType valuePatternValidatorType;
384 PatternValidatorType objectPatternValidatorType;
388 bool valueUniqueness;
389 bool arrayUniqueness;
395template <
typename SchemaDocumentType>
398 typedef typename SchemaDocumentType::ValueType ValueType;
399 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
400 typedef typename SchemaDocumentType::PointerType PointerType;
401 typedef typename ValueType::EncodingType EncodingType;
402 typedef typename EncodingType::Ch Ch;
409 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator) :
410 allocator_(allocator),
411 uri_(schemaDocument->GetURI(), *allocator),
412 pointer_(p, allocator),
413 typeless_(schemaDocument->GetTypeless()),
417 type_((1 << kTotalSchemaType) - 1),
419 notValidatorIndex_(),
421 additionalPropertiesSchema_(),
422 patternProperties_(),
423 patternPropertyCount_(),
427 additionalProperties_(
true),
430 hasSchemaDependencies_(),
431 additionalItemsSchema_(),
437 additionalItems_(
true),
442 exclusiveMinimum_(
false),
443 exclusiveMaximum_(
false),
444 defaultValueLength_(0)
446 typedef typename ValueType::ConstValueIterator ConstValueIterator;
447 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
449 if (!value.IsObject())
452 if (
const ValueType* v = GetMember(value, GetTypeString())) {
456 else if (v->IsArray())
457 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
461 if (
const ValueType* v = GetMember(value, GetEnumString()))
462 if (v->IsArray() && v->Size() > 0) {
463 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
464 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
466 char buffer[256u + 24];
468 EnumHasherType h(&hasherAllocator, 256);
470 enum_[enumCount_++] = h.GetHashCode();
474 if (schemaDocument) {
475 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
476 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
477 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
480 if (
const ValueType* v = GetMember(value, GetNotString())) {
481 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
482 notValidatorIndex_ = validatorCount_;
488 const ValueType* properties = GetMember(value, GetPropertiesString());
489 const ValueType* required = GetMember(value, GetRequiredString());
490 const ValueType* dependencies = GetMember(value, GetDependenciesString());
495 if (properties && properties->IsObject())
496 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
497 AddUniqueElement(allProperties, itr->name);
499 if (required && required->IsArray())
500 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
502 AddUniqueElement(allProperties, *itr);
504 if (dependencies && dependencies->IsObject())
505 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
506 AddUniqueElement(allProperties, itr->name);
507 if (itr->value.IsArray())
508 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
510 AddUniqueElement(allProperties, *i);
513 if (allProperties.Size() > 0) {
514 propertyCount_ = allProperties.Size();
515 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
516 for (
SizeType i = 0; i < propertyCount_; i++) {
517 new (&properties_[i]) Property();
518 properties_[i].name = allProperties[i];
519 properties_[i].schema = typeless_;
524 if (properties && properties->IsObject()) {
525 PointerType q = p.Append(GetPropertiesString(), allocator_);
526 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
528 if (FindPropertyIndex(itr->name, &index))
529 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
533 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
534 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
535 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
536 patternPropertyCount_ = 0;
538 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
539 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
540 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
541 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
542 patternPropertyCount_++;
546 if (required && required->IsArray())
547 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
548 if (itr->IsString()) {
550 if (FindPropertyIndex(*itr, &index)) {
551 properties_[index].required =
true;
556 if (dependencies && dependencies->IsObject()) {
557 PointerType q = p.Append(GetDependenciesString(), allocator_);
558 hasDependencies_ =
true;
559 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
561 if (FindPropertyIndex(itr->name, &sourceIndex)) {
562 if (itr->value.IsArray()) {
563 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
564 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
565 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
567 if (FindPropertyIndex(*targetItr, &targetIndex))
568 properties_[sourceIndex].dependencies[targetIndex] =
true;
571 else if (itr->value.IsObject()) {
572 hasSchemaDependencies_ =
true;
573 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
574 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
581 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
583 additionalProperties_ = v->GetBool();
584 else if (v->IsObject())
585 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
588 AssignIfExist(minProperties_, value, GetMinPropertiesString());
589 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
592 if (
const ValueType* v = GetMember(value, GetItemsString())) {
593 PointerType q = p.Append(GetItemsString(), allocator_);
595 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
596 else if (v->IsArray()) {
597 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
599 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
600 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
604 AssignIfExist(minItems_, value, GetMinItemsString());
605 AssignIfExist(maxItems_, value, GetMaxItemsString());
607 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
609 additionalItems_ = v->GetBool();
610 else if (v->IsObject())
611 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
614 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
617 AssignIfExist(minLength_, value, GetMinLengthString());
618 AssignIfExist(maxLength_, value, GetMaxLengthString());
620 if (
const ValueType* v = GetMember(value, GetPatternString()))
621 pattern_ = CreatePattern(*v);
624 if (
const ValueType* v = GetMember(value, GetMinimumString()))
626 minimum_.CopyFrom(*v, *allocator_);
628 if (
const ValueType* v = GetMember(value, GetMaximumString()))
630 maximum_.CopyFrom(*v, *allocator_);
632 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
633 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
635 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
636 if (v->IsNumber() && v->GetDouble() > 0.0)
637 multipleOf_.CopyFrom(*v, *allocator_);
640 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
642 defaultValueLength_ = v->GetStringLength();
647 AllocatorType::Free(enum_);
649 for (
SizeType i = 0; i < propertyCount_; i++)
650 properties_[i].~Property();
651 AllocatorType::Free(properties_);
653 if (patternProperties_) {
654 for (
SizeType i = 0; i < patternPropertyCount_; i++)
655 patternProperties_[i].~PatternProperty();
656 AllocatorType::Free(patternProperties_);
658 AllocatorType::Free(itemsTuple_);
659#if RAPIDJSON_SCHEMA_HAS_REGEX
661 pattern_->~BESRegexType();
662 AllocatorType::Free(pattern_);
667 const SValue& GetURI()
const {
671 const PointerType& GetPointer()
const {
675 bool BeginValue(
Context& context)
const {
676 if (context.inArray) {
678 context.valueUniqueness =
true;
681 context.valueSchema = itemsList_;
682 else if (itemsTuple_) {
683 if (context.arrayElementIndex < itemsTupleCount_)
684 context.valueSchema = itemsTuple_[context.arrayElementIndex];
685 else if (additionalItemsSchema_)
686 context.valueSchema = additionalItemsSchema_;
687 else if (additionalItems_)
688 context.valueSchema = typeless_;
690 context.error_handler.DisallowedItem(context.arrayElementIndex);
691 RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
695 context.valueSchema = typeless_;
697 context.arrayElementIndex++;
702 RAPIDJSON_FORCEINLINE
bool EndValue(
Context& context)
const {
703 if (context.patternPropertiesValidatorCount > 0) {
704 bool otherValid =
false;
705 SizeType count = context.patternPropertiesValidatorCount;
706 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
707 otherValid = context.patternPropertiesValidators[--count]->IsValid();
709 bool patternValid =
true;
710 for (
SizeType i = 0; i < count; i++)
711 if (!context.patternPropertiesValidators[i]->IsValid()) {
712 patternValid =
false;
716 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
718 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
719 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
722 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
723 if (!patternValid || !otherValid) {
724 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
725 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
728 else if (!patternValid && !otherValid) {
729 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
730 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
735 const uint64_t h = context.factory.GetHashCode(context.hasher);
736 for (
SizeType i = 0; i < enumCount_; i++)
739 context.error_handler.DisallowedValue();
740 RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
745 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
746 if (!context.validators[i]->IsValid()) {
747 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
748 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
751 if (anyOf_.schemas) {
752 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
753 if (context.validators[i]->IsValid())
755 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
756 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
760 if (oneOf_.schemas) {
761 bool oneValid =
false;
762 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
763 if (context.validators[i]->IsValid()) {
765 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
766 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
771 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
772 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
776 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777 context.error_handler.Disallowed();
778 RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
784 bool Null(
Context& context)
const {
785 if (!(type_ & (1 << kNullSchemaType))) {
786 DisallowedType(context, GetNullString());
787 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
789 return CreateParallelValidator(context);
792 bool Bool(
Context& context,
bool)
const {
793 if (!(type_ & (1 << kBooleanSchemaType))) {
794 DisallowedType(context, GetBooleanString());
795 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
797 return CreateParallelValidator(context);
800 bool Int(
Context& context,
int i)
const {
801 if (!CheckInt(context, i))
803 return CreateParallelValidator(context);
806 bool Uint(
Context& context,
unsigned u)
const {
807 if (!CheckUint(context, u))
809 return CreateParallelValidator(context);
812 bool Int64(
Context& context, int64_t i)
const {
813 if (!CheckInt(context, i))
815 return CreateParallelValidator(context);
818 bool Uint64(
Context& context, uint64_t u)
const {
819 if (!CheckUint(context, u))
821 return CreateParallelValidator(context);
825 if (!(type_ & (1 << kNumberSchemaType))) {
826 DisallowedType(context, GetNumberString());
827 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
830 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
833 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
836 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
839 return CreateParallelValidator(context);
842 bool String(
Context& context,
const Ch* str,
SizeType length,
bool)
const {
843 if (!(type_ & (1 << kStringSchemaType))) {
844 DisallowedType(context, GetStringString());
845 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
848 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
850 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
851 if (count < minLength_) {
852 context.error_handler.TooShort(str, length, minLength_);
853 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
855 if (count > maxLength_) {
856 context.error_handler.TooLong(str, length, maxLength_);
857 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
862 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863 context.error_handler.DoesNotMatch(str, length);
864 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
867 return CreateParallelValidator(context);
870 bool StartObject(
Context& context)
const {
871 if (!(type_ & (1 << kObjectSchemaType))) {
872 DisallowedType(context, GetObjectString());
873 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
876 if (hasDependencies_ || hasRequired_) {
877 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
878 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
881 if (patternProperties_) {
882 SizeType count = patternPropertyCount_ + 1;
883 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
884 context.patternPropertiesSchemaCount = 0;
885 std::memset(context.patternPropertiesSchemas, 0,
sizeof(
SchemaType*) * count);
888 return CreateParallelValidator(context);
892 if (patternProperties_) {
893 context.patternPropertiesSchemaCount = 0;
894 for (
SizeType i = 0; i < patternPropertyCount_; i++)
895 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
896 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
897 context.valueSchema = typeless_;
902 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
903 if (context.patternPropertiesSchemaCount > 0) {
904 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
905 context.valueSchema = typeless_;
906 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
909 context.valueSchema = properties_[index].schema;
911 if (context.propertyExist)
912 context.propertyExist[index] =
true;
917 if (additionalPropertiesSchema_) {
918 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
919 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
920 context.valueSchema = typeless_;
921 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
924 context.valueSchema = additionalPropertiesSchema_;
927 else if (additionalProperties_) {
928 context.valueSchema = typeless_;
932 if (context.patternPropertiesSchemaCount == 0) {
933 context.error_handler.DisallowedProperty(str, len);
934 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
942 context.error_handler.StartMissingProperties();
943 for (
SizeType index = 0; index < propertyCount_; index++)
944 if (properties_[index].required && !context.propertyExist[index])
945 if (properties_[index].schema->defaultValueLength_ == 0 )
946 context.error_handler.AddMissingProperty(properties_[index].name);
947 if (context.error_handler.EndMissingProperties())
948 RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
951 if (memberCount < minProperties_) {
952 context.error_handler.TooFewProperties(memberCount, minProperties_);
953 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
956 if (memberCount > maxProperties_) {
957 context.error_handler.TooManyProperties(memberCount, maxProperties_);
958 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
961 if (hasDependencies_) {
962 context.error_handler.StartDependencyErrors();
963 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
964 const Property& source = properties_[sourceIndex];
965 if (context.propertyExist[sourceIndex]) {
966 if (source.dependencies) {
967 context.error_handler.StartMissingDependentProperties();
968 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
969 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
970 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
971 context.error_handler.EndMissingDependentProperties(source.name);
973 else if (source.dependenciesSchema) {
974 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
975 if (!dependenciesValidator->IsValid())
976 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
980 if (context.error_handler.EndDependencyErrors())
981 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
987 bool StartArray(
Context& context)
const {
988 if (!(type_ & (1 << kArraySchemaType))) {
989 DisallowedType(context, GetArrayString());
990 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
993 context.arrayElementIndex = 0;
994 context.inArray =
true;
996 return CreateParallelValidator(context);
1000 context.inArray =
false;
1002 if (elementCount < minItems_) {
1003 context.error_handler.TooFewItems(elementCount, minItems_);
1004 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1007 if (elementCount > maxItems_) {
1008 context.error_handler.TooManyItems(elementCount, maxItems_);
1009 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1016#define RAPIDJSON_STRING_(name, ...) \
1017 static const ValueType& Get##name##String() {\
1018 static const Ch s[] = { __VA_ARGS__, '\0' };\
1019 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1023 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1024 RAPIDJSON_STRING_(Boolean,
'b',
'o',
'o',
'l',
'e',
'a',
'n')
1025 RAPIDJSON_STRING_(Object,
'o',
'b',
'j',
'e',
'c',
't')
1026 RAPIDJSON_STRING_(Array,
'a',
'r',
'r',
'a',
'y')
1027 RAPIDJSON_STRING_(String,
's',
't',
'r',
'i',
'n',
'g')
1028 RAPIDJSON_STRING_(Number,
'n',
'u',
'm',
'b',
'e',
'r')
1029 RAPIDJSON_STRING_(Integer,
'i',
'n',
't',
'e',
'g',
'e',
'r')
1030 RAPIDJSON_STRING_(
Type,
't',
'y',
'p',
'e')
1031 RAPIDJSON_STRING_(Enum,
'e',
'n',
'u',
'm')
1032 RAPIDJSON_STRING_(AllOf,
'a',
'l',
'l',
'O',
'f')
1033 RAPIDJSON_STRING_(AnyOf,
'a',
'n',
'y',
'O',
'f')
1034 RAPIDJSON_STRING_(OneOf,
'o',
'n',
'e',
'O',
'f')
1035 RAPIDJSON_STRING_(Not,
'n',
'o',
't')
1036 RAPIDJSON_STRING_(Properties,
'p',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1037 RAPIDJSON_STRING_(Required,
'r',
'e',
'q',
'u',
'i',
'r',
'e',
'd')
1038 RAPIDJSON_STRING_(Dependencies,
'd',
'e',
'p',
'e',
'n',
'd',
'e',
'n',
'c',
'i',
'e',
's')
1039 RAPIDJSON_STRING_(PatternProperties,
'p',
'a',
't',
't',
'e',
'r',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1040 RAPIDJSON_STRING_(AdditionalProperties,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1041 RAPIDJSON_STRING_(MinProperties,
'm',
'i',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1042 RAPIDJSON_STRING_(MaxProperties,
'm',
'a',
'x',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1043 RAPIDJSON_STRING_(Items,
'i',
't',
'e',
'm',
's')
1044 RAPIDJSON_STRING_(MinItems,
'm',
'i',
'n',
'I',
't',
'e',
'm',
's')
1045 RAPIDJSON_STRING_(MaxItems,
'm',
'a',
'x',
'I',
't',
'e',
'm',
's')
1046 RAPIDJSON_STRING_(AdditionalItems,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'I',
't',
'e',
'm',
's')
1047 RAPIDJSON_STRING_(UniqueItems,
'u',
'n',
'i',
'q',
'u',
'e',
'I',
't',
'e',
'm',
's')
1048 RAPIDJSON_STRING_(MinLength,
'm',
'i',
'n',
'L',
'e',
'n',
'g',
't',
'h')
1049 RAPIDJSON_STRING_(MaxLength,
'm',
'a',
'x',
'L',
'e',
'n',
'g',
't',
'h')
1050 RAPIDJSON_STRING_(Pattern,
'p',
'a',
't',
't',
'e',
'r',
'n')
1051 RAPIDJSON_STRING_(Minimum,
'm',
'i',
'n',
'i',
'm',
'u',
'm')
1052 RAPIDJSON_STRING_(Maximum,
'm',
'a',
'x',
'i',
'm',
'u',
'm')
1053 RAPIDJSON_STRING_(ExclusiveMinimum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'i',
'n',
'i',
'm',
'u',
'm')
1054 RAPIDJSON_STRING_(ExclusiveMaximum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'a',
'x',
'i',
'm',
'u',
'm')
1055 RAPIDJSON_STRING_(MultipleOf,
'm',
'u',
'l',
't',
'i',
'p',
'l',
'e',
'O',
'f')
1056 RAPIDJSON_STRING_(DefaultValue,
'd',
'e',
'f',
'a',
'u',
'l',
't')
1058#undef RAPIDJSON_STRING_
1061 enum SchemaValueType {
1072#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1074#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1080 struct SchemaArray {
1081 SchemaArray() : schemas(), count() {}
1082 ~SchemaArray() { AllocatorType::Free(schemas); }
1088 template <
typename V1,
typename V2>
1089 void AddUniqueElement(V1& a,
const V2& v) {
1090 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1093 V1 c(v, *allocator_);
1094 a.PushBack(c, *allocator_);
1097 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1098 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1099 return itr != value.MemberEnd() ? &(itr->value) : 0;
1102 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1103 if (
const ValueType* v = GetMember(value, name))
1108 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
1109 if (
const ValueType* v = GetMember(value, name))
1110 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1111 out =
static_cast<SizeType>(v->GetUint64());
1114 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1115 if (
const ValueType* v = GetMember(value, name)) {
1116 if (v->IsArray() && v->Size() > 0) {
1117 PointerType q = p.Append(name, allocator_);
1118 out.count = v->Size();
1119 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1120 memset(out.schemas, 0,
sizeof(
Schema*)* out.count);
1121 for (
SizeType i = 0; i < out.count; i++)
1122 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1123 out.begin = validatorCount_;
1124 validatorCount_ += out.count;
1129#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1130 template <
typename ValueType>
1132 if (value.IsString()) {
1134 if (!r->IsValid()) {
1136 AllocatorType::Free(r);
1146 return rs.Search(str);
1148#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1149 template <
typename ValueType>
1151 if (value.IsString()) {
1154 return new (r)
BESRegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1156 catch (
const std::regex_error&) {
1157 AllocatorType::Free(r);
1164 std::match_results<const Ch*> r;
1165 return std::regex_search(str, str + length, r, *pattern);
1168 template <
typename ValueType>
1169 BESRegexType* CreatePattern(
const ValueType&) {
return 0; }
1174 void AddType(
const ValueType& type) {
1175 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1176 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1177 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1178 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1179 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1180 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1181 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1184 bool CreateParallelValidator(
Context& context)
const {
1185 if (enum_ || context.arrayUniqueness)
1186 context.hasher = context.factory.CreateHasher();
1188 if (validatorCount_) {
1191 context.validatorCount = validatorCount_;
1194 CreateSchemaValidators(context, allOf_);
1197 CreateSchemaValidators(context, anyOf_);
1200 CreateSchemaValidators(context, oneOf_);
1203 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1205 if (hasSchemaDependencies_) {
1206 for (
SizeType i = 0; i < propertyCount_; i++)
1207 if (properties_[i].dependenciesSchema)
1208 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1215 void CreateSchemaValidators(
Context& context,
const SchemaArray& schemas)
const {
1216 for (
SizeType i = 0; i < schemas.count; i++)
1217 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1221 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1222 SizeType len = name.GetStringLength();
1223 const Ch* str = name.GetString();
1224 for (
SizeType index = 0; index < propertyCount_; index++)
1225 if (properties_[index].name.GetStringLength() == len &&
1226 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1234 bool CheckInt(
Context& context, int64_t i)
const {
1235 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1236 DisallowedType(context, GetIntegerString());
1237 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1240 if (!minimum_.IsNull()) {
1241 if (minimum_.IsInt64()) {
1242 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1243 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1244 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1247 else if (minimum_.IsUint64()) {
1248 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1249 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1251 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1255 if (!maximum_.IsNull()) {
1256 if (maximum_.IsInt64()) {
1257 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1258 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1259 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1262 else if (maximum_.IsUint64()) { }
1264 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1268 if (!multipleOf_.IsNull()) {
1269 if (multipleOf_.IsUint64()) {
1270 if (
static_cast<uint64_t
>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1271 context.error_handler.NotMultipleOf(i, multipleOf_);
1272 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1275 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1282 bool CheckUint(
Context& context, uint64_t i)
const {
1283 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1284 DisallowedType(context, GetIntegerString());
1285 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1288 if (!minimum_.IsNull()) {
1289 if (minimum_.IsUint64()) {
1290 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1291 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1292 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1295 else if (minimum_.IsInt64())
1297 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1301 if (!maximum_.IsNull()) {
1302 if (maximum_.IsUint64()) {
1303 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1304 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1305 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1308 else if (maximum_.IsInt64()) {
1309 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1310 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1312 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1316 if (!multipleOf_.IsNull()) {
1317 if (multipleOf_.IsUint64()) {
1318 if (i % multipleOf_.GetUint64() != 0) {
1319 context.error_handler.NotMultipleOf(i, multipleOf_);
1320 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1323 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1330 bool CheckDoubleMinimum(
Context& context,
double d)
const {
1331 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1332 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1333 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1338 bool CheckDoubleMaximum(
Context& context,
double d)
const {
1339 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1340 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1341 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1346 bool CheckDoubleMultipleOf(
Context& context,
double d)
const {
1347 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1348 double q = std::floor(a / b);
1349 double r = a - q * b;
1351 context.error_handler.NotMultipleOf(d, multipleOf_);
1352 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1357 void DisallowedType(
Context& context,
const ValueType& actualType)
const {
1359 eh.StartDisallowedType();
1361 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1362 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1363 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1364 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1365 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1367 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1368 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1370 eh.EndDisallowedType(actualType);
1374 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1375 ~Property() { AllocatorType::Free(dependencies); }
1379 SizeType dependenciesValidatorIndex;
1384 struct PatternProperty {
1385 PatternProperty() : schema(), pattern() {}
1386 ~PatternProperty() {
1388 pattern->~BESRegexType();
1389 AllocatorType::Free(pattern);
1396 AllocatorType* allocator_;
1398 PointerType pointer_;
1410 Property* properties_;
1411 const SchemaType* additionalPropertiesSchema_;
1412 PatternProperty* patternProperties_;
1417 bool additionalProperties_;
1418 bool hasDependencies_;
1420 bool hasSchemaDependencies_;
1428 bool additionalItems_;
1438 bool exclusiveMinimum_;
1439 bool exclusiveMaximum_;
1444template<
typename Stack,
typename Ch>
1446 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1447 *documentStack.template Push<Ch>() =
'/';
1449 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1450 for (
size_t i = 0; i < length; i++)
1451 *documentStack.template Push<Ch>() =
static_cast<Ch
>(buffer[i]);
1456template <
typename Stack>
1458 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1460 char *buffer = documentStack.template Push<char>(1 + 10);
1462 const char* end = internal::u32toa(index, buffer);
1463 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1466 char *buffer = documentStack.template Push<char>(1 + 20);
1468 const char* end = internal::u64toa(index, buffer);
1469 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1479template <
typename SchemaDocumentType>
1482 typedef typename SchemaDocumentType::Ch Ch;
1485 virtual const SchemaDocumentType* GetRemoteDocument(
const Ch* uri,
SizeType length) = 0;
1500template <
typename ValueT,
typename Allocator = CrtAllocator>
1503 typedef ValueT ValueType;
1506 typedef typename ValueType::EncodingType EncodingType;
1507 typedef typename EncodingType::Ch Ch;
1512 template <
typename,
typename,
typename>
1527 remoteProvider_(remoteProvider),
1528 allocator_(allocator),
1532 schemaMap_(allocator, kInitialSchemaMapSize),
1533 schemaRef_(allocator, kInitialSchemaRefSize)
1539 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1546 CreateSchemaRecursive(&root_,
PointerType(), document, document);
1549 while (!schemaRef_.Empty()) {
1550 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1551 if (
const SchemaType* s = GetSchema(refEntry->target)) {
1552 if (refEntry->schema)
1553 *refEntry->schema = s;
1556 if (!GetSchema(refEntry->source)) {
1557 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source,
const_cast<SchemaType*
>(s),
false, allocator_);
1560 else if (refEntry->schema)
1561 *refEntry->schema = typeless_;
1563 refEntry->~SchemaRefEntry();
1568 schemaRef_.ShrinkToFit();
1571#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1574 remoteProvider_(rhs.remoteProvider_),
1575 allocator_(rhs.allocator_),
1576 ownAllocator_(rhs.ownAllocator_),
1578 typeless_(rhs.typeless_),
1579 schemaMap_(std::move(rhs.schemaMap_)),
1580 schemaRef_(std::move(rhs.schemaRef_)),
1581 uri_(std::move(rhs.uri_))
1583 rhs.remoteProvider_ = 0;
1585 rhs.ownAllocator_ = 0;
1592 while (!schemaMap_.Empty())
1593 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1596 typeless_->~SchemaType();
1597 Allocator::Free(typeless_);
1603 const URIType& GetURI()
const {
return uri_; }
1614 struct SchemaRefEntry {
1615 SchemaRefEntry(
const PointerType& s,
const PointerType& t,
const SchemaType** outSchema,
Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1618 const SchemaType** schema;
1621 struct SchemaEntry {
1622 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o,
Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1625 schema->~SchemaType();
1626 Allocator::Free(schema);
1629 PointerType pointer;
1634 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1636 *schema = typeless_;
1639 const SchemaType* s = GetSchema(pointer);
1641 CreateSchema(schema, pointer, v, document);
1643 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1644 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1647 for (
SizeType i = 0; i < v.Size(); i++)
1648 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1651 void CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1654 if (!HandleRefSchema(pointer, schema, v, document)) {
1655 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_);
1656 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s,
true, allocator_);
1663 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document) {
1664 static const Ch kRefString[] = {
'$',
'r',
'e',
'f',
'\0' };
1665 static const ValueType kRefValue(kRefString, 4);
1667 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1668 if (itr == v.MemberEnd())
1671 if (itr->value.IsString()) {
1672 SizeType len = itr->value.GetStringLength();
1674 const Ch* s = itr->value.GetString();
1676 while (i < len && s[i] !=
'#')
1680 if (remoteProvider_) {
1682 PointerType pointer(&s[i], len - i, allocator_);
1683 if (pointer.IsValid()) {
1684 if (
const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1687 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source,
const_cast<SchemaType*
>(sc),
false, allocator_);
1694 else if (s[i] ==
'#') {
1695 PointerType pointer(&s[i], len - i, allocator_);
1696 if (pointer.IsValid()) {
1697 if (
const ValueType* nv = pointer.Get(document))
1698 if (HandleRefSchema(source, schema, *nv, document))
1701 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1710 const SchemaType* GetSchema(
const PointerType& pointer)
const {
1711 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1712 if (pointer == target->pointer)
1713 return target->schema;
1717 PointerType GetPointer(
const SchemaType* schema)
const {
1718 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1719 if (schema == target->schema)
1720 return target->pointer;
1721 return PointerType();
1724 const SchemaType* GetTypeless()
const {
return typeless_; }
1726 static const size_t kInitialSchemaMapSize = 64;
1727 static const size_t kInitialSchemaRefSize = 64;
1729 IRemoteSchemaDocumentProviderType* remoteProvider_;
1732 const SchemaType* root_;
1733 SchemaType* typeless_;
1760 typename SchemaDocumentType,
1769 typedef typename SchemaDocumentType::SchemaType SchemaType;
1770 typedef typename SchemaDocumentType::PointerType PointerType;
1771 typedef typename SchemaType::EncodingType EncodingType;
1772 typedef typename SchemaType::SValue SValue;
1773 typedef typename EncodingType::Ch Ch;
1785 const SchemaDocumentType& schemaDocument,
1786 StateAllocator* allocator = 0,
1787 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1788 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1790 schemaDocument_(&schemaDocument),
1791 root_(schemaDocument.GetRoot()),
1792 stateAllocator_(allocator),
1793 ownStateAllocator_(0),
1794 schemaStack_(allocator, schemaStackCapacity),
1795 documentStack_(allocator, documentStackCapacity),
1799 missingDependents_(),
1801#if RAPIDJSON_SCHEMA_VERBOSE
1815 const SchemaDocumentType& schemaDocument,
1816 OutputHandler& outputHandler,
1817 StateAllocator* allocator = 0,
1818 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1819 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1821 schemaDocument_(&schemaDocument),
1822 root_(schemaDocument.GetRoot()),
1823 stateAllocator_(allocator),
1824 ownStateAllocator_(0),
1825 schemaStack_(allocator, schemaStackCapacity),
1826 documentStack_(allocator, documentStackCapacity),
1827 outputHandler_(&outputHandler),
1830 missingDependents_(),
1832#if RAPIDJSON_SCHEMA_VERBOSE
1846 while (!schemaStack_.Empty())
1848 documentStack_.Clear();
1850 currentError_.SetNull();
1851 missingDependents_.SetNull();
1861 const ValueType&
GetError()
const {
return error_; }
1865 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1870 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1875 if (documentStack_.Empty()) {
1876 return PointerType();
1879 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
1883 void NotMultipleOf(int64_t actual,
const SValue& expected) {
1884 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1886 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
1887 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1889 void NotMultipleOf(
double actual,
const SValue& expected) {
1890 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1892 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
1893 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1894 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1896 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
1897 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1898 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1900 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
1901 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1902 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1904 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
1905 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1906 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1908 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
1909 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1910 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1912 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
1913 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1914 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1918 AddNumberError(SchemaType::GetMaxLengthString(),
1919 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1922 AddNumberError(SchemaType::GetMinLengthString(),
1923 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1925 void DoesNotMatch(
const Ch* str,
SizeType length) {
1926 currentError_.SetObject();
1927 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
1928 AddCurrentError(SchemaType::GetPatternString());
1931 void DisallowedItem(
SizeType index) {
1932 currentError_.SetObject();
1933 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
1934 AddCurrentError(SchemaType::GetAdditionalItemsString(),
true);
1937 AddNumberError(SchemaType::GetMinItemsString(),
1938 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1941 AddNumberError(SchemaType::GetMaxItemsString(),
1942 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1946 duplicates.PushBack(index1, GetStateAllocator());
1947 duplicates.PushBack(index2, GetStateAllocator());
1948 currentError_.SetObject();
1949 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1950 AddCurrentError(SchemaType::GetUniqueItemsString(),
true);
1954 AddNumberError(SchemaType::GetMaxPropertiesString(),
1955 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1958 AddNumberError(SchemaType::GetMinPropertiesString(),
1959 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1961 void StartMissingProperties() {
1962 currentError_.SetArray();
1964 void AddMissingProperty(
const SValue& name) {
1965 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1967 bool EndMissingProperties() {
1968 if (currentError_.Empty())
1971 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1972 currentError_ = error;
1973 AddCurrentError(SchemaType::GetRequiredString());
1976 void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) {
1977 for (
SizeType i = 0; i < count; ++i)
1980 void DisallowedProperty(
const Ch* name,
SizeType length) {
1981 currentError_.SetObject();
1982 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
1983 AddCurrentError(SchemaType::GetAdditionalPropertiesString(),
true);
1986 void StartDependencyErrors() {
1987 currentError_.SetObject();
1989 void StartMissingDependentProperties() {
1990 missingDependents_.SetArray();
1992 void AddMissingDependentProperty(
const SValue& targetName) {
1993 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1995 void EndMissingDependentProperties(
const SValue& sourceName) {
1996 if (!missingDependents_.Empty())
1997 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
1998 missingDependents_, GetStateAllocator());
2000 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2001 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2004 bool EndDependencyErrors() {
2005 if (currentError_.ObjectEmpty())
2008 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2009 currentError_ = error;
2010 AddCurrentError(SchemaType::GetDependenciesString());
2014 void DisallowedValue() {
2015 currentError_.SetObject();
2016 AddCurrentError(SchemaType::GetEnumString());
2018 void StartDisallowedType() {
2019 currentError_.SetArray();
2021 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2022 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2024 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2026 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2027 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2028 currentError_ = error;
2029 AddCurrentError(SchemaType::GetTypeString());
2031 void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) {
2032 for (
SizeType i = 0; i < count; ++i) {
2036 void NoneOf(ISchemaValidator** subvalidators,
SizeType count) {
2037 AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
2039 void NotOneOf(ISchemaValidator** subvalidators,
SizeType count) {
2040 AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
2043 currentError_.SetObject();
2044 AddCurrentError(SchemaType::GetNotString());
2047#define RAPIDJSON_STRING_(name, ...) \
2048 static const StringRefType& Get##name##String() {\
2049 static const Ch s[] = { __VA_ARGS__, '\0' };\
2050 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2054 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2055 RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2056 RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2057 RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2058 RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2059 RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2060 RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2061 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2063#undef RAPIDJSON_STRING_
2065#if RAPIDJSON_SCHEMA_VERBOSE
2066#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2067RAPIDJSON_MULTILINEMACRO_BEGIN\
2068 *documentStack_.template Push<Ch>() = '\0';\
2069 documentStack_.template Pop<Ch>(1);\
2070 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2071RAPIDJSON_MULTILINEMACRO_END
2073#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2076#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2077 if (!valid_) return false; \
2078 if (!BeginValue() || !CurrentSchema().method arg1) {\
2079 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2080 return valid_ = false;\
2083#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2084 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2085 if (context->hasher)\
2086 static_cast<HasherType*>(context->hasher)->method arg2;\
2087 if (context->validators)\
2088 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2089 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2090 if (context->patternPropertiesValidators)\
2091 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2092 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2095#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2096 return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
2098#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2099 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2100 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2101 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2103 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2104 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2105 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2106 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2107 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2108 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2109 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2110 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
2111 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2112 bool String(
const Ch* str,
SizeType length,
bool copy)
2113 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2115 bool StartObject() {
2116 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2117 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2118 return valid_ = !outputHandler_ || outputHandler_->StartObject();
2121 bool Key(
const Ch* str,
SizeType len,
bool copy) {
2122 if (!valid_)
return false;
2123 AppendToken(str, len);
2124 if (!CurrentSchema().Key(CurrentContext(), str, len, copy))
return valid_ =
false;
2125 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2126 return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2129 bool EndObject(
SizeType memberCount) {
2130 if (!valid_)
return false;
2131 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2132 if (!CurrentSchema().EndObject(CurrentContext(), memberCount))
return valid_ =
false;
2133 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2137 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2138 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2139 return valid_ = !outputHandler_ || outputHandler_->StartArray();
2142 bool EndArray(
SizeType elementCount) {
2143 if (!valid_)
return false;
2144 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2145 if (!CurrentSchema().EndArray(CurrentContext(), elementCount))
return valid_ =
false;
2146 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2149#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2150#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2151#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2152#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2155 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root) {
2157#if RAPIDJSON_SCHEMA_VERBOSE
2160 &GetStateAllocator());
2163 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2166 StateAllocator::Free(v);
2169 virtual void* CreateHasher() {
2170 return new (GetStateAllocator().Malloc(
sizeof(HasherType))) HasherType(&GetStateAllocator());
2173 virtual uint64_t GetHashCode(
void* hasher) {
2174 return static_cast<HasherType*
>(hasher)->GetHashCode();
2177 virtual void DestroryHasher(
void* hasher) {
2178 HasherType* h =
static_cast<HasherType*
>(hasher);
2180 StateAllocator::Free(h);
2183 virtual void* MallocState(
size_t size) {
2184 return GetStateAllocator().Malloc(size);
2187 virtual void FreeState(
void* p) {
2188 StateAllocator::Free(p);
2192 typedef typename SchemaType::Context Context;
2197 const SchemaDocumentType& schemaDocument,
2198 const SchemaType& root,
2199 const char* basePath,
size_t basePathSize,
2200#
if RAPIDJSON_SCHEMA_VERBOSE
2203 StateAllocator* allocator = 0,
2204 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2205 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2207 schemaDocument_(&schemaDocument),
2209 stateAllocator_(allocator),
2210 ownStateAllocator_(0),
2211 schemaStack_(allocator, schemaStackCapacity),
2212 documentStack_(allocator, documentStackCapacity),
2216 missingDependents_(),
2218#if RAPIDJSON_SCHEMA_VERBOSE
2222 if (basePath && basePathSize)
2223 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2226 StateAllocator& GetStateAllocator() {
2227 if (!stateAllocator_)
2228 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2229 return *stateAllocator_;
2233 if (schemaStack_.Empty())
2236 if (CurrentContext().inArray)
2239 if (!CurrentSchema().BeginValue(CurrentContext()))
2242 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2243 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2244 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2245 bool valueUniqueness = CurrentContext().valueUniqueness;
2247 PushSchema(*CurrentContext().valueSchema);
2250 CurrentContext().objectPatternValidatorType = patternValidatorType;
2251 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2252 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2253 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
2254 for (
SizeType i = 0; i < count; i++)
2255 va[validatorCount++] = CreateSchemaValidator(*sa[i]);
2258 CurrentContext().arrayUniqueness = valueUniqueness;
2264 if (!CurrentSchema().EndValue(CurrentContext()))
2267#if RAPIDJSON_SCHEMA_VERBOSE
2269 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2271 *documentStack_.template Push<Ch>() =
'\0';
2272 documentStack_.template Pop<Ch>(1);
2273 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2276 uint64_t h = CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(CurrentContext().hasher)->GetHashCode() : 0;
2280 if (!schemaStack_.Empty()) {
2281 Context& context = CurrentContext();
2282 if (context.valueUniqueness) {
2283 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
2285 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
2287 if (itr->GetUint64() == h) {
2288 DuplicateItems(
static_cast<SizeType>(itr - a->Begin()), a->Size());
2289 RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
2291 a->PushBack(h, GetStateAllocator());
2296 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
2302 void AppendToken(
const Ch* str,
SizeType len) {
2303 documentStack_.template Reserve<Ch>(1 + len * 2);
2304 *documentStack_.template PushUnsafe<Ch>() =
'/';
2305 for (
SizeType i = 0; i < len; i++) {
2306 if (str[i] ==
'~') {
2307 *documentStack_.template PushUnsafe<Ch>() =
'~';
2308 *documentStack_.template PushUnsafe<Ch>() =
'0';
2310 else if (str[i] ==
'/') {
2311 *documentStack_.template PushUnsafe<Ch>() =
'~';
2312 *documentStack_.template PushUnsafe<Ch>() =
'1';
2315 *documentStack_.template PushUnsafe<Ch>() = str[i];
2319 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema); }
2321 RAPIDJSON_FORCEINLINE
void PopSchema() {
2322 Context* c = schemaStack_.template Pop<Context>(1);
2323 if (HashCodeArray* a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
2324 a->~HashCodeArray();
2325 StateAllocator::Free(a);
2330 void AddErrorLocation(ValueType& result,
bool parent) {
2333 ((parent && instancePointer.GetTokenCount() > 0)
2334 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2335 : instancePointer).StringifyUriFragment(sb);
2336 ValueType instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
2337 GetStateAllocator());
2338 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2340 memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
2341 CurrentSchema().GetURI().GetString(),
2342 CurrentSchema().GetURI().GetStringLength() *
sizeof(Ch));
2344 ValueType schemaRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
2345 GetStateAllocator());
2346 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2349 void AddError(ValueType& keyword, ValueType& error) {
2351 if (member == error_.MemberEnd())
2352 error_.AddMember(keyword, error, GetStateAllocator());
2354 if (member->value.IsObject()) {
2356 errors.PushBack(member->value, GetStateAllocator());
2357 member->value = errors;
2359 member->value.PushBack(error, GetStateAllocator());
2363 void AddCurrentError(
const typename SchemaType::ValueType& keyword,
bool parent =
false) {
2364 AddErrorLocation(currentError_, parent);
2365 AddError(ValueType(keyword, GetStateAllocator(),
false).Move(), currentError_);
2368 void MergeError(ValueType& other) {
2370 AddError(it->name, it->value);
2374 void AddNumberError(
const typename SchemaType::ValueType& keyword, ValueType& actual,
const SValue& expected,
2375 const typename SchemaType::ValueType& (*exclusive)() = 0) {
2376 currentError_.SetObject();
2377 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2378 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2380 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
2381 AddCurrentError(keyword);
2384 void AddErrorArray(
const typename SchemaType::ValueType& keyword,
2385 ISchemaValidator** subvalidators,
SizeType count) {
2387 for (
SizeType i = 0; i < count; ++i)
2389 currentError_.SetObject();
2390 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2391 AddCurrentError(keyword);
2394 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
2395 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
2396 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
2398 static const size_t kDefaultSchemaStackCapacity = 1024;
2399 static const size_t kDefaultDocumentStackCapacity = 256;
2400 const SchemaDocumentType* schemaDocument_;
2401 const SchemaType& root_;
2402 StateAllocator* stateAllocator_;
2403 StateAllocator* ownStateAllocator_;
2406 OutputHandler* outputHandler_;
2408 ValueType currentError_;
2409 ValueType missingDependents_;
2411#if RAPIDJSON_SCHEMA_VERBOSE
2432 unsigned parseFlags,
2433 typename InputStream,
2434 typename SourceEncoding,
2439 typedef typename SchemaDocumentType::PointerType PointerType;
2440 typedef typename InputStream::Ch Ch;
2450 template <
typename Handler>
2451 bool operator()(
Handler& handler) {
2454 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2456 isValid_ = validator.IsValid();
2458 invalidSchemaPointer_ = PointerType();
2459 invalidSchemaKeyword_ = 0;
2460 invalidDocumentPointer_ = PointerType();
2464 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
2465 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2466 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2467 error_.CopyFrom(validator.GetError(), allocator_);
2470 return parseResult_;
2473 const ParseResult& GetParseResult()
const {
return parseResult_; }
2474 bool IsValid()
const {
return isValid_; }
2475 const PointerType& GetInvalidSchemaPointer()
const {
return invalidSchemaPointer_; }
2476 const Ch* GetInvalidSchemaKeyword()
const {
return invalidSchemaKeyword_; }
2477 const PointerType& GetInvalidDocumentPointer()
const {
return invalidDocumentPointer_; }
2478 const ValueType& GetError()
const {
return error_; }
2482 const SchemaDocumentType& sd_;
2485 PointerType invalidSchemaPointer_;
2486 const Ch* invalidSchemaKeyword_;
2487 PointerType invalidDocumentPointer_;
2488 StackAllocator allocator_;
C-runtime library allocator.
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
const SchemaType & GetRoot() const
Get the root schema.
~GenericSchemaDocument()
Destructor.
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
ValueType & GetError()
Gets the error object.
~GenericSchemaValidator()
Destructor.
void Reset()
Reset the internal states.
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
virtual bool IsValid() const
Checks whether the current state is valid.
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Represents an in-memory output stream.
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
GenericMemberIterator< false, Encoding, Allocator >::Iterator MemberIterator
Member iterator for iterating in object.
const GenericValue * ConstValueIterator
Constant value iterator for iterating in array.
Default memory allocator used by the parser and DOM.
A helper class for parsing with validation.
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Regular expression engine with subset of ECMAscript grammar.
A type-unsafe stack for storing different types of data.
Concept for allocating, resizing and freeing memory block.
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
#define RAPIDJSON_ASSERT(x)
Assertion.
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
#define RAPIDJSON_DELETE(x)
! customization point for global delete
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Default implementation of Handler.
Reference to a constant string (not taking a copy)
Result of parsing (wraps ParseErrorCode)