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