1 // Tencent is pleased to support the open source community by making RapidJSON available->
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License-> You may obtain a copy of the License at
7 //
8 // http://opensource->org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the
13 // specific language governing permissions and limitations under the License->
14 
15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
17 
18 #include "document.h"
19 #include "pointer.h"
20 #include "stringbuffer.h"
21 #include <cmath> // abs, floor
22 
23 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
24 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
25 #else
26 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
27 #endif
28 
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
31 #else
32 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
33 #endif
34 
35 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
36 #include "internal/regex.h"
37 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
38 #include <regex>
39 #endif
40 
41 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
42 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
43 #else
44 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
45 #endif
46 
47 #ifndef RAPIDJSON_SCHEMA_VERBOSE
48 #define RAPIDJSON_SCHEMA_VERBOSE 0
49 #endif
50 
51 #if RAPIDJSON_SCHEMA_VERBOSE
52 #include "stringbuffer.h"
53 #endif
54 
55 RAPIDJSON_DIAG_PUSH
56 
57 #if defined(__GNUC__)
58 RAPIDJSON_DIAG_OFF(effc++)
59 #endif
60 
61 #ifdef __clang__
62 RAPIDJSON_DIAG_OFF(weak-vtables)
63 RAPIDJSON_DIAG_OFF(exit-time-destructors)
64 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
65 RAPIDJSON_DIAG_OFF(variadic-macros)
66 #elif defined(_MSC_VER)
67 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
68 #endif
69 
70 RAPIDJSON_NAMESPACE_BEGIN
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 // Verbose Utilities
74 
75 #if RAPIDJSON_SCHEMA_VERBOSE
76 
77 namespace internal {
78 
PrintInvalidKeyword(const char * keyword)79 inline void PrintInvalidKeyword(const char* keyword) {
80     printf("Fail keyword: %s\n", keyword);
81 }
82 
PrintInvalidKeyword(const wchar_t * keyword)83 inline void PrintInvalidKeyword(const wchar_t* keyword) {
84     wprintf(L"Fail keyword: %ls\n", keyword);
85 }
86 
PrintInvalidDocument(const char * document)87 inline void PrintInvalidDocument(const char* document) {
88     printf("Fail document: %s\n\n", document);
89 }
90 
PrintInvalidDocument(const wchar_t * document)91 inline void PrintInvalidDocument(const wchar_t* document) {
92     wprintf(L"Fail document: %ls\n\n", document);
93 }
94 
PrintValidatorPointers(unsigned depth,const char * s,const char * d)95 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
96     printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
97 }
98 
PrintValidatorPointers(unsigned depth,const wchar_t * s,const wchar_t * d)99 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
100     wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
101 }
102 
103 } // namespace internal
104 
105 #endif // RAPIDJSON_SCHEMA_VERBOSE
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 // RAPIDJSON_INVALID_KEYWORD_RETURN
109 
110 #if RAPIDJSON_SCHEMA_VERBOSE
111 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
112 #else
113 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
114 #endif
115 
116 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
117 RAPIDJSON_MULTILINEMACRO_BEGIN\
118     context.invalidKeyword = keyword.GetString();\
119     RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
120     return false;\
121 RAPIDJSON_MULTILINEMACRO_END
122 
123 ///////////////////////////////////////////////////////////////////////////////
124 // Forward declarations
125 
126 template <typename ValueType, typename Allocator>
127 class GenericSchemaDocument;
128 
129 namespace internal {
130 
131 template <typename SchemaDocumentType>
132 class Schema;
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 // ISchemaValidator
136 
137 class ISchemaValidator {
138 public:
~ISchemaValidator()139     virtual ~ISchemaValidator() {}
140     virtual bool IsValid() const = 0;
141 };
142 
143 ///////////////////////////////////////////////////////////////////////////////
144 // ISchemaStateFactory
145 
146 template <typename SchemaType>
147 class ISchemaStateFactory {
148 public:
~ISchemaStateFactory()149     virtual ~ISchemaStateFactory() {}
150     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
151     virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
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;
157 };
158 
159 ///////////////////////////////////////////////////////////////////////////////
160 // IValidationErrorHandler
161 
162 template <typename SchemaType>
163 class IValidationErrorHandler {
164 public:
165     typedef typename SchemaType::Ch Ch;
166     typedef typename SchemaType::SValue SValue;
167 
~IValidationErrorHandler()168     virtual ~IValidationErrorHandler() {}
169 
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;
179 
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;
183 
184     virtual void DisallowedItem(SizeType index) = 0;
185     virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
186     virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
187     virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
188 
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;
194     virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
195     virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
196 
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;
203 
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;
208     virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
209     virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
210     virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
211     virtual void Disallowed() = 0;
212 };
213 
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 // Hasher
217 
218 // For comparison of compound value
219 template<typename Encoding, typename Allocator>
220 class Hasher {
221 public:
222     typedef typename Encoding::Ch Ch;
223 
stack_(allocator,stackCapacity)224     Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
225 
Null()226     bool Null() { return WriteType(kNullType); }
Bool(bool b)227     bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
Int(int i)228     bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
Uint(unsigned u)229     bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
Int64(int64_t i)230     bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
Uint64(uint64_t u)231     bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
Double(double d)232     bool Double(double d) {
233         Number n;
234         if (d < 0) n.u.i = static_cast<int64_t>(d);
235         else       n.u.u = static_cast<uint64_t>(d);
236         n.d = d;
237         return WriteNumber(n);
238     }
239 
RawNumber(const Ch * str,SizeType len,bool)240     bool RawNumber(const Ch* str, SizeType len, bool) {
241         WriteBuffer(kNumberType, str, len * sizeof(Ch));
242         return true;
243     }
244 
String(const Ch * str,SizeType len,bool)245     bool String(const Ch* str, SizeType len, bool) {
246         WriteBuffer(kStringType, str, len * sizeof(Ch));
247         return true;
248     }
249 
StartObject()250     bool StartObject() { return true; }
Key(const Ch * str,SizeType len,bool copy)251     bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
EndObject(SizeType memberCount)252     bool EndObject(SizeType memberCount) {
253         uint64_t h = Hash(0, kObjectType);
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]);  // Use xor to achieve member order insensitive
257         *stack_.template Push<uint64_t>() = h;
258         return true;
259     }
260 
StartArray()261     bool StartArray() { return true; }
EndArray(SizeType elementCount)262     bool EndArray(SizeType elementCount) {
263         uint64_t h = Hash(0, kArrayType);
264         uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
265         for (SizeType i = 0; i < elementCount; i++)
266             h = Hash(h, e[i]); // Use hash to achieve element order sensitive
267         *stack_.template Push<uint64_t>() = h;
268         return true;
269     }
270 
IsValid()271     bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
272 
GetHashCode()273     uint64_t GetHashCode() const {
274         RAPIDJSON_ASSERT(IsValid());
275         return *stack_.template Top<uint64_t>();
276     }
277 
278 private:
279     static const size_t kDefaultSize = 256;
280     struct Number {
281         union U {
282             uint64_t u;
283             int64_t i;
284         }u;
285         double d;
286     };
287 
WriteType(Type type)288     bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
289 
WriteNumber(const Number & n)290     bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
291 
WriteBuffer(Type type,const void * data,size_t len)292     bool WriteBuffer(Type type, const void* data, size_t len) {
293         // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
294         uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
295         const unsigned char* d = static_cast<const unsigned char*>(data);
296         for (size_t i = 0; i < len; i++)
297             h = Hash(h, d[i]);
298         *stack_.template Push<uint64_t>() = h;
299         return true;
300     }
301 
Hash(uint64_t h,uint64_t d)302     static uint64_t Hash(uint64_t h, uint64_t d) {
303         static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
304         h ^= d;
305         h *= kPrime;
306         return h;
307     }
308 
309     Stack<Allocator> stack_;
310 };
311 
312 ///////////////////////////////////////////////////////////////////////////////
313 // SchemaValidationContext
314 
315 template <typename SchemaDocumentType>
316 struct SchemaValidationContext {
317     typedef Schema<SchemaDocumentType> SchemaType;
318     typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
319     typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
320     typedef typename SchemaType::ValueType ValueType;
321     typedef typename ValueType::Ch Ch;
322 
323     enum PatternValidatorType {
324         kPatternValidatorOnly,
325         kPatternValidatorWithProperty,
326         kPatternValidatorWithAdditionalProperty
327     };
328 
SchemaValidationContextSchemaValidationContext329     SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :
330         factory(f),
331         error_handler(eh),
332         schema(s),
333         valueSchema(),
334         invalidKeyword(),
335         hasher(),
336         arrayElementHashCodes(),
337         validators(),
338         validatorCount(),
339         patternPropertiesValidators(),
340         patternPropertiesValidatorCount(),
341         patternPropertiesSchemas(),
342         patternPropertiesSchemaCount(),
343         valuePatternValidatorType(kPatternValidatorOnly),
344         propertyExist(),
345         inArray(false),
346         valueUniqueness(false),
347         arrayUniqueness(false)
348     {
349     }
350 
~SchemaValidationContextSchemaValidationContext351     ~SchemaValidationContext() {
352         if (hasher)
353             factory.DestroryHasher(hasher);
354         if (validators) {
355             for (SizeType i = 0; i < validatorCount; i++)
356                 factory.DestroySchemaValidator(validators[i]);
357             factory.FreeState(validators);
358         }
359         if (patternPropertiesValidators) {
360             for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
361                 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
362             factory.FreeState(patternPropertiesValidators);
363         }
364         if (patternPropertiesSchemas)
365             factory.FreeState(patternPropertiesSchemas);
366         if (propertyExist)
367             factory.FreeState(propertyExist);
368     }
369 
370     SchemaValidatorFactoryType& factory;
371     ErrorHandlerType& error_handler;
372     const SchemaType* schema;
373     const SchemaType* valueSchema;
374     const Ch* invalidKeyword;
375     void* hasher; // Only validator access
376     void* arrayElementHashCodes; // Only validator access this
377     ISchemaValidator** validators;
378     SizeType validatorCount;
379     ISchemaValidator** patternPropertiesValidators;
380     SizeType patternPropertiesValidatorCount;
381     const SchemaType** patternPropertiesSchemas;
382     SizeType patternPropertiesSchemaCount;
383     PatternValidatorType valuePatternValidatorType;
384     PatternValidatorType objectPatternValidatorType;
385     SizeType arrayElementIndex;
386     bool* propertyExist;
387     bool inArray;
388     bool valueUniqueness;
389     bool arrayUniqueness;
390 };
391 
392 ///////////////////////////////////////////////////////////////////////////////
393 // Schema
394 
395 template <typename SchemaDocumentType>
396 class Schema {
397 public:
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;
403     typedef SchemaValidationContext<SchemaDocumentType> Context;
404     typedef Schema<SchemaDocumentType> SchemaType;
405     typedef GenericValue<EncodingType, AllocatorType> SValue;
406     typedef IValidationErrorHandler<Schema> ErrorHandler;
407     friend class GenericSchemaDocument<ValueType, AllocatorType>;
408 
Schema(SchemaDocumentType * schemaDocument,const PointerType & p,const ValueType & value,const ValueType & document,AllocatorType * allocator)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()),
414         enum_(),
415         enumCount_(),
416         not_(),
417         type_((1 << kTotalSchemaType) - 1), // typeless
418         validatorCount_(),
419         notValidatorIndex_(),
420         properties_(),
421         additionalPropertiesSchema_(),
422         patternProperties_(),
423         patternPropertyCount_(),
424         propertyCount_(),
425         minProperties_(),
426         maxProperties_(SizeType(~0)),
427         additionalProperties_(true),
428         hasDependencies_(),
429         hasRequired_(),
430         hasSchemaDependencies_(),
431         additionalItemsSchema_(),
432         itemsList_(),
433         itemsTuple_(),
434         itemsTupleCount_(),
435         minItems_(),
436         maxItems_(SizeType(~0)),
437         additionalItems_(true),
438         uniqueItems_(false),
439         pattern_(),
440         minLength_(0),
441         maxLength_(~SizeType(0)),
442         exclusiveMinimum_(false),
443         exclusiveMaximum_(false),
444         defaultValueLength_(0)
445     {
446         typedef typename ValueType::ConstValueIterator ConstValueIterator;
447         typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
448 
449         if (!value.IsObject())
450             return;
451 
452         if (const ValueType* v = GetMember(value, GetTypeString())) {
453             type_ = 0;
454             if (v->IsString())
455                 AddType(*v);
456             else if (v->IsArray())
457                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
458                     AddType(*itr);
459         }
460 
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) {
465                     typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
466                     char buffer[256u + 24];
467                     MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
468                     EnumHasherType h(&hasherAllocator, 256);
469                     itr->Accept(h);
470                     enum_[enumCount_++] = h.GetHashCode();
471                 }
472             }
473 
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);
478         }
479 
480         if (const ValueType* v = GetMember(value, GetNotString())) {
481             schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
482             notValidatorIndex_ = validatorCount_;
483             validatorCount_++;
484         }
485 
486         // Object
487 
488         const ValueType* properties = GetMember(value, GetPropertiesString());
489         const ValueType* required = GetMember(value, GetRequiredString());
490         const ValueType* dependencies = GetMember(value, GetDependenciesString());
491         {
492             // Gather properties from properties/required/dependencies
493             SValue allProperties(kArrayType);
494 
495             if (properties && properties->IsObject())
496                 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
497                     AddUniqueElement(allProperties, itr->name);
498 
499             if (required && required->IsArray())
500                 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
501                     if (itr->IsString())
502                         AddUniqueElement(allProperties, *itr);
503 
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)
509                             if (i->IsString())
510                                 AddUniqueElement(allProperties, *i);
511                 }
512 
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_;
520                 }
521             }
522         }
523 
524         if (properties && properties->IsObject()) {
525             PointerType q = p.Append(GetPropertiesString(), allocator_);
526             for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
527                 SizeType index;
528                 if (FindPropertyIndex(itr->name, &index))
529                     schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
530             }
531         }
532 
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;
537 
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_++;
543             }
544         }
545 
546         if (required && required->IsArray())
547             for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
548                 if (itr->IsString()) {
549                     SizeType index;
550                     if (FindPropertyIndex(*itr, &index)) {
551                         properties_[index].required = true;
552                         hasRequired_ = true;
553                     }
554                 }
555 
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) {
560                 SizeType sourceIndex;
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) {
566                             SizeType targetIndex;
567                             if (FindPropertyIndex(*targetItr, &targetIndex))
568                                 properties_[sourceIndex].dependencies[targetIndex] = true;
569                         }
570                     }
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_;
575                         validatorCount_++;
576                     }
577                 }
578             }
579         }
580 
581         if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
582             if (v->IsBool())
583                 additionalProperties_ = v->GetBool();
584             else if (v->IsObject())
585                 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
586         }
587 
588         AssignIfExist(minProperties_, value, GetMinPropertiesString());
589         AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
590 
591         // Array
592         if (const ValueType* v = GetMember(value, GetItemsString())) {
593             PointerType q = p.Append(GetItemsString(), allocator_);
594             if (v->IsObject()) // List validation
595                 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
596             else if (v->IsArray()) { // Tuple validation
597                 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
598                 SizeType index = 0;
599                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
600                     schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
601             }
602         }
603 
604         AssignIfExist(minItems_, value, GetMinItemsString());
605         AssignIfExist(maxItems_, value, GetMaxItemsString());
606 
607         if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
608             if (v->IsBool())
609                 additionalItems_ = v->GetBool();
610             else if (v->IsObject())
611                 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
612         }
613 
614         AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
615 
616         // String
617         AssignIfExist(minLength_, value, GetMinLengthString());
618         AssignIfExist(maxLength_, value, GetMaxLengthString());
619 
620         if (const ValueType* v = GetMember(value, GetPatternString()))
621             pattern_ = CreatePattern(*v);
622 
623         // Number
624         if (const ValueType* v = GetMember(value, GetMinimumString()))
625             if (v->IsNumber())
626                 minimum_.CopyFrom(*v, *allocator_);
627 
628         if (const ValueType* v = GetMember(value, GetMaximumString()))
629             if (v->IsNumber())
630                 maximum_.CopyFrom(*v, *allocator_);
631 
632         AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
633         AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
634 
635         if (const ValueType* v = GetMember(value, GetMultipleOfString()))
636             if (v->IsNumber() && v->GetDouble() > 0.0)
637                 multipleOf_.CopyFrom(*v, *allocator_);
638 
639         // Default
640         if (const ValueType* v = GetMember(value, GetDefaultValueString()))
641             if (v->IsString())
642                 defaultValueLength_ = v->GetStringLength();
643 
644     }
645 
~Schema()646     ~Schema() {
647         AllocatorType::Free(enum_);
648         if (properties_) {
649             for (SizeType i = 0; i < propertyCount_; i++)
650                 properties_[i].~Property();
651             AllocatorType::Free(properties_);
652         }
653         if (patternProperties_) {
654             for (SizeType i = 0; i < patternPropertyCount_; i++)
655                 patternProperties_[i].~PatternProperty();
656             AllocatorType::Free(patternProperties_);
657         }
658         AllocatorType::Free(itemsTuple_);
659 #if RAPIDJSON_SCHEMA_HAS_REGEX
660         if (pattern_) {
661             pattern_->~RegexType();
662             AllocatorType::Free(pattern_);
663         }
664 #endif
665     }
666 
GetURI()667     const SValue& GetURI() const {
668         return uri_;
669     }
670 
GetPointer()671     const PointerType& GetPointer() const {
672         return pointer_;
673     }
674 
BeginValue(Context & context)675     bool BeginValue(Context& context) const {
676         if (context.inArray) {
677             if (uniqueItems_)
678                 context.valueUniqueness = true;
679 
680             if (itemsList_)
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_;
689                 else {
690                     context.error_handler.DisallowedItem(context.arrayElementIndex);
691                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
692                 }
693             }
694             else
695                 context.valueSchema = typeless_;
696 
697             context.arrayElementIndex++;
698         }
699         return true;
700     }
701 
EndValue(Context & context)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();
708 
709             bool patternValid = true;
710             for (SizeType i = 0; i < count; i++)
711                 if (!context.patternPropertiesValidators[i]->IsValid()) {
712                     patternValid = false;
713                     break;
714                 }
715 
716             if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
717                 if (!patternValid) {
718                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
719                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
720                 }
721             }
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());
726                 }
727             }
728             else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
729                 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
730                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
731             }
732         }
733 
734         if (enum_) {
735             const uint64_t h = context.factory.GetHashCode(context.hasher);
736             for (SizeType i = 0; i < enumCount_; i++)
737                 if (enum_[i] == h)
738                     goto foundEnum;
739             context.error_handler.DisallowedValue();
740             RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
741             foundEnum:;
742         }
743 
744         if (allOf_.schemas)
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());
749                 }
750 
751         if (anyOf_.schemas) {
752             for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
753                 if (context.validators[i]->IsValid())
754                     goto foundAny;
755             context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
756             RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
757             foundAny:;
758         }
759 
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()) {
764                     if (oneValid) {
765                         context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
766                         RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
767                     } else
768                         oneValid = true;
769                 }
770             if (!oneValid) {
771                 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
772                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
773             }
774         }
775 
776         if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777             context.error_handler.Disallowed();
778             RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
779         }
780 
781         return true;
782     }
783 
Null(Context & context)784     bool Null(Context& context) const {
785         if (!(type_ & (1 << kNullSchemaType))) {
786             DisallowedType(context, GetNullString());
787             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
788         }
789         return CreateParallelValidator(context);
790     }
791 
Bool(Context & context,bool)792     bool Bool(Context& context, bool) const {
793         if (!(type_ & (1 << kBooleanSchemaType))) {
794             DisallowedType(context, GetBooleanString());
795             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
796         }
797         return CreateParallelValidator(context);
798     }
799 
Int(Context & context,int i)800     bool Int(Context& context, int i) const {
801         if (!CheckInt(context, i))
802             return false;
803         return CreateParallelValidator(context);
804     }
805 
Uint(Context & context,unsigned u)806     bool Uint(Context& context, unsigned u) const {
807         if (!CheckUint(context, u))
808             return false;
809         return CreateParallelValidator(context);
810     }
811 
Int64(Context & context,int64_t i)812     bool Int64(Context& context, int64_t i) const {
813         if (!CheckInt(context, i))
814             return false;
815         return CreateParallelValidator(context);
816     }
817 
Uint64(Context & context,uint64_t u)818     bool Uint64(Context& context, uint64_t u) const {
819         if (!CheckUint(context, u))
820             return false;
821         return CreateParallelValidator(context);
822     }
823 
Double(Context & context,double d)824     bool Double(Context& context, double d) const {
825         if (!(type_ & (1 << kNumberSchemaType))) {
826             DisallowedType(context, GetNumberString());
827             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
828         }
829 
830         if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
831             return false;
832 
833         if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
834             return false;
835 
836         if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
837             return false;
838 
839         return CreateParallelValidator(context);
840     }
841 
String(Context & context,const Ch * str,SizeType length,bool)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());
846         }
847 
848         if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
849             SizeType count;
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());
854                 }
855                 if (count > maxLength_) {
856                     context.error_handler.TooLong(str, length, maxLength_);
857                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
858                 }
859             }
860         }
861 
862         if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863             context.error_handler.DoesNotMatch(str, length);
864             RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
865         }
866 
867         return CreateParallelValidator(context);
868     }
869 
StartObject(Context & context)870     bool StartObject(Context& context) const {
871         if (!(type_ & (1 << kObjectSchemaType))) {
872             DisallowedType(context, GetObjectString());
873             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
874         }
875 
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_);
879         }
880 
881         if (patternProperties_) { // pre-allocate schema array
882             SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
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);
886         }
887 
888         return CreateParallelValidator(context);
889     }
890 
Key(Context & context,const Ch * str,SizeType len,bool)891     bool Key(Context& context, const Ch* str, SizeType len, bool) const {
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_;
898                 }
899         }
900 
901         SizeType index  = 0;
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;
907             }
908             else
909                 context.valueSchema = properties_[index].schema;
910 
911             if (context.propertyExist)
912                 context.propertyExist[index] = true;
913 
914             return true;
915         }
916 
917         if (additionalPropertiesSchema_) {
918             if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
919                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
920                 context.valueSchema = typeless_;
921                 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
922             }
923             else
924                 context.valueSchema = additionalPropertiesSchema_;
925             return true;
926         }
927         else if (additionalProperties_) {
928             context.valueSchema = typeless_;
929             return true;
930         }
931 
932         if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
933             context.error_handler.DisallowedProperty(str, len);
934             RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
935         }
936 
937         return true;
938     }
939 
EndObject(Context & context,SizeType memberCount)940     bool EndObject(Context& context, SizeType memberCount) const {
941         if (hasRequired_) {
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());
949         }
950 
951         if (memberCount < minProperties_) {
952             context.error_handler.TooFewProperties(memberCount, minProperties_);
953             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
954         }
955 
956         if (memberCount > maxProperties_) {
957             context.error_handler.TooManyProperties(memberCount, maxProperties_);
958             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
959         }
960 
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);
972                     }
973                     else if (source.dependenciesSchema) {
974                         ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
975                         if (!dependenciesValidator->IsValid())
976                             context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
977                     }
978                 }
979             }
980             if (context.error_handler.EndDependencyErrors())
981                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
982         }
983 
984         return true;
985     }
986 
StartArray(Context & context)987     bool StartArray(Context& context) const {
988         if (!(type_ & (1 << kArraySchemaType))) {
989             DisallowedType(context, GetArrayString());
990             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
991         }
992 
993         context.arrayElementIndex = 0;
994         context.inArray = true;
995 
996         return CreateParallelValidator(context);
997     }
998 
EndArray(Context & context,SizeType elementCount)999     bool EndArray(Context& context, SizeType elementCount) const {
1000         context.inArray = false;
1001 
1002         if (elementCount < minItems_) {
1003             context.error_handler.TooFewItems(elementCount, minItems_);
1004             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1005         }
1006 
1007         if (elementCount > maxItems_) {
1008             context.error_handler.TooManyItems(elementCount, maxItems_);
1009             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1010         }
1011 
1012         return true;
1013     }
1014 
1015     // Generate functions for string literal according to Ch
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));\
1020         return v;\
1021     }
1022 
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')
1057 
1058 #undef RAPIDJSON_STRING_
1059 
1060 private:
1061     enum SchemaValueType {
1062         kNullSchemaType,
1063         kBooleanSchemaType,
1064         kObjectSchemaType,
1065         kArraySchemaType,
1066         kStringSchemaType,
1067         kNumberSchemaType,
1068         kIntegerSchemaType,
1069         kTotalSchemaType
1070     };
1071 
1072 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1073         typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1074 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1075         typedef std::basic_regex<Ch> RegexType;
1076 #else
1077         typedef char RegexType;
1078 #endif
1079 
1080     struct SchemaArray {
SchemaArraySchemaArray1081         SchemaArray() : schemas(), count() {}
~SchemaArraySchemaArray1082         ~SchemaArray() { AllocatorType::Free(schemas); }
1083         const SchemaType** schemas;
1084         SizeType begin; // begin index of context.validators
1085         SizeType count;
1086     };
1087 
1088     template <typename V1, typename V2>
AddUniqueElement(V1 & a,const V2 & v)1089     void AddUniqueElement(V1& a, const V2& v) {
1090         for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1091             if (*itr == v)
1092                 return;
1093         V1 c(v, *allocator_);
1094         a.PushBack(c, *allocator_);
1095     }
1096 
GetMember(const ValueType & value,const ValueType & name)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;
1100     }
1101 
AssignIfExist(bool & out,const ValueType & value,const ValueType & name)1102     static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
1103         if (const ValueType* v = GetMember(value, name))
1104             if (v->IsBool())
1105                 out = v->GetBool();
1106     }
1107 
AssignIfExist(SizeType & out,const ValueType & value,const ValueType & 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());
1112     }
1113 
AssignIfExist(SchemaArray & out,SchemaDocumentType & schemaDocument,const PointerType & p,const ValueType & value,const ValueType & name,const ValueType & document)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;
1125             }
1126         }
1127     }
1128 
1129 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1130     template <typename ValueType>
CreatePattern(const ValueType & value)1131     RegexType* CreatePattern(const ValueType& value) {
1132         if (value.IsString()) {
1133             RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1134             if (!r->IsValid()) {
1135                 r->~RegexType();
1136                 AllocatorType::Free(r);
1137                 r = 0;
1138             }
1139             return r;
1140         }
1141         return 0;
1142     }
1143 
IsPatternMatch(const RegexType * pattern,const Ch * str,SizeType)1144     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1145         GenericRegexSearch<RegexType> rs(*pattern);
1146         return rs.Search(str);
1147     }
1148 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1149     template <typename ValueType>
CreatePattern(const ValueType & value)1150     RegexType* CreatePattern(const ValueType& value) {
1151         if (value.IsString()) {
1152             RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1153             try {
1154                 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1155             }
1156             catch (const std::regex_error&) {
1157                 AllocatorType::Free(r);
1158             }
1159         }
1160         return 0;
1161     }
1162 
IsPatternMatch(const RegexType * pattern,const Ch * str,SizeType length)1163     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1164         std::match_results<const Ch*> r;
1165         return std::regex_search(str, str + length, r, *pattern);
1166     }
1167 #else
1168     template <typename ValueType>
CreatePattern(const ValueType &)1169     RegexType* CreatePattern(const ValueType&) { return 0; }
1170 
IsPatternMatch(const RegexType *,const Ch *,SizeType)1171     static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1172 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1173 
AddType(const ValueType & type)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);
1182     }
1183 
CreateParallelValidator(Context & context)1184     bool CreateParallelValidator(Context& context) const {
1185         if (enum_ || context.arrayUniqueness)
1186             context.hasher = context.factory.CreateHasher();
1187 
1188         if (validatorCount_) {
1189             RAPIDJSON_ASSERT(context.validators == 0);
1190             context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1191             context.validatorCount = validatorCount_;
1192 
1193             if (allOf_.schemas)
1194                 CreateSchemaValidators(context, allOf_);
1195 
1196             if (anyOf_.schemas)
1197                 CreateSchemaValidators(context, anyOf_);
1198 
1199             if (oneOf_.schemas)
1200                 CreateSchemaValidators(context, oneOf_);
1201 
1202             if (not_)
1203                 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1204 
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);
1209             }
1210         }
1211 
1212         return true;
1213     }
1214 
CreateSchemaValidators(Context & context,const SchemaArray & schemas)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]);
1218     }
1219 
1220     // O(n)
FindPropertyIndex(const ValueType & name,SizeType * outIndex)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))
1227             {
1228                 *outIndex = index;
1229                 return true;
1230             }
1231         return false;
1232     }
1233 
CheckInt(Context & context,int64_t i)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());
1238         }
1239 
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());
1245                 }
1246             }
1247             else if (minimum_.IsUint64()) {
1248                 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1249                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
1250             }
1251             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1252                 return false;
1253         }
1254 
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());
1260                 }
1261             }
1262             else if (maximum_.IsUint64()) { }
1263                 /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1264             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1265                 return false;
1266         }
1267 
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());
1273                 }
1274             }
1275             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1276                 return false;
1277         }
1278 
1279         return true;
1280     }
1281 
CheckUint(Context & context,uint64_t 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());
1286         }
1287 
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());
1293                 }
1294             }
1295             else if (minimum_.IsInt64())
1296                 /* do nothing */; // i >= 0 > minimum.Getint64()
1297             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1298                 return false;
1299         }
1300 
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());
1306                 }
1307             }
1308             else if (maximum_.IsInt64()) {
1309                 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1310                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
1311             }
1312             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1313                 return false;
1314         }
1315 
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());
1321                 }
1322             }
1323             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1324                 return false;
1325         }
1326 
1327         return true;
1328     }
1329 
CheckDoubleMinimum(Context & context,double d)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());
1334         }
1335         return true;
1336     }
1337 
CheckDoubleMaximum(Context & context,double d)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());
1342         }
1343         return true;
1344     }
1345 
CheckDoubleMultipleOf(Context & context,double d)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;
1350         if (r > 0.0) {
1351             context.error_handler.NotMultipleOf(d, multipleOf_);
1352             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1353         }
1354         return true;
1355     }
1356 
DisallowedType(Context & context,const ValueType & actualType)1357     void DisallowedType(Context& context, const ValueType& actualType) const {
1358         ErrorHandler& eh = context.error_handler;
1359         eh.StartDisallowedType();
1360 
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());
1366 
1367         if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1368         else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1369 
1370         eh.EndDisallowedType(actualType);
1371     }
1372 
1373     struct Property {
PropertyProperty1374         Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
~PropertyProperty1375         ~Property() { AllocatorType::Free(dependencies); }
1376         SValue name;
1377         const SchemaType* schema;
1378         const SchemaType* dependenciesSchema;
1379         SizeType dependenciesValidatorIndex;
1380         bool* dependencies;
1381         bool required;
1382     };
1383 
1384     struct PatternProperty {
PatternPropertyPatternProperty1385         PatternProperty() : schema(), pattern() {}
~PatternPropertyPatternProperty1386         ~PatternProperty() {
1387             if (pattern) {
1388                 pattern->~RegexType();
1389                 AllocatorType::Free(pattern);
1390             }
1391         }
1392         const SchemaType* schema;
1393         RegexType* pattern;
1394     };
1395 
1396     AllocatorType* allocator_;
1397     SValue uri_;
1398     PointerType pointer_;
1399     const SchemaType* typeless_;
1400     uint64_t* enum_;
1401     SizeType enumCount_;
1402     SchemaArray allOf_;
1403     SchemaArray anyOf_;
1404     SchemaArray oneOf_;
1405     const SchemaType* not_;
1406     unsigned type_; // bitmask of kSchemaType
1407     SizeType validatorCount_;
1408     SizeType notValidatorIndex_;
1409 
1410     Property* properties_;
1411     const SchemaType* additionalPropertiesSchema_;
1412     PatternProperty* patternProperties_;
1413     SizeType patternPropertyCount_;
1414     SizeType propertyCount_;
1415     SizeType minProperties_;
1416     SizeType maxProperties_;
1417     bool additionalProperties_;
1418     bool hasDependencies_;
1419     bool hasRequired_;
1420     bool hasSchemaDependencies_;
1421 
1422     const SchemaType* additionalItemsSchema_;
1423     const SchemaType* itemsList_;
1424     const SchemaType** itemsTuple_;
1425     SizeType itemsTupleCount_;
1426     SizeType minItems_;
1427     SizeType maxItems_;
1428     bool additionalItems_;
1429     bool uniqueItems_;
1430 
1431     RegexType* pattern_;
1432     SizeType minLength_;
1433     SizeType maxLength_;
1434 
1435     SValue minimum_;
1436     SValue maximum_;
1437     SValue multipleOf_;
1438     bool exclusiveMinimum_;
1439     bool exclusiveMaximum_;
1440 
1441     SizeType defaultValueLength_;
1442 };
1443 
1444 template<typename Stack, typename Ch>
1445 struct TokenHelper {
AppendIndexTokenTokenHelper1446     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1447         *documentStack.template Push<Ch>() = '/';
1448         char buffer[21];
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]);
1452     }
1453 };
1454 
1455 // Partial specialized version for char to prevent buffer copying.
1456 template <typename Stack>
1457 struct TokenHelper<Stack, char> {
1458     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1459         if (sizeof(SizeType) == 4) {
1460             char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1461             *buffer++ = '/';
1462             const char* end = internal::u32toa(index, buffer);
1463              documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1464         }
1465         else {
1466             char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1467             *buffer++ = '/';
1468             const char* end = internal::u64toa(index, buffer);
1469             documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1470         }
1471     }
1472 };
1473 
1474 } // namespace internal
1475 
1476 ///////////////////////////////////////////////////////////////////////////////
1477 // IGenericRemoteSchemaDocumentProvider
1478 
1479 template <typename SchemaDocumentType>
1480 class IGenericRemoteSchemaDocumentProvider {
1481 public:
1482     typedef typename SchemaDocumentType::Ch Ch;
1483 
1484     virtual ~IGenericRemoteSchemaDocumentProvider() {}
1485     virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1486 };
1487 
1488 ///////////////////////////////////////////////////////////////////////////////
1489 // GenericSchemaDocument
1490 
1491 //! JSON schema document.
1492 /*!
1493     A JSON schema document is a compiled version of a JSON schema.
1494     It is basically a tree of internal::Schema.
1495 
1496     \note This is an immutable class (i.e. its instance cannot be modified after construction).
1497     \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1498     \tparam Allocator Allocator type for allocating memory of this document.
1499 */
1500 template <typename ValueT, typename Allocator = CrtAllocator>
1501 class GenericSchemaDocument {
1502 public:
1503     typedef ValueT ValueType;
1504     typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1505     typedef Allocator AllocatorType;
1506     typedef typename ValueType::EncodingType EncodingType;
1507     typedef typename EncodingType::Ch Ch;
1508     typedef internal::Schema<GenericSchemaDocument> SchemaType;
1509     typedef GenericPointer<ValueType, Allocator> PointerType;
1510     typedef GenericValue<EncodingType, Allocator> URIType;
1511     friend class internal::Schema<GenericSchemaDocument>;
1512     template <typename, typename, typename>
1513     friend class GenericSchemaValidator;
1514 
1515     //! Constructor.
1516     /*!
1517         Compile a JSON document into schema document.
1518 
1519         \param document A JSON document as source.
1520         \param uri The base URI of this schema document for purposes of violation reporting.
1521         \param uriLength Length of \c name, in code points.
1522         \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1523         \param allocator An optional allocator instance for allocating memory. Can be null.
1524     */
1525     explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
1526         IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1527         remoteProvider_(remoteProvider),
1528         allocator_(allocator),
1529         ownAllocator_(),
1530         root_(),
1531         typeless_(),
1532         schemaMap_(allocator, kInitialSchemaMapSize),
1533         schemaRef_(allocator, kInitialSchemaRefSize)
1534     {
1535         if (!allocator_)
1536             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1537 
1538         Ch noUri[1] = {0};
1539         uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1540 
1541         typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1542         new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_);
1543 
1544         // Generate root schema, it will call CreateSchema() to create sub-schemas,
1545         // And call AddRefSchema() if there are $ref.
1546         CreateSchemaRecursive(&root_, PointerType(), document, document);
1547 
1548         // Resolve $ref
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;
1554 
1555                 // Create entry in map if not exist
1556                 if (!GetSchema(refEntry->source)) {
1557                     new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
1558                 }
1559             }
1560             else if (refEntry->schema)
1561                 *refEntry->schema = typeless_;
1562 
1563             refEntry->~SchemaRefEntry();
1564         }
1565 
1566         RAPIDJSON_ASSERT(root_ != 0);
1567 
1568         schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1569     }
1570 
1571 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1572     //! Move constructor in C++11
1573     GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1574         remoteProvider_(rhs.remoteProvider_),
1575         allocator_(rhs.allocator_),
1576         ownAllocator_(rhs.ownAllocator_),
1577         root_(rhs.root_),
1578         typeless_(rhs.typeless_),
1579         schemaMap_(std::move(rhs.schemaMap_)),
1580         schemaRef_(std::move(rhs.schemaRef_)),
1581         uri_(std::move(rhs.uri_))
1582     {
1583         rhs.remoteProvider_ = 0;
1584         rhs.allocator_ = 0;
1585         rhs.ownAllocator_ = 0;
1586         rhs.typeless_ = 0;
1587     }
1588 #endif
1589 
1590     //! Destructor
1591     ~GenericSchemaDocument() {
1592         while (!schemaMap_.Empty())
1593             schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1594 
1595         if (typeless_) {
1596             typeless_->~SchemaType();
1597             Allocator::Free(typeless_);
1598         }
1599 
1600         RAPIDJSON_DELETE(ownAllocator_);
1601     }
1602 
1603     const URIType& GetURI() const { return uri_; }
1604 
1605     //! Get the root schema.
1606     const SchemaType& GetRoot() const { return *root_; }
1607 
1608 private:
1609     //! Prohibit copying
1610     GenericSchemaDocument(const GenericSchemaDocument&);
1611     //! Prohibit assignment
1612     GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1613 
1614     struct SchemaRefEntry {
1615         SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1616         PointerType source;
1617         PointerType target;
1618         const SchemaType** schema;
1619     };
1620 
1621     struct SchemaEntry {
1622         SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1623         ~SchemaEntry() {
1624             if (owned) {
1625                 schema->~SchemaType();
1626                 Allocator::Free(schema);
1627             }
1628         }
1629         PointerType pointer;
1630         SchemaType* schema;
1631         bool owned;
1632     };
1633 
1634     void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1635         if (schema)
1636             *schema = typeless_;
1637 
1638         if (v.GetType() == kObjectType) {
1639             const SchemaType* s = GetSchema(pointer);
1640             if (!s)
1641                 CreateSchema(schema, pointer, v, document);
1642 
1643             for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1644                 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1645         }
1646         else if (v.GetType() == kArrayType)
1647             for (SizeType i = 0; i < v.Size(); i++)
1648                 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1649     }
1650 
1651     void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1652         RAPIDJSON_ASSERT(pointer.IsValid());
1653         if (v.IsObject()) {
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_);
1657                 if (schema)
1658                     *schema = s;
1659             }
1660         }
1661     }
1662 
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);
1666 
1667         typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1668         if (itr == v.MemberEnd())
1669             return false;
1670 
1671         if (itr->value.IsString()) {
1672             SizeType len = itr->value.GetStringLength();
1673             if (len > 0) {
1674                 const Ch* s = itr->value.GetString();
1675                 SizeType i = 0;
1676                 while (i < len && s[i] != '#') // Find the first #
1677                     i++;
1678 
1679                 if (i > 0) { // Remote reference, resolve immediately
1680                     if (remoteProvider_) {
1681                         if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1682                             PointerType pointer(&s[i], len - i, allocator_);
1683                             if (pointer.IsValid()) {
1684                                 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1685                                     if (schema)
1686                                         *schema = sc;
1687                                     new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_);
1688                                     return true;
1689                                 }
1690                             }
1691                         }
1692                     }
1693                 }
1694                 else if (s[i] == '#') { // Local reference, defer resolution
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))
1699                                 return true;
1700 
1701                         new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1702                         return true;
1703                     }
1704                 }
1705             }
1706         }
1707         return false;
1708     }
1709 
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;
1714         return 0;
1715     }
1716 
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();
1722     }
1723 
1724     const SchemaType* GetTypeless() const { return typeless_; }
1725 
1726     static const size_t kInitialSchemaMapSize = 64;
1727     static const size_t kInitialSchemaRefSize = 64;
1728 
1729     IRemoteSchemaDocumentProviderType* remoteProvider_;
1730     Allocator *allocator_;
1731     Allocator *ownAllocator_;
1732     const SchemaType* root_;                //!< Root schema.
1733     SchemaType* typeless_;
1734     internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas
1735     internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref
1736     URIType uri_;
1737 };
1738 
1739 //! GenericSchemaDocument using Value type.
1740 typedef GenericSchemaDocument<Value> SchemaDocument;
1741 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
1742 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
1743 
1744 ///////////////////////////////////////////////////////////////////////////////
1745 // GenericSchemaValidator
1746 
1747 //! JSON Schema Validator.
1748 /*!
1749     A SAX style JSON schema validator.
1750     It uses a \c GenericSchemaDocument to validate SAX events.
1751     It delegates the incoming SAX events to an output handler.
1752     The default output handler does nothing.
1753     It can be reused multiple times by calling \c Reset().
1754 
1755     \tparam SchemaDocumentType Type of schema document.
1756     \tparam OutputHandler Type of output handler. Default handler does nothing.
1757     \tparam StateAllocator Allocator for storing the internal validation states.
1758 */
1759 template <
1760     typename SchemaDocumentType,
1761     typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
1762     typename StateAllocator = CrtAllocator>
1763 class GenericSchemaValidator :
1764     public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1765     public internal::ISchemaValidator,
1766     public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
1767 {
1768 public:
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;
1774     typedef GenericStringRef<Ch> StringRefType;
1775     typedef GenericValue<EncodingType, StateAllocator> ValueType;
1776 
1777     //! Constructor without output handler.
1778     /*!
1779         \param schemaDocument The schema document to conform to.
1780         \param allocator Optional allocator for storing internal validation states.
1781         \param schemaStackCapacity Optional initial capacity of schema path stack.
1782         \param documentStackCapacity Optional initial capacity of document path stack.
1783     */
1784     GenericSchemaValidator(
1785         const SchemaDocumentType& schemaDocument,
1786         StateAllocator* allocator = 0,
1787         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1788         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1789         :
1790         schemaDocument_(&schemaDocument),
1791         root_(schemaDocument.GetRoot()),
1792         stateAllocator_(allocator),
1793         ownStateAllocator_(0),
1794         schemaStack_(allocator, schemaStackCapacity),
1795         documentStack_(allocator, documentStackCapacity),
1796         outputHandler_(0),
1797         error_(kObjectType),
1798         currentError_(),
1799         missingDependents_(),
1800         valid_(true)
1801 #if RAPIDJSON_SCHEMA_VERBOSE
1802         , depth_(0)
1803 #endif
1804     {
1805     }
1806 
1807     //! Constructor with output handler.
1808     /*!
1809         \param schemaDocument The schema document to conform to.
1810         \param allocator Optional allocator for storing internal validation states.
1811         \param schemaStackCapacity Optional initial capacity of schema path stack.
1812         \param documentStackCapacity Optional initial capacity of document path stack.
1813     */
1814     GenericSchemaValidator(
1815         const SchemaDocumentType& schemaDocument,
1816         OutputHandler& outputHandler,
1817         StateAllocator* allocator = 0,
1818         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1819         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1820         :
1821         schemaDocument_(&schemaDocument),
1822         root_(schemaDocument.GetRoot()),
1823         stateAllocator_(allocator),
1824         ownStateAllocator_(0),
1825         schemaStack_(allocator, schemaStackCapacity),
1826         documentStack_(allocator, documentStackCapacity),
1827         outputHandler_(&outputHandler),
1828         error_(kObjectType),
1829         currentError_(),
1830         missingDependents_(),
1831         valid_(true)
1832 #if RAPIDJSON_SCHEMA_VERBOSE
1833         , depth_(0)
1834 #endif
1835     {
1836     }
1837 
1838     //! Destructor.
1839     ~GenericSchemaValidator() {
1840         Reset();
1841         RAPIDJSON_DELETE(ownStateAllocator_);
1842     }
1843 
1844     //! Reset the internal states.
1845     void Reset() {
1846         while (!schemaStack_.Empty())
1847             PopSchema();
1848         documentStack_.Clear();
1849         error_.SetObject();
1850         currentError_.SetNull();
1851         missingDependents_.SetNull();
1852         valid_ = true;
1853     }
1854 
1855     //! Checks whether the current state is valid.
1856     // Implementation of ISchemaValidator
1857     virtual bool IsValid() const { return valid_; }
1858 
1859     //! Gets the error object.
1860     ValueType& GetError() { return error_; }
1861     const ValueType& GetError() const { return error_; }
1862 
1863     //! Gets the JSON pointer pointed to the invalid schema.
1864     PointerType GetInvalidSchemaPointer() const {
1865         return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1866     }
1867 
1868     //! Gets the keyword of invalid schema.
1869     const Ch* GetInvalidSchemaKeyword() const {
1870         return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1871     }
1872 
1873     //! Gets the JSON pointer pointed to the invalid value.
1874     PointerType GetInvalidDocumentPointer() const {
1875         if (documentStack_.Empty()) {
1876             return PointerType();
1877         }
1878         else {
1879             return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1880         }
1881     }
1882 
1883     void NotMultipleOf(int64_t actual, const SValue& expected) {
1884         AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1885     }
1886     void NotMultipleOf(uint64_t actual, const SValue& expected) {
1887         AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1888     }
1889     void NotMultipleOf(double actual, const SValue& expected) {
1890         AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1891     }
1892     void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
1893         AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1894             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1895     }
1896     void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
1897         AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1898             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1899     }
1900     void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
1901         AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1902             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1903     }
1904     void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
1905         AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1906             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1907     }
1908     void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
1909         AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1910             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1911     }
1912     void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
1913         AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1914             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1915     }
1916 
1917     void TooLong(const Ch* str, SizeType length, SizeType expected) {
1918         AddNumberError(SchemaType::GetMaxLengthString(),
1919             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1920     }
1921     void TooShort(const Ch* str, SizeType length, SizeType expected) {
1922         AddNumberError(SchemaType::GetMinLengthString(),
1923             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1924     }
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());
1929     }
1930 
1931     void DisallowedItem(SizeType index) {
1932         currentError_.SetObject();
1933         currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
1934         AddCurrentError(SchemaType::GetAdditionalItemsString(), true);
1935     }
1936     void TooFewItems(SizeType actualCount, SizeType expectedCount) {
1937         AddNumberError(SchemaType::GetMinItemsString(),
1938             ValueType(actualCount).Move(), SValue(expectedCount).Move());
1939     }
1940     void TooManyItems(SizeType actualCount, SizeType expectedCount) {
1941         AddNumberError(SchemaType::GetMaxItemsString(),
1942             ValueType(actualCount).Move(), SValue(expectedCount).Move());
1943     }
1944     void DuplicateItems(SizeType index1, SizeType index2) {
1945         ValueType duplicates(kArrayType);
1946         duplicates.PushBack(index1, GetStateAllocator());
1947         duplicates.PushBack(index2, GetStateAllocator());
1948         currentError_.SetObject();
1949         currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1950         AddCurrentError(SchemaType::GetUniqueItemsString(), true);
1951     }
1952 
1953     void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
1954         AddNumberError(SchemaType::GetMaxPropertiesString(),
1955             ValueType(actualCount).Move(), SValue(expectedCount).Move());
1956     }
1957     void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
1958         AddNumberError(SchemaType::GetMinPropertiesString(),
1959             ValueType(actualCount).Move(), SValue(expectedCount).Move());
1960     }
1961     void StartMissingProperties() {
1962         currentError_.SetArray();
1963     }
1964     void AddMissingProperty(const SValue& name) {
1965         currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1966     }
1967     bool EndMissingProperties() {
1968         if (currentError_.Empty())
1969             return false;
1970         ValueType error(kObjectType);
1971         error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1972         currentError_ = error;
1973         AddCurrentError(SchemaType::GetRequiredString());
1974         return true;
1975     }
1976     void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
1977         for (SizeType i = 0; i < count; ++i)
1978             MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
1979     }
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);
1984     }
1985 
1986     void StartDependencyErrors() {
1987         currentError_.SetObject();
1988     }
1989     void StartMissingDependentProperties() {
1990         missingDependents_.SetArray();
1991     }
1992     void AddMissingDependentProperty(const SValue& targetName) {
1993         missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1994     }
1995     void EndMissingDependentProperties(const SValue& sourceName) {
1996         if (!missingDependents_.Empty())
1997             currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
1998                 missingDependents_, GetStateAllocator());
1999     }
2000     void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2001         currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2002             static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2003     }
2004     bool EndDependencyErrors() {
2005         if (currentError_.ObjectEmpty())
2006             return false;
2007         ValueType error(kObjectType);
2008         error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2009         currentError_ = error;
2010         AddCurrentError(SchemaType::GetDependenciesString());
2011         return true;
2012     }
2013 
2014     void DisallowedValue() {
2015         currentError_.SetObject();
2016         AddCurrentError(SchemaType::GetEnumString());
2017     }
2018     void StartDisallowedType() {
2019         currentError_.SetArray();
2020     }
2021     void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
2022         currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2023     }
2024     void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
2025         ValueType error(kObjectType);
2026         error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2027         error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2028         currentError_ = error;
2029         AddCurrentError(SchemaType::GetTypeString());
2030     }
2031     void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2032         for (SizeType i = 0; i < count; ++i) {
2033             MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2034         }
2035     }
2036     void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2037         AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
2038     }
2039     void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2040         AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
2041     }
2042     void Disallowed() {
2043         currentError_.SetObject();
2044         AddCurrentError(SchemaType::GetNotString());
2045     }
2046 
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)); \
2051         return v;\
2052     }
2053 
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')
2062 
2063 #undef RAPIDJSON_STRING_
2064 
2065 #if RAPIDJSON_SCHEMA_VERBOSE
2066 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2067 RAPIDJSON_MULTILINEMACRO_BEGIN\
2068     *documentStack_.template Push<Ch>() = '\0';\
2069     documentStack_.template Pop<Ch>(1);\
2070     internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2071 RAPIDJSON_MULTILINEMACRO_END
2072 #else
2073 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2074 #endif
2075 
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;\
2081     }
2082 
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;\
2093     }
2094 
2095 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2096     return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
2097 
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)
2102 
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)); }
2114 
2115     bool StartObject() {
2116         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2117         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2118         return valid_ = !outputHandler_ || outputHandler_->StartObject();
2119     }
2120 
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);
2127     }
2128 
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));
2134     }
2135 
2136     bool StartArray() {
2137         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2138         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2139         return valid_ = !outputHandler_ || outputHandler_->StartArray();
2140     }
2141 
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));
2147     }
2148 
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_
2153 
2154     // Implementation of ISchemaStateFactory<SchemaType>
2155     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
2156         return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2157 #if RAPIDJSON_SCHEMA_VERBOSE
2158         depth_ + 1,
2159 #endif
2160         &GetStateAllocator());
2161     }
2162 
2163     virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2164         GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
2165         v->~GenericSchemaValidator();
2166         StateAllocator::Free(v);
2167     }
2168 
2169     virtual void* CreateHasher() {
2170         return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
2171     }
2172 
2173     virtual uint64_t GetHashCode(void* hasher) {
2174         return static_cast<HasherType*>(hasher)->GetHashCode();
2175     }
2176 
2177     virtual void DestroryHasher(void* hasher) {
2178         HasherType* h = static_cast<HasherType*>(hasher);
2179         h->~HasherType();
2180         StateAllocator::Free(h);
2181     }
2182 
2183     virtual void* MallocState(size_t size) {
2184         return GetStateAllocator().Malloc(size);
2185     }
2186 
2187     virtual void FreeState(void* p) {
2188         StateAllocator::Free(p);
2189     }
2190 
2191 private:
2192     typedef typename SchemaType::Context Context;
2193     typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2194     typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2195 
2196     GenericSchemaValidator(
2197         const SchemaDocumentType& schemaDocument,
2198         const SchemaType& root,
2199         const char* basePath, size_t basePathSize,
2200 #if RAPIDJSON_SCHEMA_VERBOSE
2201         unsigned depth,
2202 #endif
2203         StateAllocator* allocator = 0,
2204         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2205         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2206         :
2207         schemaDocument_(&schemaDocument),
2208         root_(root),
2209         stateAllocator_(allocator),
2210         ownStateAllocator_(0),
2211         schemaStack_(allocator, schemaStackCapacity),
2212         documentStack_(allocator, documentStackCapacity),
2213         outputHandler_(0),
2214         error_(kObjectType),
2215         currentError_(),
2216         missingDependents_(),
2217         valid_(true)
2218 #if RAPIDJSON_SCHEMA_VERBOSE
2219         , depth_(depth)
2220 #endif
2221     {
2222         if (basePath && basePathSize)
2223             memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2224     }
2225 
2226     StateAllocator& GetStateAllocator() {
2227         if (!stateAllocator_)
2228             stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
2229         return *stateAllocator_;
2230     }
2231 
2232     bool BeginValue() {
2233         if (schemaStack_.Empty())
2234             PushSchema(root_);
2235         else {
2236             if (CurrentContext().inArray)
2237                 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2238 
2239             if (!CurrentSchema().BeginValue(CurrentContext()))
2240                 return false;
2241 
2242             SizeType count = CurrentContext().patternPropertiesSchemaCount;
2243             const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2244             typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2245             bool valueUniqueness = CurrentContext().valueUniqueness;
2246             RAPIDJSON_ASSERT(CurrentContext().valueSchema);
2247             PushSchema(*CurrentContext().valueSchema);
2248 
2249             if (count > 0) {
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]);
2256             }
2257 
2258             CurrentContext().arrayUniqueness = valueUniqueness;
2259         }
2260         return true;
2261     }
2262 
2263     bool EndValue() {
2264         if (!CurrentSchema().EndValue(CurrentContext()))
2265             return false;
2266 
2267 #if RAPIDJSON_SCHEMA_VERBOSE
2268         GenericStringBuffer<EncodingType> sb;
2269         schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2270 
2271         *documentStack_.template Push<Ch>() = '\0';
2272         documentStack_.template Pop<Ch>(1);
2273         internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2274 #endif
2275 
2276         uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
2277 
2278         PopSchema();
2279 
2280         if (!schemaStack_.Empty()) {
2281             Context& context = CurrentContext();
2282             if (context.valueUniqueness) {
2283                 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
2284                 if (!a)
2285                     CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
2286                 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
2287                     if (itr->GetUint64() == h) {
2288                         DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
2289                         RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
2290                     }
2291                 a->PushBack(h, GetStateAllocator());
2292             }
2293         }
2294 
2295         // Remove the last token of document pointer
2296         while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
2297             ;
2298 
2299         return true;
2300     }
2301 
2302     void AppendToken(const Ch* str, SizeType len) {
2303         documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
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';
2309             }
2310             else if (str[i] == '/') {
2311                 *documentStack_.template PushUnsafe<Ch>() = '~';
2312                 *documentStack_.template PushUnsafe<Ch>() = '1';
2313             }
2314             else
2315                 *documentStack_.template PushUnsafe<Ch>() = str[i];
2316         }
2317     }
2318 
2319     RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); }
2320 
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);
2326         }
2327         c->~Context();
2328     }
2329 
2330     void AddErrorLocation(ValueType& result, bool parent) {
2331         GenericStringBuffer<EncodingType> sb;
2332         PointerType instancePointer = GetInvalidDocumentPointer();
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());
2339         sb.Clear();
2340         memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
2341             CurrentSchema().GetURI().GetString(),
2342             CurrentSchema().GetURI().GetStringLength() * sizeof(Ch));
2343         GetInvalidSchemaPointer().StringifyUriFragment(sb);
2344         ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2345             GetStateAllocator());
2346         result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2347     }
2348 
2349     void AddError(ValueType& keyword, ValueType& error) {
2350         typename ValueType::MemberIterator member = error_.FindMember(keyword);
2351         if (member == error_.MemberEnd())
2352             error_.AddMember(keyword, error, GetStateAllocator());
2353         else {
2354             if (member->value.IsObject()) {
2355                 ValueType errors(kArrayType);
2356                 errors.PushBack(member->value, GetStateAllocator());
2357                 member->value = errors;
2358             }
2359             member->value.PushBack(error, GetStateAllocator());
2360         }
2361     }
2362 
2363     void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) {
2364         AddErrorLocation(currentError_, parent);
2365         AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_);
2366     }
2367 
2368     void MergeError(ValueType& other) {
2369         for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
2370             AddError(it->name, it->value);
2371         }
2372     }
2373 
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());
2379         if (exclusive)
2380             currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
2381         AddCurrentError(keyword);
2382     }
2383 
2384     void AddErrorArray(const typename SchemaType::ValueType& keyword,
2385         ISchemaValidator** subvalidators, SizeType count) {
2386         ValueType errors(kArrayType);
2387         for (SizeType i = 0; i < count; ++i)
2388             errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
2389         currentError_.SetObject();
2390         currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2391         AddCurrentError(keyword);
2392     }
2393 
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>(); }
2397 
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_;
2404     internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)
2405     internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)
2406     OutputHandler* outputHandler_;
2407     ValueType error_;
2408     ValueType currentError_;
2409     ValueType missingDependents_;
2410     bool valid_;
2411 #if RAPIDJSON_SCHEMA_VERBOSE
2412     unsigned depth_;
2413 #endif
2414 };
2415 
2416 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
2417 
2418 ///////////////////////////////////////////////////////////////////////////////
2419 // SchemaValidatingReader
2420 
2421 //! A helper class for parsing with validation.
2422 /*!
2423     This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
2424 
2425     \tparam parseFlags Combination of \ref ParseFlag.
2426     \tparam InputStream Type of input stream, implementing Stream concept.
2427     \tparam SourceEncoding Encoding of the input stream.
2428     \tparam SchemaDocumentType Type of schema document.
2429     \tparam StackAllocator Allocator type for stack.
2430 */
2431 template <
2432     unsigned parseFlags,
2433     typename InputStream,
2434     typename SourceEncoding,
2435     typename SchemaDocumentType = SchemaDocument,
2436     typename StackAllocator = CrtAllocator>
2437 class SchemaValidatingReader {
2438 public:
2439     typedef typename SchemaDocumentType::PointerType PointerType;
2440     typedef typename InputStream::Ch Ch;
2441     typedef GenericValue<SourceEncoding, StackAllocator> ValueType;
2442 
2443     //! Constructor
2444     /*!
2445         \param is Input stream.
2446         \param sd Schema document.
2447     */
2448     SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}
2449 
2450     template <typename Handler>
2451     bool operator()(Handler& handler) {
2452         GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
2453         GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
2454         parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2455 
2456         isValid_ = validator.IsValid();
2457         if (isValid_) {
2458             invalidSchemaPointer_ = PointerType();
2459             invalidSchemaKeyword_ = 0;
2460             invalidDocumentPointer_ = PointerType();
2461             error_.SetObject();
2462         }
2463         else {
2464             invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
2465             invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2466             invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2467             error_.CopyFrom(validator.GetError(), allocator_);
2468         }
2469 
2470         return parseResult_;
2471     }
2472 
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_; }
2479 
2480 private:
2481     InputStream& is_;
2482     const SchemaDocumentType& sd_;
2483 
2484     ParseResult parseResult_;
2485     PointerType invalidSchemaPointer_;
2486     const Ch* invalidSchemaKeyword_;
2487     PointerType invalidDocumentPointer_;
2488     StackAllocator allocator_;
2489     ValueType error_;
2490     bool isValid_;
2491 };
2492 
2493 RAPIDJSON_NAMESPACE_END
2494 RAPIDJSON_DIAG_POP
2495 
2496 #endif // RAPIDJSON_SCHEMA_H_
2497