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 "error/en.h"
22 #include <cmath> // abs, floor
23 
24 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
26 #else
27 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
28 #endif
29 
30 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
32 #else
33 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
34 #endif
35 
36 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
37 #include "internal/regex.h"
38 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
39 #include <regex>
40 #endif
41 
42 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
43 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
44 #else
45 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
46 #endif
47 
48 #ifndef RAPIDJSON_SCHEMA_VERBOSE
49 #define RAPIDJSON_SCHEMA_VERBOSE 0
50 #endif
51 
52 #if RAPIDJSON_SCHEMA_VERBOSE
53 #include "stringbuffer.h"
54 #endif
55 
56 RAPIDJSON_DIAG_PUSH
57 
58 #if defined(__GNUC__)
59 RAPIDJSON_DIAG_OFF(effc++)
60 #endif
61 
62 #ifdef __clang__
63 RAPIDJSON_DIAG_OFF(weak-vtables)
64 RAPIDJSON_DIAG_OFF(exit-time-destructors)
65 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
66 RAPIDJSON_DIAG_OFF(variadic-macros)
67 #elif defined(_MSC_VER)
68 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
69 #endif
70 
71 RAPIDJSON_NAMESPACE_BEGIN
72 
73 ///////////////////////////////////////////////////////////////////////////////
74 // Verbose Utilities
75 
76 #if RAPIDJSON_SCHEMA_VERBOSE
77 
78 namespace internal {
79 
PrintInvalidKeyword(const char * keyword)80 inline void PrintInvalidKeyword(const char* keyword) {
81     printf("Fail keyword: %s\n", keyword);
82 }
83 
PrintInvalidKeyword(const wchar_t * keyword)84 inline void PrintInvalidKeyword(const wchar_t* keyword) {
85     wprintf(L"Fail keyword: %ls\n", keyword);
86 }
87 
PrintInvalidDocument(const char * document)88 inline void PrintInvalidDocument(const char* document) {
89     printf("Fail document: %s\n\n", document);
90 }
91 
PrintInvalidDocument(const wchar_t * document)92 inline void PrintInvalidDocument(const wchar_t* document) {
93     wprintf(L"Fail document: %ls\n\n", document);
94 }
95 
PrintValidatorPointers(unsigned depth,const char * s,const char * d)96 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
97     printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
98 }
99 
PrintValidatorPointers(unsigned depth,const wchar_t * s,const wchar_t * d)100 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
101     wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
102 }
103 
104 } // namespace internal
105 
106 #endif // RAPIDJSON_SCHEMA_VERBOSE
107 
108 ///////////////////////////////////////////////////////////////////////////////
109 // RAPIDJSON_INVALID_KEYWORD_RETURN
110 
111 #if RAPIDJSON_SCHEMA_VERBOSE
112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
113 #else
114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
115 #endif
116 
117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
118 RAPIDJSON_MULTILINEMACRO_BEGIN\
119     context.invalidCode = code;\
120     context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
121     RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
122     return false;\
123 RAPIDJSON_MULTILINEMACRO_END
124 
125 ///////////////////////////////////////////////////////////////////////////////
126 // ValidateFlag
127 
128 /*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
129     \ingroup RAPIDJSON_CONFIG
130     \brief User-defined kValidateDefaultFlags definition.
131 
132     User can define this as any \c ValidateFlag combinations.
133 */
134 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
135 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
136 #endif
137 
138 //! Combination of validate flags
139 /*! \see
140  */
141 enum ValidateFlag {
142     kValidateNoFlags = 0,                                       //!< No flags are set.
143     kValidateContinueOnErrorFlag = 1,                           //!< Don't stop after first validation error.
144     kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS    //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
145 };
146 
147 ///////////////////////////////////////////////////////////////////////////////
148 // Forward declarations
149 
150 template <typename ValueType, typename Allocator>
151 class GenericSchemaDocument;
152 
153 namespace internal {
154 
155 template <typename SchemaDocumentType>
156 class Schema;
157 
158 ///////////////////////////////////////////////////////////////////////////////
159 // ISchemaValidator
160 
161 class ISchemaValidator {
162 public:
~ISchemaValidator()163     virtual ~ISchemaValidator() {}
164     virtual bool IsValid() const = 0;
165     virtual void SetValidateFlags(unsigned flags) = 0;
166     virtual unsigned GetValidateFlags() const = 0;
167 };
168 
169 ///////////////////////////////////////////////////////////////////////////////
170 // ISchemaStateFactory
171 
172 template <typename SchemaType>
173 class ISchemaStateFactory {
174 public:
~ISchemaStateFactory()175     virtual ~ISchemaStateFactory() {}
176     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
177     virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
178     virtual void* CreateHasher() = 0;
179     virtual uint64_t GetHashCode(void* hasher) = 0;
180     virtual void DestroryHasher(void* hasher) = 0;
181     virtual void* MallocState(size_t size) = 0;
182     virtual void FreeState(void* p) = 0;
183 };
184 
185 ///////////////////////////////////////////////////////////////////////////////
186 // IValidationErrorHandler
187 
188 template <typename SchemaType>
189 class IValidationErrorHandler {
190 public:
191     typedef typename SchemaType::Ch Ch;
192     typedef typename SchemaType::SValue SValue;
193 
~IValidationErrorHandler()194     virtual ~IValidationErrorHandler() {}
195 
196     virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
197     virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
198     virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
199     virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
200     virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
201     virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
202     virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
203     virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
204     virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
205 
206     virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
207     virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
208     virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
209 
210     virtual void DisallowedItem(SizeType index) = 0;
211     virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
212     virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
213     virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
214 
215     virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
216     virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
217     virtual void StartMissingProperties() = 0;
218     virtual void AddMissingProperty(const SValue& name) = 0;
219     virtual bool EndMissingProperties() = 0;
220     virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
221     virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
222 
223     virtual void StartDependencyErrors() = 0;
224     virtual void StartMissingDependentProperties() = 0;
225     virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
226     virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
227     virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
228     virtual bool EndDependencyErrors() = 0;
229 
230     virtual void DisallowedValue(const ValidateErrorCode code) = 0;
231     virtual void StartDisallowedType() = 0;
232     virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
233     virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
234     virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
235     virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
236     virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched) = 0;
237     virtual void Disallowed() = 0;
238 };
239 
240 
241 ///////////////////////////////////////////////////////////////////////////////
242 // Hasher
243 
244 // For comparison of compound value
245 template<typename Encoding, typename Allocator>
246 class Hasher {
247 public:
248     typedef typename Encoding::Ch Ch;
249 
stack_(allocator,stackCapacity)250     Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
251 
Null()252     bool Null() { return WriteType(kNullType); }
Bool(bool b)253     bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
Int(int i)254     bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
Uint(unsigned u)255     bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
Int64(int64_t i)256     bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
Uint64(uint64_t u)257     bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
Double(double d)258     bool Double(double d) {
259         Number n;
260         if (d < 0) n.u.i = static_cast<int64_t>(d);
261         else       n.u.u = static_cast<uint64_t>(d);
262         n.d = d;
263         return WriteNumber(n);
264     }
265 
RawNumber(const Ch * str,SizeType len,bool)266     bool RawNumber(const Ch* str, SizeType len, bool) {
267         WriteBuffer(kNumberType, str, len * sizeof(Ch));
268         return true;
269     }
270 
String(const Ch * str,SizeType len,bool)271     bool String(const Ch* str, SizeType len, bool) {
272         WriteBuffer(kStringType, str, len * sizeof(Ch));
273         return true;
274     }
275 
StartObject()276     bool StartObject() { return true; }
Key(const Ch * str,SizeType len,bool copy)277     bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
EndObject(SizeType memberCount)278     bool EndObject(SizeType memberCount) {
279         uint64_t h = Hash(0, kObjectType);
280         uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
281         for (SizeType i = 0; i < memberCount; i++)
282             h ^= Hash(kv[i * 2], kv[i * 2 + 1]);  // Use xor to achieve member order insensitive
283         *stack_.template Push<uint64_t>() = h;
284         return true;
285     }
286 
StartArray()287     bool StartArray() { return true; }
EndArray(SizeType elementCount)288     bool EndArray(SizeType elementCount) {
289         uint64_t h = Hash(0, kArrayType);
290         uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
291         for (SizeType i = 0; i < elementCount; i++)
292             h = Hash(h, e[i]); // Use hash to achieve element order sensitive
293         *stack_.template Push<uint64_t>() = h;
294         return true;
295     }
296 
IsValid()297     bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
298 
GetHashCode()299     uint64_t GetHashCode() const {
300         RAPIDJSON_ASSERT(IsValid());
301         return *stack_.template Top<uint64_t>();
302     }
303 
304 private:
305     static const size_t kDefaultSize = 256;
306     struct Number {
307         union U {
308             uint64_t u;
309             int64_t i;
310         }u;
311         double d;
312     };
313 
WriteType(Type type)314     bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
315 
WriteNumber(const Number & n)316     bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
317 
WriteBuffer(Type type,const void * data,size_t len)318     bool WriteBuffer(Type type, const void* data, size_t len) {
319         // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
320         uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
321         const unsigned char* d = static_cast<const unsigned char*>(data);
322         for (size_t i = 0; i < len; i++)
323             h = Hash(h, d[i]);
324         *stack_.template Push<uint64_t>() = h;
325         return true;
326     }
327 
Hash(uint64_t h,uint64_t d)328     static uint64_t Hash(uint64_t h, uint64_t d) {
329         static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
330         h ^= d;
331         h *= kPrime;
332         return h;
333     }
334 
335     Stack<Allocator> stack_;
336 };
337 
338 ///////////////////////////////////////////////////////////////////////////////
339 // SchemaValidationContext
340 
341 template <typename SchemaDocumentType>
342 struct SchemaValidationContext {
343     typedef Schema<SchemaDocumentType> SchemaType;
344     typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
345     typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
346     typedef typename SchemaType::ValueType ValueType;
347     typedef typename ValueType::Ch Ch;
348 
349     enum PatternValidatorType {
350         kPatternValidatorOnly,
351         kPatternValidatorWithProperty,
352         kPatternValidatorWithAdditionalProperty
353     };
354 
SchemaValidationContextSchemaValidationContext355     SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :
356         factory(f),
357         error_handler(eh),
358         schema(s),
359         valueSchema(),
360         invalidKeyword(),
361         invalidCode(),
362         hasher(),
363         arrayElementHashCodes(),
364         validators(),
365         validatorCount(),
366         patternPropertiesValidators(),
367         patternPropertiesValidatorCount(),
368         patternPropertiesSchemas(),
369         patternPropertiesSchemaCount(),
370         valuePatternValidatorType(kPatternValidatorOnly),
371         propertyExist(),
372         inArray(false),
373         valueUniqueness(false),
374         arrayUniqueness(false)
375     {
376     }
377 
~SchemaValidationContextSchemaValidationContext378     ~SchemaValidationContext() {
379         if (hasher)
380             factory.DestroryHasher(hasher);
381         if (validators) {
382             for (SizeType i = 0; i < validatorCount; i++)
383                 factory.DestroySchemaValidator(validators[i]);
384             factory.FreeState(validators);
385         }
386         if (patternPropertiesValidators) {
387             for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
388                 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
389             factory.FreeState(patternPropertiesValidators);
390         }
391         if (patternPropertiesSchemas)
392             factory.FreeState(patternPropertiesSchemas);
393         if (propertyExist)
394             factory.FreeState(propertyExist);
395     }
396 
397     SchemaValidatorFactoryType& factory;
398     ErrorHandlerType& error_handler;
399     const SchemaType* schema;
400     const SchemaType* valueSchema;
401     const Ch* invalidKeyword;
402     ValidateErrorCode invalidCode;
403     void* hasher; // Only validator access
404     void* arrayElementHashCodes; // Only validator access this
405     ISchemaValidator** validators;
406     SizeType validatorCount;
407     ISchemaValidator** patternPropertiesValidators;
408     SizeType patternPropertiesValidatorCount;
409     const SchemaType** patternPropertiesSchemas;
410     SizeType patternPropertiesSchemaCount;
411     PatternValidatorType valuePatternValidatorType;
412     PatternValidatorType objectPatternValidatorType;
413     SizeType arrayElementIndex;
414     bool* propertyExist;
415     bool inArray;
416     bool valueUniqueness;
417     bool arrayUniqueness;
418 };
419 
420 ///////////////////////////////////////////////////////////////////////////////
421 // Schema
422 
423 template <typename SchemaDocumentType>
424 class Schema {
425 public:
426     typedef typename SchemaDocumentType::ValueType ValueType;
427     typedef typename SchemaDocumentType::AllocatorType AllocatorType;
428     typedef typename SchemaDocumentType::PointerType PointerType;
429     typedef typename ValueType::EncodingType EncodingType;
430     typedef typename EncodingType::Ch Ch;
431     typedef SchemaValidationContext<SchemaDocumentType> Context;
432     typedef Schema<SchemaDocumentType> SchemaType;
433     typedef GenericValue<EncodingType, AllocatorType> SValue;
434     typedef IValidationErrorHandler<Schema> ErrorHandler;
435     friend class GenericSchemaDocument<ValueType, AllocatorType>;
436 
Schema(SchemaDocumentType * schemaDocument,const PointerType & p,const ValueType & value,const ValueType & document,AllocatorType * allocator)437     Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
438         allocator_(allocator),
439         uri_(schemaDocument->GetURI(), *allocator),
440         pointer_(p, allocator),
441         typeless_(schemaDocument->GetTypeless()),
442         enum_(),
443         enumCount_(),
444         not_(),
445         type_((1 << kTotalSchemaType) - 1), // typeless
446         validatorCount_(),
447         notValidatorIndex_(),
448         properties_(),
449         additionalPropertiesSchema_(),
450         patternProperties_(),
451         patternPropertyCount_(),
452         propertyCount_(),
453         minProperties_(),
454         maxProperties_(SizeType(~0)),
455         additionalProperties_(true),
456         hasDependencies_(),
457         hasRequired_(),
458         hasSchemaDependencies_(),
459         additionalItemsSchema_(),
460         itemsList_(),
461         itemsTuple_(),
462         itemsTupleCount_(),
463         minItems_(),
464         maxItems_(SizeType(~0)),
465         additionalItems_(true),
466         uniqueItems_(false),
467         pattern_(),
468         minLength_(0),
469         maxLength_(~SizeType(0)),
470         exclusiveMinimum_(false),
471         exclusiveMaximum_(false),
472         defaultValueLength_(0)
473     {
474         typedef typename ValueType::ConstValueIterator ConstValueIterator;
475         typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
476 
477         if (!value.IsObject())
478             return;
479 
480         if (const ValueType* v = GetMember(value, GetTypeString())) {
481             type_ = 0;
482             if (v->IsString())
483                 AddType(*v);
484             else if (v->IsArray())
485                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
486                     AddType(*itr);
487         }
488 
489         if (const ValueType* v = GetMember(value, GetEnumString())) {
490             if (v->IsArray() && v->Size() > 0) {
491                 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
492                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
493                     typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
494                     char buffer[256u + 24];
495                     MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
496                     EnumHasherType h(&hasherAllocator, 256);
497                     itr->Accept(h);
498                     enum_[enumCount_++] = h.GetHashCode();
499                 }
500             }
501         }
502 
503         if (schemaDocument) {
504             AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
505             AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
506             AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
507         }
508 
509         if (const ValueType* v = GetMember(value, GetNotString())) {
510             schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
511             notValidatorIndex_ = validatorCount_;
512             validatorCount_++;
513         }
514 
515         // Object
516 
517         const ValueType* properties = GetMember(value, GetPropertiesString());
518         const ValueType* required = GetMember(value, GetRequiredString());
519         const ValueType* dependencies = GetMember(value, GetDependenciesString());
520         {
521             // Gather properties from properties/required/dependencies
522             SValue allProperties(kArrayType);
523 
524             if (properties && properties->IsObject())
525                 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
526                     AddUniqueElement(allProperties, itr->name);
527 
528             if (required && required->IsArray())
529                 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
530                     if (itr->IsString())
531                         AddUniqueElement(allProperties, *itr);
532 
533             if (dependencies && dependencies->IsObject())
534                 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
535                     AddUniqueElement(allProperties, itr->name);
536                     if (itr->value.IsArray())
537                         for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
538                             if (i->IsString())
539                                 AddUniqueElement(allProperties, *i);
540                 }
541 
542             if (allProperties.Size() > 0) {
543                 propertyCount_ = allProperties.Size();
544                 properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
545                 for (SizeType i = 0; i < propertyCount_; i++) {
546                     new (&properties_[i]) Property();
547                     properties_[i].name = allProperties[i];
548                     properties_[i].schema = typeless_;
549                 }
550             }
551         }
552 
553         if (properties && properties->IsObject()) {
554             PointerType q = p.Append(GetPropertiesString(), allocator_);
555             for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
556                 SizeType index;
557                 if (FindPropertyIndex(itr->name, &index))
558                     schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
559             }
560         }
561 
562         if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
563             PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
564             patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
565             patternPropertyCount_ = 0;
566 
567             for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
568                 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
569                 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
570                 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
571                 patternPropertyCount_++;
572             }
573         }
574 
575         if (required && required->IsArray())
576             for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
577                 if (itr->IsString()) {
578                     SizeType index;
579                     if (FindPropertyIndex(*itr, &index)) {
580                         properties_[index].required = true;
581                         hasRequired_ = true;
582                     }
583                 }
584 
585         if (dependencies && dependencies->IsObject()) {
586             PointerType q = p.Append(GetDependenciesString(), allocator_);
587             hasDependencies_ = true;
588             for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
589                 SizeType sourceIndex;
590                 if (FindPropertyIndex(itr->name, &sourceIndex)) {
591                     if (itr->value.IsArray()) {
592                         properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
593                         std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
594                         for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
595                             SizeType targetIndex;
596                             if (FindPropertyIndex(*targetItr, &targetIndex))
597                                 properties_[sourceIndex].dependencies[targetIndex] = true;
598                         }
599                     }
600                     else if (itr->value.IsObject()) {
601                         hasSchemaDependencies_ = true;
602                         schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
603                         properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
604                         validatorCount_++;
605                     }
606                 }
607             }
608         }
609 
610         if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
611             if (v->IsBool())
612                 additionalProperties_ = v->GetBool();
613             else if (v->IsObject())
614                 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
615         }
616 
617         AssignIfExist(minProperties_, value, GetMinPropertiesString());
618         AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
619 
620         // Array
621         if (const ValueType* v = GetMember(value, GetItemsString())) {
622             PointerType q = p.Append(GetItemsString(), allocator_);
623             if (v->IsObject()) // List validation
624                 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
625             else if (v->IsArray()) { // Tuple validation
626                 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
627                 SizeType index = 0;
628                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
629                     schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
630             }
631         }
632 
633         AssignIfExist(minItems_, value, GetMinItemsString());
634         AssignIfExist(maxItems_, value, GetMaxItemsString());
635 
636         if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
637             if (v->IsBool())
638                 additionalItems_ = v->GetBool();
639             else if (v->IsObject())
640                 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
641         }
642 
643         AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
644 
645         // String
646         AssignIfExist(minLength_, value, GetMinLengthString());
647         AssignIfExist(maxLength_, value, GetMaxLengthString());
648 
649         if (const ValueType* v = GetMember(value, GetPatternString()))
650             pattern_ = CreatePattern(*v);
651 
652         // Number
653         if (const ValueType* v = GetMember(value, GetMinimumString()))
654             if (v->IsNumber())
655                 minimum_.CopyFrom(*v, *allocator_);
656 
657         if (const ValueType* v = GetMember(value, GetMaximumString()))
658             if (v->IsNumber())
659                 maximum_.CopyFrom(*v, *allocator_);
660 
661         AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
662         AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
663 
664         if (const ValueType* v = GetMember(value, GetMultipleOfString()))
665             if (v->IsNumber() && v->GetDouble() > 0.0)
666                 multipleOf_.CopyFrom(*v, *allocator_);
667 
668         // Default
669         if (const ValueType* v = GetMember(value, GetDefaultValueString()))
670             if (v->IsString())
671                 defaultValueLength_ = v->GetStringLength();
672 
673     }
674 
~Schema()675     ~Schema() {
676         AllocatorType::Free(enum_);
677         if (properties_) {
678             for (SizeType i = 0; i < propertyCount_; i++)
679                 properties_[i].~Property();
680             AllocatorType::Free(properties_);
681         }
682         if (patternProperties_) {
683             for (SizeType i = 0; i < patternPropertyCount_; i++)
684                 patternProperties_[i].~PatternProperty();
685             AllocatorType::Free(patternProperties_);
686         }
687         AllocatorType::Free(itemsTuple_);
688 #if RAPIDJSON_SCHEMA_HAS_REGEX
689         if (pattern_) {
690             pattern_->~RegexType();
691             AllocatorType::Free(pattern_);
692         }
693 #endif
694     }
695 
GetURI()696     const SValue& GetURI() const {
697         return uri_;
698     }
699 
GetPointer()700     const PointerType& GetPointer() const {
701         return pointer_;
702     }
703 
BeginValue(Context & context)704     bool BeginValue(Context& context) const {
705         if (context.inArray) {
706             if (uniqueItems_)
707                 context.valueUniqueness = true;
708 
709             if (itemsList_)
710                 context.valueSchema = itemsList_;
711             else if (itemsTuple_) {
712                 if (context.arrayElementIndex < itemsTupleCount_)
713                     context.valueSchema = itemsTuple_[context.arrayElementIndex];
714                 else if (additionalItemsSchema_)
715                     context.valueSchema = additionalItemsSchema_;
716                 else if (additionalItems_)
717                     context.valueSchema = typeless_;
718                 else {
719                     context.error_handler.DisallowedItem(context.arrayElementIndex);
720                     // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
721                     context.valueSchema = typeless_;
722                     // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
723                     context.arrayElementIndex++;
724                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
725                 }
726             }
727             else
728                 context.valueSchema = typeless_;
729 
730             context.arrayElementIndex++;
731         }
732         return true;
733     }
734 
EndValue(Context & context)735     RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
736         if (context.patternPropertiesValidatorCount > 0) {
737             bool otherValid = false;
738             SizeType count = context.patternPropertiesValidatorCount;
739             if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
740                 otherValid = context.patternPropertiesValidators[--count]->IsValid();
741 
742             bool patternValid = true;
743             for (SizeType i = 0; i < count; i++)
744                 if (!context.patternPropertiesValidators[i]->IsValid()) {
745                     patternValid = false;
746                     break;
747                 }
748 
749             if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
750                 if (!patternValid) {
751                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
752                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
753                 }
754             }
755             else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
756                 if (!patternValid || !otherValid) {
757                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
758                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
759                 }
760             }
761             else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
762                 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
763                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
764             }
765         }
766 
767         // For enums only check if we have a hasher
768         if (enum_ && context.hasher) {
769             const uint64_t h = context.factory.GetHashCode(context.hasher);
770             for (SizeType i = 0; i < enumCount_; i++)
771                 if (enum_[i] == h)
772                     goto foundEnum;
773             context.error_handler.DisallowedValue(kValidateErrorEnum);
774             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
775             foundEnum:;
776         }
777 
778         if (allOf_.schemas)
779             for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
780                 if (!context.validators[i]->IsValid()) {
781                     context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
782                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
783                 }
784 
785         if (anyOf_.schemas) {
786             for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
787                 if (context.validators[i]->IsValid())
788                     goto foundAny;
789             context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
790             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
791             foundAny:;
792         }
793 
794         if (oneOf_.schemas) {
795             bool oneValid = false;
796             for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
797                 if (context.validators[i]->IsValid()) {
798                     if (oneValid) {
799                         context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, true);
800                         RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
801                     } else
802                         oneValid = true;
803                 }
804             if (!oneValid) {
805                 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count, false);
806                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
807             }
808         }
809 
810         if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
811             context.error_handler.Disallowed();
812             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
813         }
814 
815         return true;
816     }
817 
Null(Context & context)818     bool Null(Context& context) const {
819         if (!(type_ & (1 << kNullSchemaType))) {
820             DisallowedType(context, GetNullString());
821             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
822         }
823         return CreateParallelValidator(context);
824     }
825 
Bool(Context & context,bool)826     bool Bool(Context& context, bool) const {
827         if (!(type_ & (1 << kBooleanSchemaType))) {
828             DisallowedType(context, GetBooleanString());
829             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
830         }
831         return CreateParallelValidator(context);
832     }
833 
Int(Context & context,int i)834     bool Int(Context& context, int i) const {
835         if (!CheckInt(context, i))
836             return false;
837         return CreateParallelValidator(context);
838     }
839 
Uint(Context & context,unsigned u)840     bool Uint(Context& context, unsigned u) const {
841         if (!CheckUint(context, u))
842             return false;
843         return CreateParallelValidator(context);
844     }
845 
Int64(Context & context,int64_t i)846     bool Int64(Context& context, int64_t i) const {
847         if (!CheckInt(context, i))
848             return false;
849         return CreateParallelValidator(context);
850     }
851 
Uint64(Context & context,uint64_t u)852     bool Uint64(Context& context, uint64_t u) const {
853         if (!CheckUint(context, u))
854             return false;
855         return CreateParallelValidator(context);
856     }
857 
Double(Context & context,double d)858     bool Double(Context& context, double d) const {
859         if (!(type_ & (1 << kNumberSchemaType))) {
860             DisallowedType(context, GetNumberString());
861             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
862         }
863 
864         if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
865             return false;
866 
867         if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
868             return false;
869 
870         if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
871             return false;
872 
873         return CreateParallelValidator(context);
874     }
875 
String(Context & context,const Ch * str,SizeType length,bool)876     bool String(Context& context, const Ch* str, SizeType length, bool) const {
877         if (!(type_ & (1 << kStringSchemaType))) {
878             DisallowedType(context, GetStringString());
879             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
880         }
881 
882         if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
883             SizeType count;
884             if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
885                 if (count < minLength_) {
886                     context.error_handler.TooShort(str, length, minLength_);
887                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
888                 }
889                 if (count > maxLength_) {
890                     context.error_handler.TooLong(str, length, maxLength_);
891                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
892                 }
893             }
894         }
895 
896         if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
897             context.error_handler.DoesNotMatch(str, length);
898             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
899         }
900 
901         return CreateParallelValidator(context);
902     }
903 
StartObject(Context & context)904     bool StartObject(Context& context) const {
905         if (!(type_ & (1 << kObjectSchemaType))) {
906             DisallowedType(context, GetObjectString());
907             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
908         }
909 
910         if (hasDependencies_ || hasRequired_) {
911             context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
912             std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
913         }
914 
915         if (patternProperties_) { // pre-allocate schema array
916             SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
917             context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
918             context.patternPropertiesSchemaCount = 0;
919             std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
920         }
921 
922         return CreateParallelValidator(context);
923     }
924 
Key(Context & context,const Ch * str,SizeType len,bool)925     bool Key(Context& context, const Ch* str, SizeType len, bool) const {
926         if (patternProperties_) {
927             context.patternPropertiesSchemaCount = 0;
928             for (SizeType i = 0; i < patternPropertyCount_; i++)
929                 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
930                     context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
931                     context.valueSchema = typeless_;
932                 }
933         }
934 
935         SizeType index  = 0;
936         if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
937             if (context.patternPropertiesSchemaCount > 0) {
938                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
939                 context.valueSchema = typeless_;
940                 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
941             }
942             else
943                 context.valueSchema = properties_[index].schema;
944 
945             if (context.propertyExist)
946                 context.propertyExist[index] = true;
947 
948             return true;
949         }
950 
951         if (additionalPropertiesSchema_) {
952             if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
953                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
954                 context.valueSchema = typeless_;
955                 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
956             }
957             else
958                 context.valueSchema = additionalPropertiesSchema_;
959             return true;
960         }
961         else if (additionalProperties_) {
962             context.valueSchema = typeless_;
963             return true;
964         }
965 
966         if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
967             // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
968             context.valueSchema = typeless_;
969             context.error_handler.DisallowedProperty(str, len);
970             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
971         }
972 
973         return true;
974     }
975 
EndObject(Context & context,SizeType memberCount)976     bool EndObject(Context& context, SizeType memberCount) const {
977         if (hasRequired_) {
978             context.error_handler.StartMissingProperties();
979             for (SizeType index = 0; index < propertyCount_; index++)
980                 if (properties_[index].required && !context.propertyExist[index])
981                     if (properties_[index].schema->defaultValueLength_ == 0 )
982                         context.error_handler.AddMissingProperty(properties_[index].name);
983             if (context.error_handler.EndMissingProperties())
984                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
985         }
986 
987         if (memberCount < minProperties_) {
988             context.error_handler.TooFewProperties(memberCount, minProperties_);
989             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
990         }
991 
992         if (memberCount > maxProperties_) {
993             context.error_handler.TooManyProperties(memberCount, maxProperties_);
994             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
995         }
996 
997         if (hasDependencies_) {
998             context.error_handler.StartDependencyErrors();
999             for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1000                 const Property& source = properties_[sourceIndex];
1001                 if (context.propertyExist[sourceIndex]) {
1002                     if (source.dependencies) {
1003                         context.error_handler.StartMissingDependentProperties();
1004                         for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1005                             if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1006                                 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1007                         context.error_handler.EndMissingDependentProperties(source.name);
1008                     }
1009                     else if (source.dependenciesSchema) {
1010                         ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1011                         if (!dependenciesValidator->IsValid())
1012                             context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1013                     }
1014                 }
1015             }
1016             if (context.error_handler.EndDependencyErrors())
1017                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
1018         }
1019 
1020         return true;
1021     }
1022 
StartArray(Context & context)1023     bool StartArray(Context& context) const {
1024         context.arrayElementIndex = 0;
1025         context.inArray = true;  // Ensure we note that we are in an array
1026 
1027         if (!(type_ & (1 << kArraySchemaType))) {
1028             DisallowedType(context, GetArrayString());
1029             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1030         }
1031 
1032         return CreateParallelValidator(context);
1033     }
1034 
EndArray(Context & context,SizeType elementCount)1035     bool EndArray(Context& context, SizeType elementCount) const {
1036         context.inArray = false;
1037 
1038         if (elementCount < minItems_) {
1039             context.error_handler.TooFewItems(elementCount, minItems_);
1040             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
1041         }
1042 
1043         if (elementCount > maxItems_) {
1044             context.error_handler.TooManyItems(elementCount, maxItems_);
1045             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
1046         }
1047 
1048         return true;
1049     }
1050 
GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)1051     static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
1052         switch (validateErrorCode) {
1053             case kValidateErrorMultipleOf:              return GetMultipleOfString();
1054             case kValidateErrorMaximum:                 return GetMaximumString();
1055             case kValidateErrorExclusiveMaximum:        return GetMaximumString(); // Same
1056             case kValidateErrorMinimum:                 return GetMinimumString();
1057             case kValidateErrorExclusiveMinimum:        return GetMinimumString(); // Same
1058 
1059             case kValidateErrorMaxLength:               return GetMaxLengthString();
1060             case kValidateErrorMinLength:               return GetMinLengthString();
1061             case kValidateErrorPattern:                 return GetPatternString();
1062 
1063             case kValidateErrorMaxItems:                return GetMaxItemsString();
1064             case kValidateErrorMinItems:                return GetMinItemsString();
1065             case kValidateErrorUniqueItems:             return GetUniqueItemsString();
1066             case kValidateErrorAdditionalItems:         return GetAdditionalItemsString();
1067 
1068             case kValidateErrorMaxProperties:           return GetMaxPropertiesString();
1069             case kValidateErrorMinProperties:           return GetMinPropertiesString();
1070             case kValidateErrorRequired:                return GetRequiredString();
1071             case kValidateErrorAdditionalProperties:    return GetAdditionalPropertiesString();
1072             case kValidateErrorPatternProperties:       return GetPatternPropertiesString();
1073             case kValidateErrorDependencies:            return GetDependenciesString();
1074 
1075             case kValidateErrorEnum:                    return GetEnumString();
1076             case kValidateErrorType:                    return GetTypeString();
1077 
1078             case kValidateErrorOneOf:                   return GetOneOfString();
1079             case kValidateErrorOneOfMatch:              return GetOneOfString(); // Same
1080             case kValidateErrorAllOf:                   return GetAllOfString();
1081             case kValidateErrorAnyOf:                   return GetAnyOfString();
1082             case kValidateErrorNot:                     return GetNotString();
1083 
1084             default:                                    return GetNullString();
1085         }
1086     }
1087 
1088 
1089     // Generate functions for string literal according to Ch
1090 #define RAPIDJSON_STRING_(name, ...) \
1091     static const ValueType& Get##name##String() {\
1092         static const Ch s[] = { __VA_ARGS__, '\0' };\
1093         static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1094         return v;\
1095     }
1096 
1097     RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1098     RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1099     RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1100     RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1101     RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1102     RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1103     RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1104     RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1105     RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1106     RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1107     RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1108     RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1109     RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1110     RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1111     RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1112     RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1113     RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1114     RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1115     RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1116     RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1117     RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1118     RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1119     RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1120     RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1121     RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1122     RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1123     RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1124     RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1125     RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1126     RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1127     RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1128     RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1129     RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1130     RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1131 
1132 #undef RAPIDJSON_STRING_
1133 
1134 private:
1135     enum SchemaValueType {
1136         kNullSchemaType,
1137         kBooleanSchemaType,
1138         kObjectSchemaType,
1139         kArraySchemaType,
1140         kStringSchemaType,
1141         kNumberSchemaType,
1142         kIntegerSchemaType,
1143         kTotalSchemaType
1144     };
1145 
1146 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1147         typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1148 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1149         typedef std::basic_regex<Ch> RegexType;
1150 #else
1151         typedef char RegexType;
1152 #endif
1153 
1154     struct SchemaArray {
SchemaArraySchemaArray1155         SchemaArray() : schemas(), count() {}
~SchemaArraySchemaArray1156         ~SchemaArray() { AllocatorType::Free(schemas); }
1157         const SchemaType** schemas;
1158         SizeType begin; // begin index of context.validators
1159         SizeType count;
1160     };
1161 
1162     template <typename V1, typename V2>
AddUniqueElement(V1 & a,const V2 & v)1163     void AddUniqueElement(V1& a, const V2& v) {
1164         for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1165             if (*itr == v)
1166                 return;
1167         V1 c(v, *allocator_);
1168         a.PushBack(c, *allocator_);
1169     }
1170 
GetMember(const ValueType & value,const ValueType & name)1171     static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
1172         typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1173         return itr != value.MemberEnd() ? &(itr->value) : 0;
1174     }
1175 
AssignIfExist(bool & out,const ValueType & value,const ValueType & name)1176     static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
1177         if (const ValueType* v = GetMember(value, name))
1178             if (v->IsBool())
1179                 out = v->GetBool();
1180     }
1181 
AssignIfExist(SizeType & out,const ValueType & value,const ValueType & name)1182     static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
1183         if (const ValueType* v = GetMember(value, name))
1184             if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
1185                 out = static_cast<SizeType>(v->GetUint64());
1186     }
1187 
AssignIfExist(SchemaArray & out,SchemaDocumentType & schemaDocument,const PointerType & p,const ValueType & value,const ValueType & name,const ValueType & document)1188     void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
1189         if (const ValueType* v = GetMember(value, name)) {
1190             if (v->IsArray() && v->Size() > 0) {
1191                 PointerType q = p.Append(name, allocator_);
1192                 out.count = v->Size();
1193                 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
1194                 memset(out.schemas, 0, sizeof(Schema*)* out.count);
1195                 for (SizeType i = 0; i < out.count; i++)
1196                     schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1197                 out.begin = validatorCount_;
1198                 validatorCount_ += out.count;
1199             }
1200         }
1201     }
1202 
1203 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1204     template <typename ValueType>
CreatePattern(const ValueType & value)1205     RegexType* CreatePattern(const ValueType& value) {
1206         if (value.IsString()) {
1207             RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1208             if (!r->IsValid()) {
1209                 r->~RegexType();
1210                 AllocatorType::Free(r);
1211                 r = 0;
1212             }
1213             return r;
1214         }
1215         return 0;
1216     }
1217 
IsPatternMatch(const RegexType * pattern,const Ch * str,SizeType)1218     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1219         GenericRegexSearch<RegexType> rs(*pattern);
1220         return rs.Search(str);
1221     }
1222 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1223     template <typename ValueType>
CreatePattern(const ValueType & value)1224     RegexType* CreatePattern(const ValueType& value) {
1225         if (value.IsString()) {
1226             RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1227             try {
1228                 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1229             }
1230             catch (const std::regex_error&) {
1231                 AllocatorType::Free(r);
1232             }
1233         }
1234         return 0;
1235     }
1236 
IsPatternMatch(const RegexType * pattern,const Ch * str,SizeType length)1237     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1238         std::match_results<const Ch*> r;
1239         return std::regex_search(str, str + length, r, *pattern);
1240     }
1241 #else
1242     template <typename ValueType>
CreatePattern(const ValueType &)1243     RegexType* CreatePattern(const ValueType&) { return 0; }
1244 
IsPatternMatch(const RegexType *,const Ch *,SizeType)1245     static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1246 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1247 
AddType(const ValueType & type)1248     void AddType(const ValueType& type) {
1249         if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;
1250         else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1251         else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1252         else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;
1253         else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1254         else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1255         else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1256     }
1257 
CreateParallelValidator(Context & context)1258     bool CreateParallelValidator(Context& context) const {
1259         if (enum_ || context.arrayUniqueness)
1260             context.hasher = context.factory.CreateHasher();
1261 
1262         if (validatorCount_) {
1263             RAPIDJSON_ASSERT(context.validators == 0);
1264             context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1265             context.validatorCount = validatorCount_;
1266 
1267             // Always return after first failure for these sub-validators
1268             if (allOf_.schemas)
1269                 CreateSchemaValidators(context, allOf_, false);
1270 
1271             if (anyOf_.schemas)
1272                 CreateSchemaValidators(context, anyOf_, false);
1273 
1274             if (oneOf_.schemas)
1275                 CreateSchemaValidators(context, oneOf_, false);
1276 
1277             if (not_)
1278                 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
1279 
1280             if (hasSchemaDependencies_) {
1281                 for (SizeType i = 0; i < propertyCount_; i++)
1282                     if (properties_[i].dependenciesSchema)
1283                         context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
1284             }
1285         }
1286 
1287         return true;
1288     }
1289 
CreateSchemaValidators(Context & context,const SchemaArray & schemas,const bool inheritContinueOnErrors)1290     void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
1291         for (SizeType i = 0; i < schemas.count; i++)
1292             context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1293     }
1294 
1295     // O(n)
FindPropertyIndex(const ValueType & name,SizeType * outIndex)1296     bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
1297         SizeType len = name.GetStringLength();
1298         const Ch* str = name.GetString();
1299         for (SizeType index = 0; index < propertyCount_; index++)
1300             if (properties_[index].name.GetStringLength() == len &&
1301                 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1302             {
1303                 *outIndex = index;
1304                 return true;
1305             }
1306         return false;
1307     }
1308 
CheckInt(Context & context,int64_t i)1309     bool CheckInt(Context& context, int64_t i) const {
1310         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1311             DisallowedType(context, GetIntegerString());
1312             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1313         }
1314 
1315         if (!minimum_.IsNull()) {
1316             if (minimum_.IsInt64()) {
1317                 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1318                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1319                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1320                 }
1321             }
1322             else if (minimum_.IsUint64()) {
1323                 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1324                 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1325             }
1326             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1327                 return false;
1328         }
1329 
1330         if (!maximum_.IsNull()) {
1331             if (maximum_.IsInt64()) {
1332                 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1333                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1334                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1335                 }
1336             }
1337             else if (maximum_.IsUint64()) { }
1338                 /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1339             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1340                 return false;
1341         }
1342 
1343         if (!multipleOf_.IsNull()) {
1344             if (multipleOf_.IsUint64()) {
1345                 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1346                     context.error_handler.NotMultipleOf(i, multipleOf_);
1347                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1348                 }
1349             }
1350             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1351                 return false;
1352         }
1353 
1354         return true;
1355     }
1356 
CheckUint(Context & context,uint64_t i)1357     bool CheckUint(Context& context, uint64_t i) const {
1358         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1359             DisallowedType(context, GetIntegerString());
1360             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1361         }
1362 
1363         if (!minimum_.IsNull()) {
1364             if (minimum_.IsUint64()) {
1365                 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1366                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1367                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1368                 }
1369             }
1370             else if (minimum_.IsInt64())
1371                 /* do nothing */; // i >= 0 > minimum.Getint64()
1372             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1373                 return false;
1374         }
1375 
1376         if (!maximum_.IsNull()) {
1377             if (maximum_.IsUint64()) {
1378                 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1379                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1380                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1381                 }
1382             }
1383             else if (maximum_.IsInt64()) {
1384                 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1385                 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
1386             }
1387             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1388                 return false;
1389         }
1390 
1391         if (!multipleOf_.IsNull()) {
1392             if (multipleOf_.IsUint64()) {
1393                 if (i % multipleOf_.GetUint64() != 0) {
1394                     context.error_handler.NotMultipleOf(i, multipleOf_);
1395                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1396                 }
1397             }
1398             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1399                 return false;
1400         }
1401 
1402         return true;
1403     }
1404 
CheckDoubleMinimum(Context & context,double d)1405     bool CheckDoubleMinimum(Context& context, double d) const {
1406         if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1407             context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1408             RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1409         }
1410         return true;
1411     }
1412 
CheckDoubleMaximum(Context & context,double d)1413     bool CheckDoubleMaximum(Context& context, double d) const {
1414         if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1415             context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1416             RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1417         }
1418         return true;
1419     }
1420 
CheckDoubleMultipleOf(Context & context,double d)1421     bool CheckDoubleMultipleOf(Context& context, double d) const {
1422         double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1423         double q = std::floor(a / b);
1424         double r = a - q * b;
1425         if (r > 0.0) {
1426             context.error_handler.NotMultipleOf(d, multipleOf_);
1427             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1428         }
1429         return true;
1430     }
1431 
DisallowedType(Context & context,const ValueType & actualType)1432     void DisallowedType(Context& context, const ValueType& actualType) const {
1433         ErrorHandler& eh = context.error_handler;
1434         eh.StartDisallowedType();
1435 
1436         if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1437         if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1438         if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1439         if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1440         if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1441 
1442         if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1443         else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1444 
1445         eh.EndDisallowedType(actualType);
1446     }
1447 
1448     struct Property {
PropertyProperty1449         Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
~PropertyProperty1450         ~Property() { AllocatorType::Free(dependencies); }
1451         SValue name;
1452         const SchemaType* schema;
1453         const SchemaType* dependenciesSchema;
1454         SizeType dependenciesValidatorIndex;
1455         bool* dependencies;
1456         bool required;
1457     };
1458 
1459     struct PatternProperty {
PatternPropertyPatternProperty1460         PatternProperty() : schema(), pattern() {}
~PatternPropertyPatternProperty1461         ~PatternProperty() {
1462             if (pattern) {
1463                 pattern->~RegexType();
1464                 AllocatorType::Free(pattern);
1465             }
1466         }
1467         const SchemaType* schema;
1468         RegexType* pattern;
1469     };
1470 
1471     AllocatorType* allocator_;
1472     SValue uri_;
1473     PointerType pointer_;
1474     const SchemaType* typeless_;
1475     uint64_t* enum_;
1476     SizeType enumCount_;
1477     SchemaArray allOf_;
1478     SchemaArray anyOf_;
1479     SchemaArray oneOf_;
1480     const SchemaType* not_;
1481     unsigned type_; // bitmask of kSchemaType
1482     SizeType validatorCount_;
1483     SizeType notValidatorIndex_;
1484 
1485     Property* properties_;
1486     const SchemaType* additionalPropertiesSchema_;
1487     PatternProperty* patternProperties_;
1488     SizeType patternPropertyCount_;
1489     SizeType propertyCount_;
1490     SizeType minProperties_;
1491     SizeType maxProperties_;
1492     bool additionalProperties_;
1493     bool hasDependencies_;
1494     bool hasRequired_;
1495     bool hasSchemaDependencies_;
1496 
1497     const SchemaType* additionalItemsSchema_;
1498     const SchemaType* itemsList_;
1499     const SchemaType** itemsTuple_;
1500     SizeType itemsTupleCount_;
1501     SizeType minItems_;
1502     SizeType maxItems_;
1503     bool additionalItems_;
1504     bool uniqueItems_;
1505 
1506     RegexType* pattern_;
1507     SizeType minLength_;
1508     SizeType maxLength_;
1509 
1510     SValue minimum_;
1511     SValue maximum_;
1512     SValue multipleOf_;
1513     bool exclusiveMinimum_;
1514     bool exclusiveMaximum_;
1515 
1516     SizeType defaultValueLength_;
1517 };
1518 
1519 template<typename Stack, typename Ch>
1520 struct TokenHelper {
AppendIndexTokenTokenHelper1521     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1522         *documentStack.template Push<Ch>() = '/';
1523         char buffer[21];
1524         size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1525         for (size_t i = 0; i < length; i++)
1526             *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1527     }
1528 };
1529 
1530 // Partial specialized version for char to prevent buffer copying.
1531 template <typename Stack>
1532 struct TokenHelper<Stack, char> {
1533     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1534         if (sizeof(SizeType) == 4) {
1535             char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1536             *buffer++ = '/';
1537             const char* end = internal::u32toa(index, buffer);
1538              documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1539         }
1540         else {
1541             char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1542             *buffer++ = '/';
1543             const char* end = internal::u64toa(index, buffer);
1544             documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1545         }
1546     }
1547 };
1548 
1549 } // namespace internal
1550 
1551 ///////////////////////////////////////////////////////////////////////////////
1552 // IGenericRemoteSchemaDocumentProvider
1553 
1554 template <typename SchemaDocumentType>
1555 class IGenericRemoteSchemaDocumentProvider {
1556 public:
1557     typedef typename SchemaDocumentType::Ch Ch;
1558 
1559     virtual ~IGenericRemoteSchemaDocumentProvider() {}
1560     virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1561 };
1562 
1563 ///////////////////////////////////////////////////////////////////////////////
1564 // GenericSchemaDocument
1565 
1566 //! JSON schema document.
1567 /*!
1568     A JSON schema document is a compiled version of a JSON schema.
1569     It is basically a tree of internal::Schema.
1570 
1571     \note This is an immutable class (i.e. its instance cannot be modified after construction).
1572     \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1573     \tparam Allocator Allocator type for allocating memory of this document.
1574 */
1575 template <typename ValueT, typename Allocator = CrtAllocator>
1576 class GenericSchemaDocument {
1577 public:
1578     typedef ValueT ValueType;
1579     typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1580     typedef Allocator AllocatorType;
1581     typedef typename ValueType::EncodingType EncodingType;
1582     typedef typename EncodingType::Ch Ch;
1583     typedef internal::Schema<GenericSchemaDocument> SchemaType;
1584     typedef GenericPointer<ValueType, Allocator> PointerType;
1585     typedef GenericValue<EncodingType, Allocator> URIType;
1586     friend class internal::Schema<GenericSchemaDocument>;
1587     template <typename, typename, typename>
1588     friend class GenericSchemaValidator;
1589 
1590     //! Constructor.
1591     /*!
1592         Compile a JSON document into schema document.
1593 
1594         \param document A JSON document as source.
1595         \param uri The base URI of this schema document for purposes of violation reporting.
1596         \param uriLength Length of \c name, in code points.
1597         \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1598         \param allocator An optional allocator instance for allocating memory. Can be null.
1599     */
1600     explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
1601         IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1602         remoteProvider_(remoteProvider),
1603         allocator_(allocator),
1604         ownAllocator_(),
1605         root_(),
1606         typeless_(),
1607         schemaMap_(allocator, kInitialSchemaMapSize),
1608         schemaRef_(allocator, kInitialSchemaRefSize)
1609     {
1610         if (!allocator_)
1611             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1612 
1613         Ch noUri[1] = {0};
1614         uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1615 
1616         typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1617         new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_);
1618 
1619         // Generate root schema, it will call CreateSchema() to create sub-schemas,
1620         // And call AddRefSchema() if there are $ref.
1621         CreateSchemaRecursive(&root_, PointerType(), document, document);
1622 
1623         // Resolve $ref
1624         while (!schemaRef_.Empty()) {
1625             SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1626             if (const SchemaType* s = GetSchema(refEntry->target)) {
1627                 if (refEntry->schema)
1628                     *refEntry->schema = s;
1629 
1630                 // Create entry in map if not exist
1631                 if (!GetSchema(refEntry->source)) {
1632                     new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
1633                 }
1634             }
1635             else if (refEntry->schema)
1636                 *refEntry->schema = typeless_;
1637 
1638             refEntry->~SchemaRefEntry();
1639         }
1640 
1641         RAPIDJSON_ASSERT(root_ != 0);
1642 
1643         schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1644     }
1645 
1646 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1647     //! Move constructor in C++11
1648     GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1649         remoteProvider_(rhs.remoteProvider_),
1650         allocator_(rhs.allocator_),
1651         ownAllocator_(rhs.ownAllocator_),
1652         root_(rhs.root_),
1653         typeless_(rhs.typeless_),
1654         schemaMap_(std::move(rhs.schemaMap_)),
1655         schemaRef_(std::move(rhs.schemaRef_)),
1656         uri_(std::move(rhs.uri_))
1657     {
1658         rhs.remoteProvider_ = 0;
1659         rhs.allocator_ = 0;
1660         rhs.ownAllocator_ = 0;
1661         rhs.typeless_ = 0;
1662     }
1663 #endif
1664 
1665     //! Destructor
1666     ~GenericSchemaDocument() {
1667         while (!schemaMap_.Empty())
1668             schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1669 
1670         if (typeless_) {
1671             typeless_->~SchemaType();
1672             Allocator::Free(typeless_);
1673         }
1674 
1675         RAPIDJSON_DELETE(ownAllocator_);
1676     }
1677 
1678     const URIType& GetURI() const { return uri_; }
1679 
1680     //! Get the root schema.
1681     const SchemaType& GetRoot() const { return *root_; }
1682 
1683 private:
1684     //! Prohibit copying
1685     GenericSchemaDocument(const GenericSchemaDocument&);
1686     //! Prohibit assignment
1687     GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1688 
1689     struct SchemaRefEntry {
1690         SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1691         PointerType source;
1692         PointerType target;
1693         const SchemaType** schema;
1694     };
1695 
1696     struct SchemaEntry {
1697         SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1698         ~SchemaEntry() {
1699             if (owned) {
1700                 schema->~SchemaType();
1701                 Allocator::Free(schema);
1702             }
1703         }
1704         PointerType pointer;
1705         SchemaType* schema;
1706         bool owned;
1707     };
1708 
1709     void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1710         if (schema)
1711             *schema = typeless_;
1712 
1713         if (v.GetType() == kObjectType) {
1714             const SchemaType* s = GetSchema(pointer);
1715             if (!s)
1716                 CreateSchema(schema, pointer, v, document);
1717 
1718             for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1719                 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1720         }
1721         else if (v.GetType() == kArrayType)
1722             for (SizeType i = 0; i < v.Size(); i++)
1723                 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1724     }
1725 
1726     void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1727         RAPIDJSON_ASSERT(pointer.IsValid());
1728         if (v.IsObject()) {
1729             if (!HandleRefSchema(pointer, schema, v, document)) {
1730                 SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
1731                 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
1732                 if (schema)
1733                     *schema = s;
1734             }
1735         }
1736     }
1737 
1738     bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
1739         static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
1740         static const ValueType kRefValue(kRefString, 4);
1741 
1742         typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1743         if (itr == v.MemberEnd())
1744             return false;
1745 
1746         if (itr->value.IsString()) {
1747             SizeType len = itr->value.GetStringLength();
1748             if (len > 0) {
1749                 const Ch* s = itr->value.GetString();
1750                 SizeType i = 0;
1751                 while (i < len && s[i] != '#') // Find the first #
1752                     i++;
1753 
1754                 if (i > 0) { // Remote reference, resolve immediately
1755                     if (remoteProvider_) {
1756                         if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1757                             PointerType pointer(&s[i], len - i, allocator_);
1758                             if (pointer.IsValid()) {
1759                                 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1760                                     if (schema)
1761                                         *schema = sc;
1762                                     new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_);
1763                                     return true;
1764                                 }
1765                             }
1766                         }
1767                     }
1768                 }
1769                 else if (s[i] == '#') { // Local reference, defer resolution
1770                     PointerType pointer(&s[i], len - i, allocator_);
1771                     if (pointer.IsValid()) {
1772                         if (const ValueType* nv = pointer.Get(document))
1773                             if (HandleRefSchema(source, schema, *nv, document))
1774                                 return true;
1775 
1776                         new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1777                         return true;
1778                     }
1779                 }
1780             }
1781         }
1782         return false;
1783     }
1784 
1785     const SchemaType* GetSchema(const PointerType& pointer) const {
1786         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1787             if (pointer == target->pointer)
1788                 return target->schema;
1789         return 0;
1790     }
1791 
1792     PointerType GetPointer(const SchemaType* schema) const {
1793         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1794             if (schema == target->schema)
1795                 return target->pointer;
1796         return PointerType();
1797     }
1798 
1799     const SchemaType* GetTypeless() const { return typeless_; }
1800 
1801     static const size_t kInitialSchemaMapSize = 64;
1802     static const size_t kInitialSchemaRefSize = 64;
1803 
1804     IRemoteSchemaDocumentProviderType* remoteProvider_;
1805     Allocator *allocator_;
1806     Allocator *ownAllocator_;
1807     const SchemaType* root_;                //!< Root schema.
1808     SchemaType* typeless_;
1809     internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas
1810     internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref
1811     URIType uri_;
1812 };
1813 
1814 //! GenericSchemaDocument using Value type.
1815 typedef GenericSchemaDocument<Value> SchemaDocument;
1816 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
1817 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
1818 
1819 ///////////////////////////////////////////////////////////////////////////////
1820 // GenericSchemaValidator
1821 
1822 //! JSON Schema Validator.
1823 /*!
1824     A SAX style JSON schema validator.
1825     It uses a \c GenericSchemaDocument to validate SAX events.
1826     It delegates the incoming SAX events to an output handler.
1827     The default output handler does nothing.
1828     It can be reused multiple times by calling \c Reset().
1829 
1830     \tparam SchemaDocumentType Type of schema document.
1831     \tparam OutputHandler Type of output handler. Default handler does nothing.
1832     \tparam StateAllocator Allocator for storing the internal validation states.
1833 */
1834 template <
1835     typename SchemaDocumentType,
1836     typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
1837     typename StateAllocator = CrtAllocator>
1838 class GenericSchemaValidator :
1839     public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1840     public internal::ISchemaValidator,
1841     public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
1842 public:
1843     typedef typename SchemaDocumentType::SchemaType SchemaType;
1844     typedef typename SchemaDocumentType::PointerType PointerType;
1845     typedef typename SchemaType::EncodingType EncodingType;
1846     typedef typename SchemaType::SValue SValue;
1847     typedef typename EncodingType::Ch Ch;
1848     typedef GenericStringRef<Ch> StringRefType;
1849     typedef GenericValue<EncodingType, StateAllocator> ValueType;
1850 
1851     //! Constructor without output handler.
1852     /*!
1853         \param schemaDocument The schema document to conform to.
1854         \param allocator Optional allocator for storing internal validation states.
1855         \param schemaStackCapacity Optional initial capacity of schema path stack.
1856         \param documentStackCapacity Optional initial capacity of document path stack.
1857     */
1858     GenericSchemaValidator(
1859         const SchemaDocumentType& schemaDocument,
1860         StateAllocator* allocator = 0,
1861         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1862         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1863         :
1864         schemaDocument_(&schemaDocument),
1865         root_(schemaDocument.GetRoot()),
1866         stateAllocator_(allocator),
1867         ownStateAllocator_(0),
1868         schemaStack_(allocator, schemaStackCapacity),
1869         documentStack_(allocator, documentStackCapacity),
1870         outputHandler_(0),
1871         error_(kObjectType),
1872         currentError_(),
1873         missingDependents_(),
1874         valid_(true),
1875         flags_(kValidateDefaultFlags)
1876 #if RAPIDJSON_SCHEMA_VERBOSE
1877         , depth_(0)
1878 #endif
1879     {
1880     }
1881 
1882     //! Constructor with output handler.
1883     /*!
1884         \param schemaDocument The schema document to conform to.
1885         \param allocator Optional allocator for storing internal validation states.
1886         \param schemaStackCapacity Optional initial capacity of schema path stack.
1887         \param documentStackCapacity Optional initial capacity of document path stack.
1888     */
1889     GenericSchemaValidator(
1890         const SchemaDocumentType& schemaDocument,
1891         OutputHandler& outputHandler,
1892         StateAllocator* allocator = 0,
1893         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1894         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1895         :
1896         schemaDocument_(&schemaDocument),
1897         root_(schemaDocument.GetRoot()),
1898         stateAllocator_(allocator),
1899         ownStateAllocator_(0),
1900         schemaStack_(allocator, schemaStackCapacity),
1901         documentStack_(allocator, documentStackCapacity),
1902         outputHandler_(&outputHandler),
1903         error_(kObjectType),
1904         currentError_(),
1905         missingDependents_(),
1906         valid_(true),
1907         flags_(kValidateDefaultFlags)
1908 #if RAPIDJSON_SCHEMA_VERBOSE
1909         , depth_(0)
1910 #endif
1911     {
1912     }
1913 
1914     //! Destructor.
1915     ~GenericSchemaValidator() {
1916         Reset();
1917         RAPIDJSON_DELETE(ownStateAllocator_);
1918     }
1919 
1920     //! Reset the internal states.
1921     void Reset() {
1922         while (!schemaStack_.Empty())
1923             PopSchema();
1924         documentStack_.Clear();
1925         ResetError();
1926     }
1927 
1928     //! Reset the error state.
1929     void ResetError() {
1930         error_.SetObject();
1931         currentError_.SetNull();
1932         missingDependents_.SetNull();
1933         valid_ = true;
1934     }
1935 
1936     //! Implementation of ISchemaValidator
1937     void SetValidateFlags(unsigned flags) {
1938         flags_ = flags;
1939     }
1940     virtual unsigned GetValidateFlags() const {
1941         return flags_;
1942     }
1943 
1944     //! Checks whether the current state is valid.
1945     // Implementation of ISchemaValidator
1946     virtual bool IsValid() const {
1947         if (!valid_) return false;
1948         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
1949         return true;
1950     }
1951 
1952     //! Gets the error object.
1953     ValueType& GetError() { return error_; }
1954     const ValueType& GetError() const { return error_; }
1955 
1956     //! Gets the JSON pointer pointed to the invalid schema.
1957     //  If reporting all errors, the stack will be empty.
1958     PointerType GetInvalidSchemaPointer() const {
1959         return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1960     }
1961 
1962     //! Gets the keyword of invalid schema.
1963     //  If reporting all errors, the stack will be empty, so return "errors".
1964     const Ch* GetInvalidSchemaKeyword() const {
1965         if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
1966         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return (const Ch*)GetErrorsString();
1967         return 0;
1968     }
1969 
1970     //! Gets the error code of invalid schema.
1971     //  If reporting all errors, the stack will be empty, so return kValidateErrors.
1972     ValidateErrorCode GetInvalidSchemaCode() const {
1973         if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
1974         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
1975         return kValidateErrorNone;
1976     }
1977 
1978     //! Gets the JSON pointer pointed to the invalid value.
1979     //  If reporting all errors, the stack will be empty.
1980     PointerType GetInvalidDocumentPointer() const {
1981         if (documentStack_.Empty()) {
1982             return PointerType();
1983         }
1984         else {
1985             return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1986         }
1987     }
1988 
1989     void NotMultipleOf(int64_t actual, const SValue& expected) {
1990         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1991     }
1992     void NotMultipleOf(uint64_t actual, const SValue& expected) {
1993         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1994     }
1995     void NotMultipleOf(double actual, const SValue& expected) {
1996         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
1997     }
1998     void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
1999         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2000             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2001     }
2002     void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
2003         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2004             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2005     }
2006     void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
2007         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2008             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2009     }
2010     void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
2011         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2012             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2013     }
2014     void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
2015         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2016             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2017     }
2018     void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
2019         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2020             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2021     }
2022 
2023     void TooLong(const Ch* str, SizeType length, SizeType expected) {
2024         AddNumberError(kValidateErrorMaxLength,
2025             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2026     }
2027     void TooShort(const Ch* str, SizeType length, SizeType expected) {
2028         AddNumberError(kValidateErrorMinLength,
2029             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2030     }
2031     void DoesNotMatch(const Ch* str, SizeType length) {
2032         currentError_.SetObject();
2033         currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2034         AddCurrentError(kValidateErrorPattern);
2035     }
2036 
2037     void DisallowedItem(SizeType index) {
2038         currentError_.SetObject();
2039         currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2040         AddCurrentError(kValidateErrorAdditionalItems, true);
2041     }
2042     void TooFewItems(SizeType actualCount, SizeType expectedCount) {
2043         AddNumberError(kValidateErrorMinItems,
2044             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2045     }
2046     void TooManyItems(SizeType actualCount, SizeType expectedCount) {
2047         AddNumberError(kValidateErrorMaxItems,
2048             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2049     }
2050     void DuplicateItems(SizeType index1, SizeType index2) {
2051         ValueType duplicates(kArrayType);
2052         duplicates.PushBack(index1, GetStateAllocator());
2053         duplicates.PushBack(index2, GetStateAllocator());
2054         currentError_.SetObject();
2055         currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2056         AddCurrentError(kValidateErrorUniqueItems, true);
2057     }
2058 
2059     void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
2060         AddNumberError(kValidateErrorMaxProperties,
2061             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2062     }
2063     void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
2064         AddNumberError(kValidateErrorMinProperties,
2065             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2066     }
2067     void StartMissingProperties() {
2068         currentError_.SetArray();
2069     }
2070     void AddMissingProperty(const SValue& name) {
2071         currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2072     }
2073     bool EndMissingProperties() {
2074         if (currentError_.Empty())
2075             return false;
2076         ValueType error(kObjectType);
2077         error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2078         currentError_ = error;
2079         AddCurrentError(kValidateErrorRequired);
2080         return true;
2081     }
2082     void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
2083         for (SizeType i = 0; i < count; ++i)
2084             MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2085     }
2086     void DisallowedProperty(const Ch* name, SizeType length) {
2087         currentError_.SetObject();
2088         currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2089         AddCurrentError(kValidateErrorAdditionalProperties, true);
2090     }
2091 
2092     void StartDependencyErrors() {
2093         currentError_.SetObject();
2094     }
2095     void StartMissingDependentProperties() {
2096         missingDependents_.SetArray();
2097     }
2098     void AddMissingDependentProperty(const SValue& targetName) {
2099         missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2100     }
2101     void EndMissingDependentProperties(const SValue& sourceName) {
2102         if (!missingDependents_.Empty()) {
2103             // Create equivalent 'required' error
2104             ValueType error(kObjectType);
2105             ValidateErrorCode code = kValidateErrorRequired;
2106             error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2107             AddErrorCode(error, code);
2108             AddErrorInstanceLocation(error, false);
2109             // When appending to a pointer ensure its allocator is used
2110             PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2111             AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2112             ValueType wrapper(kObjectType);
2113             wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2114             currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2115         }
2116     }
2117     void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2118         currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2119             static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2120     }
2121     bool EndDependencyErrors() {
2122         if (currentError_.ObjectEmpty())
2123             return false;
2124         ValueType error(kObjectType);
2125         error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2126         currentError_ = error;
2127         AddCurrentError(kValidateErrorDependencies);
2128         return true;
2129     }
2130 
2131     void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
2132         currentError_.SetObject();
2133         AddCurrentError(code);
2134     }
2135     void StartDisallowedType() {
2136         currentError_.SetArray();
2137     }
2138     void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
2139         currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2140     }
2141     void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
2142         ValueType error(kObjectType);
2143         error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2144         error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2145         currentError_ = error;
2146         AddCurrentError(kValidateErrorType);
2147     }
2148     void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2149         // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
2150         AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2151         //for (SizeType i = 0; i < count; ++i) {
2152         //    MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2153         //}
2154     }
2155     void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2156         AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
2157     }
2158     void NotOneOf(ISchemaValidator** subvalidators, SizeType count, bool matched = false) {
2159         AddErrorArray(matched ? kValidateErrorOneOfMatch : kValidateErrorOneOf, subvalidators, count);
2160     }
2161     void Disallowed() {
2162         currentError_.SetObject();
2163         AddCurrentError(kValidateErrorNot);
2164     }
2165 
2166 #define RAPIDJSON_STRING_(name, ...) \
2167     static const StringRefType& Get##name##String() {\
2168         static const Ch s[] = { __VA_ARGS__, '\0' };\
2169         static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2170         return v;\
2171     }
2172 
2173     RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2174     RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2175     RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2176     RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2177     RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2178     RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2179     RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2180     RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2181     RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2182     RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2183 
2184 #undef RAPIDJSON_STRING_
2185 
2186 #if RAPIDJSON_SCHEMA_VERBOSE
2187 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2188 RAPIDJSON_MULTILINEMACRO_BEGIN\
2189     *documentStack_.template Push<Ch>() = '\0';\
2190     documentStack_.template Pop<Ch>(1);\
2191     internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2192 RAPIDJSON_MULTILINEMACRO_END
2193 #else
2194 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2195 #endif
2196 
2197 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2198     if (!valid_) return false; \
2199     if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2200         RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2201         return valid_ = false;\
2202     }
2203 
2204 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2205     for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2206         if (context->hasher)\
2207             static_cast<HasherType*>(context->hasher)->method arg2;\
2208         if (context->validators)\
2209             for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2210                 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2211         if (context->patternPropertiesValidators)\
2212             for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2213                 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2214     }
2215 
2216 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2217     valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2218     return valid_;
2219 
2220 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2221     RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\
2222     RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2223     RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)
2224 
2225     bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()), ( )); }
2226     bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }
2227     bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }
2228     bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }
2229     bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }
2230     bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2231     bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2232     bool RawNumber(const Ch* str, SizeType length, bool copy)
2233                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2234     bool String(const Ch* str, SizeType length, bool copy)
2235                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2236 
2237     bool StartObject() {
2238         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2239         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2240         return valid_ = !outputHandler_ || outputHandler_->StartObject();
2241     }
2242 
2243     bool Key(const Ch* str, SizeType len, bool copy) {
2244         if (!valid_) return false;
2245         AppendToken(str, len);
2246         if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) return valid_ = false;
2247         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2248         return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2249     }
2250 
2251     bool EndObject(SizeType memberCount) {
2252         if (!valid_) return false;
2253         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2254         if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) return valid_ = false;
2255         RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2256     }
2257 
2258     bool StartArray() {
2259         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2260         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2261         return valid_ = !outputHandler_ || outputHandler_->StartArray();
2262     }
2263 
2264     bool EndArray(SizeType elementCount) {
2265         if (!valid_) return false;
2266         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2267         if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) return valid_ = false;
2268         RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2269     }
2270 
2271 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2272 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2273 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2274 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2275 
2276     // Implementation of ISchemaStateFactory<SchemaType>
2277     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
2278         ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2279 #if RAPIDJSON_SCHEMA_VERBOSE
2280         depth_ + 1,
2281 #endif
2282         &GetStateAllocator());
2283         sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~(unsigned)kValidateContinueOnErrorFlag);
2284         return sv;
2285     }
2286 
2287     virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2288         GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
2289         v->~GenericSchemaValidator();
2290         StateAllocator::Free(v);
2291     }
2292 
2293     virtual void* CreateHasher() {
2294         return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
2295     }
2296 
2297     virtual uint64_t GetHashCode(void* hasher) {
2298         return static_cast<HasherType*>(hasher)->GetHashCode();
2299     }
2300 
2301     virtual void DestroryHasher(void* hasher) {
2302         HasherType* h = static_cast<HasherType*>(hasher);
2303         h->~HasherType();
2304         StateAllocator::Free(h);
2305     }
2306 
2307     virtual void* MallocState(size_t size) {
2308         return GetStateAllocator().Malloc(size);
2309     }
2310 
2311     virtual void FreeState(void* p) {
2312         StateAllocator::Free(p);
2313     }
2314 
2315 private:
2316     typedef typename SchemaType::Context Context;
2317     typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2318     typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2319 
2320     GenericSchemaValidator(
2321         const SchemaDocumentType& schemaDocument,
2322         const SchemaType& root,
2323         const char* basePath, size_t basePathSize,
2324 #if RAPIDJSON_SCHEMA_VERBOSE
2325         unsigned depth,
2326 #endif
2327         StateAllocator* allocator = 0,
2328         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2329         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2330         :
2331         schemaDocument_(&schemaDocument),
2332         root_(root),
2333         stateAllocator_(allocator),
2334         ownStateAllocator_(0),
2335         schemaStack_(allocator, schemaStackCapacity),
2336         documentStack_(allocator, documentStackCapacity),
2337         outputHandler_(0),
2338         error_(kObjectType),
2339         currentError_(),
2340         missingDependents_(),
2341         valid_(true),
2342         flags_(kValidateDefaultFlags)
2343 #if RAPIDJSON_SCHEMA_VERBOSE
2344         , depth_(depth)
2345 #endif
2346     {
2347         if (basePath && basePathSize)
2348             memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2349     }
2350 
2351     StateAllocator& GetStateAllocator() {
2352         if (!stateAllocator_)
2353             stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
2354         return *stateAllocator_;
2355     }
2356 
2357     bool GetContinueOnErrors() const {
2358         return flags_ & kValidateContinueOnErrorFlag;
2359     }
2360 
2361     bool BeginValue() {
2362         if (schemaStack_.Empty())
2363             PushSchema(root_);
2364         else {
2365             if (CurrentContext().inArray)
2366                 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2367 
2368             if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2369                 return false;
2370 
2371             SizeType count = CurrentContext().patternPropertiesSchemaCount;
2372             const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2373             typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2374             bool valueUniqueness = CurrentContext().valueUniqueness;
2375             RAPIDJSON_ASSERT(CurrentContext().valueSchema);
2376             PushSchema(*CurrentContext().valueSchema);
2377 
2378             if (count > 0) {
2379                 CurrentContext().objectPatternValidatorType = patternValidatorType;
2380                 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2381                 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2382                 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
2383                 for (SizeType i = 0; i < count; i++)
2384                     va[validatorCount++] = CreateSchemaValidator(*sa[i], true);  // Inherit continueOnError
2385             }
2386 
2387             CurrentContext().arrayUniqueness = valueUniqueness;
2388         }
2389         return true;
2390     }
2391 
2392     bool EndValue() {
2393         if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
2394             return false;
2395 
2396 #if RAPIDJSON_SCHEMA_VERBOSE
2397         GenericStringBuffer<EncodingType> sb;
2398         schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2399 
2400         *documentStack_.template Push<Ch>() = '\0';
2401         documentStack_.template Pop<Ch>(1);
2402         internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2403 #endif
2404         void* hasher = CurrentContext().hasher;
2405         uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
2406 
2407         PopSchema();
2408 
2409         if (!schemaStack_.Empty()) {
2410             Context& context = CurrentContext();
2411             // Only check uniqueness if there is a hasher
2412             if (hasher && context.valueUniqueness) {
2413                 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
2414                 if (!a)
2415                     CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
2416                 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
2417                     if (itr->GetUint64() == h) {
2418                         DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
2419                         // Cleanup before returning if continuing
2420                         if (GetContinueOnErrors()) {
2421                             a->PushBack(h, GetStateAllocator());
2422                             while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
2423                         }
2424                         RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
2425                     }
2426                 a->PushBack(h, GetStateAllocator());
2427             }
2428         }
2429 
2430         // Remove the last token of document pointer
2431         while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
2432             ;
2433 
2434         return true;
2435     }
2436 
2437     void AppendToken(const Ch* str, SizeType len) {
2438         documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
2439         *documentStack_.template PushUnsafe<Ch>() = '/';
2440         for (SizeType i = 0; i < len; i++) {
2441             if (str[i] == '~') {
2442                 *documentStack_.template PushUnsafe<Ch>() = '~';
2443                 *documentStack_.template PushUnsafe<Ch>() = '0';
2444             }
2445             else if (str[i] == '/') {
2446                 *documentStack_.template PushUnsafe<Ch>() = '~';
2447                 *documentStack_.template PushUnsafe<Ch>() = '1';
2448             }
2449             else
2450                 *documentStack_.template PushUnsafe<Ch>() = str[i];
2451         }
2452     }
2453 
2454     RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); }
2455 
2456     RAPIDJSON_FORCEINLINE void PopSchema() {
2457         Context* c = schemaStack_.template Pop<Context>(1);
2458         if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
2459             a->~HashCodeArray();
2460             StateAllocator::Free(a);
2461         }
2462         c->~Context();
2463     }
2464 
2465     void AddErrorInstanceLocation(ValueType& result, bool parent) {
2466         GenericStringBuffer<EncodingType> sb;
2467         PointerType instancePointer = GetInvalidDocumentPointer();
2468         ((parent && instancePointer.GetTokenCount() > 0)
2469          ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2470          : instancePointer).StringifyUriFragment(sb);
2471         ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2472                               GetStateAllocator());
2473         result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2474     }
2475 
2476     void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
2477         GenericStringBuffer<EncodingType> sb;
2478         SizeType len = CurrentSchema().GetURI().GetStringLength();
2479         if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
2480         if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
2481         else GetInvalidSchemaPointer().StringifyUriFragment(sb);
2482         ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2483             GetStateAllocator());
2484         result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2485     }
2486 
2487     void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
2488         result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
2489     }
2490 
2491     void AddError(ValueType& keyword, ValueType& error) {
2492         typename ValueType::MemberIterator member = error_.FindMember(keyword);
2493         if (member == error_.MemberEnd())
2494             error_.AddMember(keyword, error, GetStateAllocator());
2495         else {
2496             if (member->value.IsObject()) {
2497                 ValueType errors(kArrayType);
2498                 errors.PushBack(member->value, GetStateAllocator());
2499                 member->value = errors;
2500             }
2501             member->value.PushBack(error, GetStateAllocator());
2502         }
2503     }
2504 
2505     void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
2506         AddErrorCode(currentError_, code);
2507         AddErrorInstanceLocation(currentError_, parent);
2508         AddErrorSchemaLocation(currentError_);
2509         AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
2510     }
2511 
2512     void MergeError(ValueType& other) {
2513         for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
2514             AddError(it->name, it->value);
2515         }
2516     }
2517 
2518     void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
2519         const typename SchemaType::ValueType& (*exclusive)() = 0) {
2520         currentError_.SetObject();
2521         currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2522         currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2523         if (exclusive)
2524             currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
2525         AddCurrentError(code);
2526     }
2527 
2528     void AddErrorArray(const ValidateErrorCode code,
2529         ISchemaValidator** subvalidators, SizeType count) {
2530         ValueType errors(kArrayType);
2531         for (SizeType i = 0; i < count; ++i)
2532             errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
2533         currentError_.SetObject();
2534         currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2535         AddCurrentError(code);
2536     }
2537 
2538     const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
2539     Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
2540     const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
2541 
2542     static const size_t kDefaultSchemaStackCapacity = 1024;
2543     static const size_t kDefaultDocumentStackCapacity = 256;
2544     const SchemaDocumentType* schemaDocument_;
2545     const SchemaType& root_;
2546     StateAllocator* stateAllocator_;
2547     StateAllocator* ownStateAllocator_;
2548     internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)
2549     internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)
2550     OutputHandler* outputHandler_;
2551     ValueType error_;
2552     ValueType currentError_;
2553     ValueType missingDependents_;
2554     bool valid_;
2555     unsigned flags_;
2556 #if RAPIDJSON_SCHEMA_VERBOSE
2557     unsigned depth_;
2558 #endif
2559 };
2560 
2561 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
2562 
2563 ///////////////////////////////////////////////////////////////////////////////
2564 // SchemaValidatingReader
2565 
2566 //! A helper class for parsing with validation.
2567 /*!
2568     This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
2569 
2570     \tparam parseFlags Combination of \ref ParseFlag.
2571     \tparam InputStream Type of input stream, implementing Stream concept.
2572     \tparam SourceEncoding Encoding of the input stream.
2573     \tparam SchemaDocumentType Type of schema document.
2574     \tparam StackAllocator Allocator type for stack.
2575 */
2576 template <
2577     unsigned parseFlags,
2578     typename InputStream,
2579     typename SourceEncoding,
2580     typename SchemaDocumentType = SchemaDocument,
2581     typename StackAllocator = CrtAllocator>
2582 class SchemaValidatingReader {
2583 public:
2584     typedef typename SchemaDocumentType::PointerType PointerType;
2585     typedef typename InputStream::Ch Ch;
2586     typedef GenericValue<SourceEncoding, StackAllocator> ValueType;
2587 
2588     //! Constructor
2589     /*!
2590         \param is Input stream.
2591         \param sd Schema document.
2592     */
2593     SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
2594 
2595     template <typename Handler>
2596     bool operator()(Handler& handler) {
2597         GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
2598         GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
2599         parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2600 
2601         isValid_ = validator.IsValid();
2602         if (isValid_) {
2603             invalidSchemaPointer_ = PointerType();
2604             invalidSchemaKeyword_ = 0;
2605             invalidDocumentPointer_ = PointerType();
2606             error_.SetObject();
2607         }
2608         else {
2609             invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
2610             invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
2611             invalidSchemaCode_ = validator.GetInvalidSchemaCode();
2612             invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2613             error_.CopyFrom(validator.GetError(), allocator_);
2614         }
2615 
2616         return parseResult_;
2617     }
2618 
2619     const ParseResult& GetParseResult() const { return parseResult_; }
2620     bool IsValid() const { return isValid_; }
2621     const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
2622     const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
2623     const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
2624     const ValueType& GetError() const { return error_; }
2625     ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
2626 
2627 private:
2628     InputStream& is_;
2629     const SchemaDocumentType& sd_;
2630 
2631     ParseResult parseResult_;
2632     PointerType invalidSchemaPointer_;
2633     const Ch* invalidSchemaKeyword_;
2634     PointerType invalidDocumentPointer_;
2635     ValidateErrorCode invalidSchemaCode_;
2636     StackAllocator allocator_;
2637     ValueType error_;
2638     bool isValid_;
2639 };
2640 
2641 RAPIDJSON_NAMESPACE_END
2642 RAPIDJSON_DIAG_POP
2643 
2644 #endif // RAPIDJSON_SCHEMA_H_
2645