DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers schema.h Source File

schema.h

00001 // Tencent is pleased to support the open source community by making RapidJSON available->
00002 // 
00003 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
00004 //
00005 // Licensed under the MIT License (the "License"); you may not use this file except
00006 // in compliance with the License-> You may obtain a copy of the License at
00007 //
00008 // http://opensource->org/licenses/MIT
00009 //
00010 // Unless required by applicable law or agreed to in writing, software distributed 
00011 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
00012 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the 
00013 // specific language governing permissions and limitations under the License->
00014 
00015 #ifndef RAPIDJSON_SCHEMA_H_
00016 #define RAPIDJSON_SCHEMA_H_
00017 
00018 #include "document.h "
00019 #include "pointer.h"
00020 #include <cmath> // abs, floor
00021 
00022 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
00023 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
00024 #else
00025 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
00026 #endif
00027 
00028 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
00029 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
00030 #else
00031 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
00032 #endif
00033 
00034 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
00035 #include "internal/regex.h"
00036 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
00037 #include <regex>
00038 #endif
00039 
00040 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
00041 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
00042 #else
00043 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
00044 #endif
00045 
00046 #ifndef RAPIDJSON_SCHEMA_VERBOSE
00047 #define RAPIDJSON_SCHEMA_VERBOSE 0
00048 #endif
00049 
00050 #if RAPIDJSON_SCHEMA_VERBOSE
00051 #include "stringbuffer.h"
00052 #endif
00053 
00054 RAPIDJSON_DIAG_PUSH
00055 
00056 #if defined(__GNUC__)
00057 RAPIDJSON_DIAG_OFF(effc++)
00058 #endif
00059 
00060 #ifdef __clang__
00061 RAPIDJSON_DIAG_OFF(weak-vtables)
00062 RAPIDJSON_DIAG_OFF(exit-time-destructors)
00063 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
00064 RAPIDJSON_DIAG_OFF(variadic-macros)
00065 #endif
00066 
00067 #ifdef _MSC_VER
00068 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
00069 #endif
00070 
00071 RAPIDJSON_NAMESPACE_BEGIN
00072 
00073 ///////////////////////////////////////////////////////////////////////////////
00074 // Verbose Utilities
00075 
00076 #if RAPIDJSON_SCHEMA_VERBOSE
00077 
00078 namespace internal {
00079 
00080 inline void PrintInvalidKeyword(const char* keyword) {
00081     printf("Fail keyword: %s\n", keyword);
00082 }
00083 
00084 inline void PrintInvalidKeyword(const wchar_t* keyword) {
00085     wprintf(L"Fail keyword: %ls\n", keyword);
00086 }
00087 
00088 inline void PrintInvalidDocument(const char* document) {
00089     printf("Fail document: %s\n\n", document);
00090 }
00091 
00092 inline void PrintInvalidDocument(const wchar_t* document) {
00093     wprintf(L"Fail document: %ls\n\n", document);
00094 }
00095 
00096 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
00097     printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
00098 }
00099 
00100 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
00101     wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
00102 }
00103 
00104 } // namespace internal
00105 
00106 #endif // RAPIDJSON_SCHEMA_VERBOSE
00107 
00108 ///////////////////////////////////////////////////////////////////////////////
00109 // RAPIDJSON_INVALID_KEYWORD_RETURN
00110 
00111 #if RAPIDJSON_SCHEMA_VERBOSE
00112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
00113 #else
00114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
00115 #endif
00116 
00117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
00118 RAPIDJSON_MULTILINEMACRO_BEGIN\
00119     context.invalidKeyword = keyword.GetString();\
00120     RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
00121     return false;\
00122 RAPIDJSON_MULTILINEMACRO_END
00123 
00124 ///////////////////////////////////////////////////////////////////////////////
00125 // Forward declarations
00126 
00127 template <typename ValueType, typename Allocator>
00128 class GenericSchemaDocument;
00129 
00130 namespace internal {
00131 
00132 template <typename SchemaDocumentType>
00133 class Schema;
00134 
00135 ///////////////////////////////////////////////////////////////////////////////
00136 // ISchemaValidator
00137 
00138 class ISchemaValidator {
00139 public:
00140     virtual ~ISchemaValidator() {}
00141     virtual bool IsValid() const = 0;
00142 };
00143 
00144 ///////////////////////////////////////////////////////////////////////////////
00145 // ISchemaStateFactory
00146 
00147 template <typename SchemaType>
00148 class ISchemaStateFactory {
00149 public:
00150     virtual ~ISchemaStateFactory() {}
00151     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
00152     virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
00153     virtual void* CreateHasher() = 0;
00154     virtual uint64_t GetHashCode(void* hasher) = 0;
00155     virtual void DestroryHasher(void* hasher) = 0;
00156     virtual void* MallocState(size_t size) = 0;
00157     virtual void FreeState(void* p) = 0;
00158 };
00159 
00160 ///////////////////////////////////////////////////////////////////////////////
00161 // Hasher
00162 
00163 // For comparison of compound value
00164 template<typename Encoding, typename Allocator>
00165 class Hasher {
00166 public:
00167     typedef typename Encoding::Ch Ch;
00168 
00169     Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
00170 
00171     bool Null() { return WriteType(kNullType); }
00172     bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
00173     bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
00174     bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
00175     bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
00176     bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
00177     bool Double(double d) { 
00178         Number n; 
00179         if (d < 0) n.u.i = static_cast<int64_t>(d);
00180         else       n.u.u = static_cast<uint64_t>(d); 
00181         n.d = d;
00182         return WriteNumber(n);
00183     }
00184 
00185     bool RawNumber(const Ch* str, SizeType len, bool) {
00186         WriteBuffer(kNumberType, str, len * sizeof(Ch));
00187         return true;
00188     }
00189 
00190     bool String(const Ch* str, SizeType len, bool) {
00191         WriteBuffer(kStringType, str, len * sizeof(Ch));
00192         return true;
00193     }
00194 
00195     bool StartObject() { return true; }
00196     bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
00197     bool EndObject(SizeType memberCount) { 
00198         uint64_t h = Hash(0, kObjectType);
00199         uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
00200         for (SizeType i = 0; i < memberCount; i++)
00201             h ^= Hash(kv[i * 2], kv[i * 2 + 1]);  // Use xor to achieve member order insensitive
00202         *stack_.template Push<uint64_t>() = h;
00203         return true;
00204     }
00205     
00206     bool StartArray() { return true; }
00207     bool EndArray(SizeType elementCount) { 
00208         uint64_t h = Hash(0, kArrayType);
00209         uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
00210         for (SizeType i = 0; i < elementCount; i++)
00211             h = Hash(h, e[i]); // Use hash to achieve element order sensitive
00212         *stack_.template Push<uint64_t>() = h;
00213         return true;
00214     }
00215 
00216     bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
00217 
00218     uint64_t GetHashCode() const {
00219         RAPIDJSON_ASSERT(IsValid());
00220         return *stack_.template Top<uint64_t>();
00221     }
00222 
00223 private:
00224     static const size_t kDefaultSize = 256;
00225     struct Number {
00226         union U {
00227             uint64_t u;
00228             int64_t i;
00229         }u;
00230         double d;
00231     };
00232 
00233     bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
00234     
00235     bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
00236     
00237     bool WriteBuffer(Type type, const void* data, size_t len) {
00238         // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
00239         uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
00240         const unsigned char* d = static_cast<const unsigned char*>(data);
00241         for (size_t i = 0; i < len; i++)
00242             h = Hash(h, d[i]);
00243         *stack_.template Push<uint64_t>() = h;
00244         return true;
00245     }
00246 
00247     static uint64_t Hash(uint64_t h, uint64_t d) {
00248         static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
00249         h ^= d;
00250         h *= kPrime;
00251         return h;
00252     }
00253 
00254     Stack<Allocator> stack_;
00255 };
00256 
00257 ///////////////////////////////////////////////////////////////////////////////
00258 // SchemaValidationContext
00259 
00260 template <typename SchemaDocumentType>
00261 struct SchemaValidationContext {
00262     typedef Schema<SchemaDocumentType> SchemaType;
00263     typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
00264     typedef typename SchemaType::ValueType ValueType;
00265     typedef typename ValueType::Ch Ch;
00266 
00267     enum PatternValidatorType {
00268         kPatternValidatorOnly,
00269         kPatternValidatorWithProperty,
00270         kPatternValidatorWithAdditionalProperty
00271     };
00272 
00273     SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
00274         factory(f),
00275         schema(s),
00276         valueSchema(),
00277         invalidKeyword(),
00278         hasher(),
00279         arrayElementHashCodes(),
00280         validators(),
00281         validatorCount(),
00282         patternPropertiesValidators(),
00283         patternPropertiesValidatorCount(),
00284         patternPropertiesSchemas(),
00285         patternPropertiesSchemaCount(),
00286         valuePatternValidatorType(kPatternValidatorOnly),
00287         propertyExist(),
00288         inArray(false),
00289         valueUniqueness(false),
00290         arrayUniqueness(false)
00291     {
00292     }
00293 
00294     ~SchemaValidationContext() {
00295         if (hasher)
00296             factory.DestroryHasher(hasher);
00297         if (validators) {
00298             for (SizeType i = 0; i < validatorCount; i++)
00299                 factory.DestroySchemaValidator(validators[i]);
00300             factory.FreeState(validators);
00301         }
00302         if (patternPropertiesValidators) {
00303             for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
00304                 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
00305             factory.FreeState(patternPropertiesValidators);
00306         }
00307         if (patternPropertiesSchemas)
00308             factory.FreeState(patternPropertiesSchemas);
00309         if (propertyExist)
00310             factory.FreeState(propertyExist);
00311     }
00312 
00313     SchemaValidatorFactoryType& factory;
00314     const SchemaType* schema;
00315     const SchemaType* valueSchema;
00316     const Ch* invalidKeyword;
00317     void* hasher; // Only validator access
00318     void* arrayElementHashCodes; // Only validator access this
00319     ISchemaValidator** validators;
00320     SizeType validatorCount;
00321     ISchemaValidator** patternPropertiesValidators;
00322     SizeType patternPropertiesValidatorCount;
00323     const SchemaType** patternPropertiesSchemas;
00324     SizeType patternPropertiesSchemaCount;
00325     PatternValidatorType valuePatternValidatorType;
00326     PatternValidatorType objectPatternValidatorType;
00327     SizeType arrayElementIndex;
00328     bool* propertyExist;
00329     bool inArray;
00330     bool valueUniqueness;
00331     bool arrayUniqueness;
00332 };
00333 
00334 ///////////////////////////////////////////////////////////////////////////////
00335 // Schema
00336 
00337 template <typename SchemaDocumentType>
00338 class Schema {
00339 public:
00340     typedef typename SchemaDocumentType::ValueType ValueType;
00341     typedef typename SchemaDocumentType::AllocatorType AllocatorType;
00342     typedef typename SchemaDocumentType::PointerType PointerType;
00343     typedef typename ValueType::EncodingType EncodingType;
00344     typedef typename EncodingType::Ch Ch;
00345     typedef SchemaValidationContext<SchemaDocumentType> Context;
00346     typedef Schema<SchemaDocumentType> SchemaType;
00347     typedef GenericValue<EncodingType, AllocatorType>  SValue;
00348     friend class GenericSchemaDocument<ValueType, AllocatorType>;
00349 
00350     Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
00351         allocator_(allocator),
00352         enum_(),
00353         enumCount_(),
00354         not_(),
00355         type_((1 << kTotalSchemaType) - 1), // typeless
00356         validatorCount_(),
00357         properties_(),
00358         additionalPropertiesSchema_(),
00359         patternProperties_(),
00360         patternPropertyCount_(),
00361         propertyCount_(),
00362         minProperties_(),
00363         maxProperties_(SizeType(~0)),
00364         additionalProperties_(true),
00365         hasDependencies_(),
00366         hasRequired_(),
00367         hasSchemaDependencies_(),
00368         additionalItemsSchema_(),
00369         itemsList_(),
00370         itemsTuple_(),
00371         itemsTupleCount_(),
00372         minItems_(),
00373         maxItems_(SizeType(~0)),
00374         additionalItems_(true),
00375         uniqueItems_(false),
00376         pattern_(),
00377         minLength_(0),
00378         maxLength_(~SizeType(0)),
00379         exclusiveMinimum_(false),
00380         exclusiveMaximum_(false)
00381     {
00382         typedef typename SchemaDocumentType::ValueType ValueType;
00383         typedef typename ValueType::ConstValueIterator ConstValueIterator;
00384         typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
00385 
00386         if (!value.IsObject())
00387             return;
00388 
00389         if (const ValueType* v = GetMember(value, GetTypeString())) {
00390             type_ = 0;
00391             if (v->IsString())
00392                 AddType(*v);
00393             else if (v->IsArray())
00394                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
00395                     AddType(*itr);
00396         }
00397 
00398         if (const ValueType* v = GetMember(value, GetEnumString()))
00399             if (v->IsArray() && v->Size() > 0) {
00400                 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
00401                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
00402                     typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
00403                     char buffer[256 + 24];
00404                     MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
00405                     EnumHasherType h(&hasherAllocator, 256);
00406                     itr->Accept(h);
00407                     enum_[enumCount_++] = h.GetHashCode();
00408                 }
00409             }
00410 
00411         if (schemaDocument) {
00412             AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
00413             AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
00414             AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
00415         }
00416 
00417         if (const ValueType* v = GetMember(value, GetNotString())) {
00418             schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
00419             notValidatorIndex_ = validatorCount_;
00420             validatorCount_++;
00421         }
00422 
00423         // Object
00424 
00425         const ValueType* properties = GetMember(value, GetPropertiesString());
00426         const ValueType* required = GetMember(value, GetRequiredString());
00427         const ValueType* dependencies = GetMember(value, GetDependenciesString());
00428         {
00429             // Gather properties from properties/required/dependencies
00430             SValue allProperties(kArrayType);
00431 
00432             if (properties && properties->IsObject())
00433                 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
00434                     AddUniqueElement(allProperties, itr->name);
00435             
00436             if (required && required->IsArray())
00437                 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
00438                     if (itr->IsString())
00439                         AddUniqueElement(allProperties, *itr);
00440 
00441             if (dependencies && dependencies->IsObject())
00442                 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
00443                     AddUniqueElement(allProperties, itr->name);
00444                     if (itr->value.IsArray())
00445                         for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
00446                             if (i->IsString())
00447                                 AddUniqueElement(allProperties, *i);
00448                 }
00449 
00450             if (allProperties.Size() > 0) {
00451                 propertyCount_ = allProperties.Size();
00452                 properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
00453                 for (SizeType i = 0; i < propertyCount_; i++) {
00454                     new (&properties_[i]) Property();
00455                     properties_[i].name = allProperties[i];
00456                     properties_[i].schema = GetTypeless();
00457                 }
00458             }
00459         }
00460 
00461         if (properties && properties->IsObject()) {
00462             PointerType q = p.Append(GetPropertiesString(), allocator_);
00463             for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
00464                 SizeType index;
00465                 if (FindPropertyIndex(itr->name, &index))
00466                     schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
00467             }
00468         }
00469 
00470         if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
00471             PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
00472             patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
00473             patternPropertyCount_ = 0;
00474 
00475             for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
00476                 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
00477                 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
00478                 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
00479                 patternPropertyCount_++;
00480             }
00481         }
00482 
00483         if (required && required->IsArray())
00484             for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
00485                 if (itr->IsString()) {
00486                     SizeType index;
00487                     if (FindPropertyIndex(*itr, &index)) {
00488                         properties_[index].required = true;
00489                         hasRequired_ = true;
00490                     }
00491                 }
00492 
00493         if (dependencies && dependencies->IsObject()) {
00494             PointerType q = p.Append(GetDependenciesString(), allocator_);
00495             hasDependencies_ = true;
00496             for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
00497                 SizeType sourceIndex;
00498                 if (FindPropertyIndex(itr->name, &sourceIndex)) {
00499                     if (itr->value.IsArray()) {
00500                         properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
00501                         std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
00502                         for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
00503                             SizeType targetIndex;
00504                             if (FindPropertyIndex(*targetItr, &targetIndex))
00505                                 properties_[sourceIndex].dependencies[targetIndex] = true;
00506                         }
00507                     }
00508                     else if (itr->value.IsObject()) {
00509                         hasSchemaDependencies_ = true;
00510                         schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
00511                         properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
00512                         validatorCount_++;
00513                     }
00514                 }
00515             }
00516         }
00517 
00518         if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
00519             if (v->IsBool())
00520                 additionalProperties_ = v->GetBool();
00521             else if (v->IsObject())
00522                 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
00523         }
00524 
00525         AssignIfExist(minProperties_, value, GetMinPropertiesString());
00526         AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
00527 
00528         // Array
00529         if (const ValueType* v = GetMember(value, GetItemsString())) {
00530             PointerType q = p.Append(GetItemsString(), allocator_);
00531             if (v->IsObject()) // List validation
00532                 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
00533             else if (v->IsArray()) { // Tuple validation
00534                 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
00535                 SizeType index = 0;
00536                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
00537                     schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
00538             }
00539         }
00540 
00541         AssignIfExist(minItems_, value, GetMinItemsString());
00542         AssignIfExist(maxItems_, value, GetMaxItemsString());
00543 
00544         if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
00545             if (v->IsBool())
00546                 additionalItems_ = v->GetBool();
00547             else if (v->IsObject())
00548                 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
00549         }
00550 
00551         AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
00552 
00553         // String
00554         AssignIfExist(minLength_, value, GetMinLengthString());
00555         AssignIfExist(maxLength_, value, GetMaxLengthString());
00556 
00557         if (const ValueType* v = GetMember(value, GetPatternString()))
00558             pattern_ = CreatePattern(*v);
00559 
00560         // Number
00561         if (const ValueType* v = GetMember(value, GetMinimumString()))
00562             if (v->IsNumber())
00563                 minimum_.CopyFrom(*v, *allocator_);
00564 
00565         if (const ValueType* v = GetMember(value, GetMaximumString()))
00566             if (v->IsNumber())
00567                 maximum_.CopyFrom(*v, *allocator_);
00568 
00569         AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
00570         AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
00571 
00572         if (const ValueType* v = GetMember(value, GetMultipleOfString()))
00573             if (v->IsNumber() && v->GetDouble() > 0.0)
00574                 multipleOf_.CopyFrom(*v, *allocator_);
00575     }
00576 
00577     ~Schema() {
00578         if (allocator_) {
00579             allocator_->Free(enum_);
00580         }
00581         if (properties_) {
00582             for (SizeType i = 0; i < propertyCount_; i++)
00583                 properties_[i].~Property();
00584             AllocatorType::Free(properties_);
00585         }
00586         if (patternProperties_) {
00587             for (SizeType i = 0; i < patternPropertyCount_; i++)
00588                 patternProperties_[i].~PatternProperty();
00589             AllocatorType::Free(patternProperties_);
00590         }
00591         AllocatorType::Free(itemsTuple_);
00592 #if RAPIDJSON_SCHEMA_HAS_REGEX
00593         if (pattern_) {
00594             pattern_->~RegexType();
00595             allocator_->Free(pattern_);
00596         }
00597 #endif
00598     }
00599 
00600     bool BeginValue(Context& context) const {
00601         if (context.inArray) {
00602             if (uniqueItems_)
00603                 context.valueUniqueness = true;
00604 
00605             if (itemsList_)
00606                 context.valueSchema = itemsList_;
00607             else if (itemsTuple_) {
00608                 if (context.arrayElementIndex < itemsTupleCount_)
00609                     context.valueSchema = itemsTuple_[context.arrayElementIndex];
00610                 else if (additionalItemsSchema_)
00611                     context.valueSchema = additionalItemsSchema_;
00612                 else if (additionalItems_)
00613                     context.valueSchema = GetTypeless();
00614                 else
00615                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
00616             }
00617             else
00618                 context.valueSchema = GetTypeless();
00619 
00620             context.arrayElementIndex++;
00621         }
00622         return true;
00623     }
00624 
00625     RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
00626         if (context.patternPropertiesValidatorCount > 0) {
00627             bool otherValid = false;
00628             SizeType count = context.patternPropertiesValidatorCount;
00629             if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
00630                 otherValid = context.patternPropertiesValidators[--count]->IsValid();
00631 
00632             bool patternValid = true;
00633             for (SizeType i = 0; i < count; i++)
00634                 if (!context.patternPropertiesValidators[i]->IsValid()) {
00635                     patternValid = false;
00636                     break;
00637                 }
00638 
00639             if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
00640                 if (!patternValid)
00641                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
00642             }
00643             else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
00644                 if (!patternValid || !otherValid)
00645                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
00646             }
00647             else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
00648                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
00649         }
00650 
00651         if (enum_) {
00652             const uint64_t h = context.factory.GetHashCode(context.hasher);
00653             for (SizeType i = 0; i < enumCount_; i++)
00654                 if (enum_[i] == h)
00655                     goto foundEnum;
00656             RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
00657             foundEnum:;
00658         }
00659 
00660         if (allOf_.schemas)
00661             for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
00662                 if (!context.validators[i]->IsValid())
00663                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
00664         
00665         if (anyOf_.schemas) {
00666             for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
00667                 if (context.validators[i]->IsValid())
00668                     goto foundAny;
00669             RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
00670             foundAny:;
00671         }
00672 
00673         if (oneOf_.schemas) {
00674             bool oneValid = false;
00675             for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
00676                 if (context.validators[i]->IsValid()) {
00677                     if (oneValid)
00678                         RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
00679                     else
00680                         oneValid = true;
00681                 }
00682             if (!oneValid)
00683                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
00684         }
00685 
00686         if (not_ && context.validators[notValidatorIndex_]->IsValid())
00687             RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
00688 
00689         return true;
00690     }
00691 
00692     bool Null(Context& context) const { 
00693         if (!(type_ & (1 << kNullSchemaType)))
00694             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00695         return CreateParallelValidator(context);
00696     }
00697     
00698     bool Bool(Context& context, bool) const { 
00699         if (!(type_ & (1 << kBooleanSchemaType)))
00700             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00701         return CreateParallelValidator(context);
00702     }
00703 
00704     bool Int(Context& context, int i) const {
00705         if (!CheckInt(context, i))
00706             return false;
00707         return CreateParallelValidator(context);
00708     }
00709 
00710     bool Uint(Context& context, unsigned u) const {
00711         if (!CheckUint(context, u))
00712             return false;
00713         return CreateParallelValidator(context);
00714     }
00715 
00716     bool Int64(Context& context, int64_t i) const {
00717         if (!CheckInt(context, i))
00718             return false;
00719         return CreateParallelValidator(context);
00720     }
00721 
00722     bool Uint64(Context& context, uint64_t u) const {
00723         if (!CheckUint(context, u))
00724             return false;
00725         return CreateParallelValidator(context);
00726     }
00727 
00728     bool Double(Context& context, double d) const {
00729         if (!(type_ & (1 << kNumberSchemaType)))
00730             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00731 
00732         if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
00733             return false;
00734 
00735         if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
00736             return false;
00737         
00738         if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
00739             return false;
00740         
00741         return CreateParallelValidator(context);
00742     }
00743     
00744     bool String(Context& context, const Ch* str, SizeType length, bool) const {
00745         if (!(type_ & (1 << kStringSchemaType)))
00746             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00747 
00748         if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
00749             SizeType count;
00750             if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
00751                 if (count < minLength_)
00752                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
00753                 if (count > maxLength_)
00754                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
00755             }
00756         }
00757 
00758         if (pattern_ && !IsPatternMatch(pattern_, str, length))
00759             RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
00760 
00761         return CreateParallelValidator(context);
00762     }
00763 
00764     bool StartObject(Context& context) const { 
00765         if (!(type_ & (1 << kObjectSchemaType)))
00766             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00767 
00768         if (hasDependencies_ || hasRequired_) {
00769             context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
00770             std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
00771         }
00772 
00773         if (patternProperties_) { // pre-allocate schema array
00774             SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
00775             context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
00776             context.patternPropertiesSchemaCount = 0;
00777             std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
00778         }
00779 
00780         return CreateParallelValidator(context);
00781     }
00782     
00783     bool Key(Context& context, const Ch* str, SizeType len, bool) const {
00784         if (patternProperties_) {
00785             context.patternPropertiesSchemaCount = 0;
00786             for (SizeType i = 0; i < patternPropertyCount_; i++)
00787                 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
00788                     context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
00789         }
00790 
00791         SizeType index;
00792         if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
00793             if (context.patternPropertiesSchemaCount > 0) {
00794                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
00795                 context.valueSchema = GetTypeless();
00796                 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
00797             }
00798             else
00799                 context.valueSchema = properties_[index].schema;
00800 
00801             if (context.propertyExist)
00802                 context.propertyExist[index] = true;
00803 
00804             return true;
00805         }
00806 
00807         if (additionalPropertiesSchema_) {
00808             if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
00809                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
00810                 context.valueSchema = GetTypeless();
00811                 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
00812             }
00813             else
00814                 context.valueSchema = additionalPropertiesSchema_;
00815             return true;
00816         }
00817         else if (additionalProperties_) {
00818             context.valueSchema = GetTypeless();
00819             return true;
00820         }
00821 
00822         if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
00823             RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
00824 
00825         return true;
00826     }
00827 
00828     bool EndObject(Context& context, SizeType memberCount) const {
00829         if (hasRequired_)
00830             for (SizeType index = 0; index < propertyCount_; index++)
00831                 if (properties_[index].required)
00832                     if (!context.propertyExist[index])
00833                         RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
00834 
00835         if (memberCount < minProperties_)
00836             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
00837 
00838         if (memberCount > maxProperties_)
00839             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
00840 
00841         if (hasDependencies_) {
00842             for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
00843                 if (context.propertyExist[sourceIndex]) {
00844                     if (properties_[sourceIndex].dependencies) {
00845                         for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
00846                             if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
00847                                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
00848                     }
00849                     else if (properties_[sourceIndex].dependenciesSchema)
00850                         if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
00851                             RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
00852                 }
00853         }
00854 
00855         return true;
00856     }
00857 
00858     bool StartArray(Context& context) const { 
00859         if (!(type_ & (1 << kArraySchemaType)))
00860             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
00861 
00862         context.arrayElementIndex = 0;
00863         context.inArray = true;
00864 
00865         return CreateParallelValidator(context);
00866     }
00867 
00868     bool EndArray(Context& context, SizeType elementCount) const { 
00869         context.inArray = false;
00870         
00871         if (elementCount < minItems_)
00872             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
00873         
00874         if (elementCount > maxItems_)
00875             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
00876 
00877         return true;
00878     }
00879 
00880     // Generate functions for string literal according to Ch
00881 #define RAPIDJSON_STRING_(name, ...) \
00882     static const ValueType& Get##name##String() {\
00883         static const Ch s[] = { __VA_ARGS__, '\0' };\
00884         static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
00885         return v;\
00886     }
00887 
00888     RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
00889     RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
00890     RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
00891     RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
00892     RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
00893     RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
00894     RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
00895     RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
00896     RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
00897     RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
00898     RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
00899     RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
00900     RAPIDJSON_STRING_(Not, 'n', 'o', 't')
00901     RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
00902     RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
00903     RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
00904     RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
00905     RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
00906     RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
00907     RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
00908     RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
00909     RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
00910     RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
00911     RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
00912     RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
00913     RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
00914     RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
00915     RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
00916     RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
00917     RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
00918     RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
00919     RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
00920     RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
00921 
00922 #undef RAPIDJSON_STRING_
00923 
00924 private:
00925     enum SchemaValueType {
00926         kNullSchemaType,
00927         kBooleanSchemaType,
00928         kObjectSchemaType,
00929         kArraySchemaType,
00930         kStringSchemaType,
00931         kNumberSchemaType,
00932         kIntegerSchemaType,
00933         kTotalSchemaType
00934     };
00935 
00936 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
00937         typedef internal::GenericRegex<EncodingType> RegexType;
00938 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
00939         typedef std::basic_regex<Ch> RegexType;
00940 #else
00941         typedef char RegexType;
00942 #endif
00943 
00944     struct SchemaArray {
00945         SchemaArray() : schemas(), count() {}
00946         ~SchemaArray() { AllocatorType::Free(schemas); }
00947         const SchemaType** schemas;
00948         SizeType begin; // begin index of context.validators
00949         SizeType count;
00950     };
00951 
00952     static const SchemaType* GetTypeless() {
00953         static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
00954         return &typeless;
00955     }
00956 
00957     template <typename V1, typename V2>
00958     void AddUniqueElement(V1& a, const V2& v) {
00959         for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
00960             if (*itr == v)
00961                 return;
00962         V1 c(v, *allocator_);
00963         a.PushBack(c, *allocator_);
00964     }
00965 
00966     static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
00967         typename ValueType::ConstMemberIterator itr = value.FindMember(name);
00968         return itr != value.MemberEnd() ? &(itr->value) : 0;
00969     }
00970 
00971     static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
00972         if (const ValueType* v = GetMember(value, name))
00973             if (v->IsBool())
00974                 out = v->GetBool();
00975     }
00976 
00977     static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
00978         if (const ValueType* v = GetMember(value, name))
00979             if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
00980                 out = static_cast<SizeType>(v->GetUint64());
00981     }
00982 
00983     void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
00984         if (const ValueType* v = GetMember(value, name)) {
00985             if (v->IsArray() && v->Size() > 0) {
00986                 PointerType q = p.Append(name, allocator_);
00987                 out.count = v->Size();
00988                 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
00989                 memset(out.schemas, 0, sizeof(Schema*)* out.count);
00990                 for (SizeType i = 0; i < out.count; i++)
00991                     schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
00992                 out.begin = validatorCount_;
00993                 validatorCount_ += out.count;
00994             }
00995         }
00996     }
00997 
00998 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
00999     template <typename ValueType>
01000     RegexType* CreatePattern(const ValueType& value) {
01001         if (value.IsString()) {
01002             RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
01003             if (!r->IsValid()) {
01004                 r->~RegexType();
01005                 AllocatorType::Free(r);
01006                 r = 0;
01007             }
01008             return r;
01009         }
01010         return 0;
01011     }
01012 
01013     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
01014         GenericRegexSearch<RegexType> rs(*pattern);
01015         return rs.Search(str);
01016     }
01017 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
01018     template <typename ValueType>
01019     RegexType* CreatePattern(const ValueType& value) {
01020         if (value.IsString())
01021             try {
01022                 return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
01023             }
01024             catch (const std::regex_error&) {
01025             }
01026         return 0;
01027     }
01028 
01029     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
01030         std::match_results<const Ch*> r;
01031         return std::regex_search(str, str + length, r, *pattern);
01032     }
01033 #else
01034     template <typename ValueType>
01035     RegexType* CreatePattern(const ValueType&) { return 0; }
01036 
01037     static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
01038 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
01039 
01040     void AddType(const ValueType& type) {
01041         if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;
01042         else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
01043         else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
01044         else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;
01045         else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
01046         else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
01047         else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
01048     }
01049 
01050     bool CreateParallelValidator(Context& context) const {
01051         if (enum_ || context.arrayUniqueness)
01052             context.hasher = context.factory.CreateHasher();
01053 
01054         if (validatorCount_) {
01055             RAPIDJSON_ASSERT(context.validators == 0);
01056             context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
01057             context.validatorCount = validatorCount_;
01058 
01059             if (allOf_.schemas)
01060                 CreateSchemaValidators(context, allOf_);
01061 
01062             if (anyOf_.schemas)
01063                 CreateSchemaValidators(context, anyOf_);
01064             
01065             if (oneOf_.schemas)
01066                 CreateSchemaValidators(context, oneOf_);
01067             
01068             if (not_)
01069                 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
01070             
01071             if (hasSchemaDependencies_) {
01072                 for (SizeType i = 0; i < propertyCount_; i++)
01073                     if (properties_[i].dependenciesSchema)
01074                         context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
01075             }
01076         }
01077 
01078         return true;
01079     }
01080 
01081     void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
01082         for (SizeType i = 0; i < schemas.count; i++)
01083             context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
01084     }
01085 
01086     // O(n)
01087     bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
01088         SizeType len = name.GetStringLength();
01089         const Ch* str = name.GetString();
01090         for (SizeType index = 0; index < propertyCount_; index++)
01091             if (properties_[index].name.GetStringLength() == len && 
01092                 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
01093             {
01094                 *outIndex = index;
01095                 return true;
01096             }
01097         return false;
01098     }
01099 
01100     bool CheckInt(Context& context, int64_t i) const {
01101         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
01102             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
01103 
01104         if (!minimum_.IsNull()) {
01105             if (minimum_.IsInt64()) {
01106                 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
01107                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
01108             }
01109             else if (minimum_.IsUint64()) {
01110                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
01111             }
01112             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
01113                 return false;
01114         }
01115 
01116         if (!maximum_.IsNull()) {
01117             if (maximum_.IsInt64()) {
01118                 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
01119                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
01120             }
01121             else if (maximum_.IsUint64())
01122                 /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
01123             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
01124                 return false;
01125         }
01126 
01127         if (!multipleOf_.IsNull()) {
01128             if (multipleOf_.IsUint64()) {
01129                 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
01130                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
01131             }
01132             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
01133                 return false;
01134         }
01135 
01136         return true;
01137     }
01138 
01139     bool CheckUint(Context& context, uint64_t i) const {
01140         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
01141             RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
01142 
01143         if (!minimum_.IsNull()) {
01144             if (minimum_.IsUint64()) {
01145                 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
01146                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
01147             }
01148             else if (minimum_.IsInt64())
01149                 /* do nothing */; // i >= 0 > minimum.Getint64()
01150             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
01151                 return false;
01152         }
01153 
01154         if (!maximum_.IsNull()) {
01155             if (maximum_.IsUint64()) {
01156                 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
01157                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
01158             }
01159             else if (maximum_.IsInt64())
01160                 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
01161             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
01162                 return false;
01163         }
01164 
01165         if (!multipleOf_.IsNull()) {
01166             if (multipleOf_.IsUint64()) {
01167                 if (i % multipleOf_.GetUint64() != 0)
01168                     RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
01169             }
01170             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
01171                 return false;
01172         }
01173 
01174         return true;
01175     }
01176 
01177     bool CheckDoubleMinimum(Context& context, double d) const {
01178         if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
01179             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
01180         return true;
01181     }
01182 
01183     bool CheckDoubleMaximum(Context& context, double d) const {
01184         if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
01185             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
01186         return true;
01187     }
01188 
01189     bool CheckDoubleMultipleOf(Context& context, double d) const {
01190         double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
01191         double q = std::floor(a / b);
01192         double r = a - q * b;
01193         if (r > 0.0)
01194             RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
01195         return true;
01196     }
01197 
01198     struct Property {
01199         Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
01200         ~Property() { AllocatorType::Free(dependencies); }
01201         SValue name;
01202         const SchemaType* schema;
01203         const SchemaType* dependenciesSchema;
01204         SizeType dependenciesValidatorIndex;
01205         bool* dependencies;
01206         bool required;
01207     };
01208 
01209     struct PatternProperty {
01210         PatternProperty() : schema(), pattern() {}
01211         ~PatternProperty() { 
01212             if (pattern) {
01213                 pattern->~RegexType();
01214                 AllocatorType::Free(pattern);
01215             }
01216         }
01217         const SchemaType* schema;
01218         RegexType* pattern;
01219     };
01220 
01221     AllocatorType* allocator_;
01222     uint64_t* enum_;
01223     SizeType enumCount_;
01224     SchemaArray allOf_;
01225     SchemaArray anyOf_;
01226     SchemaArray oneOf_;
01227     const SchemaType* not_;
01228     unsigned type_; // bitmask of kSchemaType
01229     SizeType validatorCount_;
01230     SizeType notValidatorIndex_;
01231 
01232     Property* properties_;
01233     const SchemaType* additionalPropertiesSchema_;
01234     PatternProperty* patternProperties_;
01235     SizeType patternPropertyCount_;
01236     SizeType propertyCount_;
01237     SizeType minProperties_;
01238     SizeType maxProperties_;
01239     bool additionalProperties_;
01240     bool hasDependencies_;
01241     bool hasRequired_;
01242     bool hasSchemaDependencies_;
01243 
01244     const SchemaType* additionalItemsSchema_;
01245     const SchemaType* itemsList_;
01246     const SchemaType** itemsTuple_;
01247     SizeType itemsTupleCount_;
01248     SizeType minItems_;
01249     SizeType maxItems_;
01250     bool additionalItems_;
01251     bool uniqueItems_;
01252 
01253     RegexType* pattern_;
01254     SizeType minLength_;
01255     SizeType maxLength_;
01256 
01257     SValue minimum_;
01258     SValue maximum_;
01259     SValue multipleOf_;
01260     bool exclusiveMinimum_;
01261     bool exclusiveMaximum_;
01262 };
01263 
01264 template<typename Stack, typename Ch>
01265 struct TokenHelper {
01266     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
01267         *documentStack.template Push<Ch>() = '/';
01268         char buffer[21];
01269         size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
01270         for (size_t i = 0; i < length; i++)
01271             *documentStack.template Push<Ch>() = buffer[i];
01272     }
01273 };
01274 
01275 // Partial specialized version for char to prevent buffer copying.
01276 template <typename Stack>
01277 struct TokenHelper<Stack, char> {
01278     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
01279         if (sizeof(SizeType) == 4) {
01280             char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
01281             *buffer++ = '/';
01282             const char* end = internal::u32toa(index, buffer);
01283              documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
01284         }
01285         else {
01286             char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
01287             *buffer++ = '/';
01288             const char* end = internal::u64toa(index, buffer);
01289             documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
01290         }
01291     }
01292 };
01293 
01294 } // namespace internal
01295 
01296 ///////////////////////////////////////////////////////////////////////////////
01297 // IGenericRemoteSchemaDocumentProvider
01298 
01299 template <typename SchemaDocumentType>
01300 class IGenericRemoteSchemaDocumentProvider {
01301 public:
01302     typedef typename SchemaDocumentType::Ch Ch;
01303 
01304     virtual ~IGenericRemoteSchemaDocumentProvider() {}
01305     virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
01306 };
01307 
01308 ///////////////////////////////////////////////////////////////////////////////
01309 // GenericSchemaDocument
01310 
01311 //! JSON schema document.
01312 /*!
01313     A JSON schema document is a compiled version of a JSON schema.
01314     It is basically a tree of internal::Schema.
01315 
01316     \note This is an immutable class (i.e. its instance cannot be modified after construction).
01317     \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
01318     \tparam Allocator Allocator type for allocating memory of this document.
01319 */
01320 template <typename ValueT, typename Allocator = CrtAllocator>
01321 class GenericSchemaDocument {
01322 public:
01323     typedef ValueT ValueType;
01324     typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
01325     typedef Allocator AllocatorType;
01326     typedef typename ValueType::EncodingType EncodingType;
01327     typedef typename EncodingType::Ch Ch;
01328     typedef internal::Schema<GenericSchemaDocument> SchemaType;
01329     typedef GenericPointer<ValueType, Allocator> PointerType;
01330     friend class internal::Schema<GenericSchemaDocument>;
01331     template <typename, typename, typename>
01332     friend class GenericSchemaValidator;
01333 
01334     //! Constructor.
01335     /*!
01336         Compile a JSON document into schema document.
01337 
01338         \param document A JSON document as source.
01339         \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
01340         \param allocator An optional allocator instance for allocating memory. Can be null.
01341     */
01342     explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
01343         remoteProvider_(remoteProvider),
01344         allocator_(allocator),
01345         ownAllocator_(),
01346         root_(),
01347         schemaMap_(allocator, kInitialSchemaMapSize),
01348         schemaRef_(allocator, kInitialSchemaRefSize)
01349     {
01350         if (!allocator_)
01351             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
01352 
01353         // Generate root schema, it will call CreateSchema() to create sub-schemas,
01354         // And call AddRefSchema() if there are $ref.
01355         CreateSchemaRecursive(&root_, PointerType(), document, document);
01356 
01357         // Resolve $ref
01358         while (!schemaRef_.Empty()) {
01359             SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
01360             if (const SchemaType* s = GetSchema(refEntry->target)) {
01361                 if (refEntry->schema)
01362                     *refEntry->schema = s;
01363 
01364                 // Create entry in map if not exist
01365                 if (!GetSchema(refEntry->source)) {
01366                     new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
01367                 }
01368             }
01369             refEntry->~SchemaRefEntry();
01370         }
01371 
01372         RAPIDJSON_ASSERT(root_ != 0);
01373 
01374         schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
01375     }
01376 
01377 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
01378     //! Move constructor in C++11
01379     GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
01380         remoteProvider_(rhs.remoteProvider_),
01381         allocator_(rhs.allocator_),
01382         ownAllocator_(rhs.ownAllocator_),
01383         root_(rhs.root_),
01384         schemaMap_(std::move(rhs.schemaMap_)),
01385         schemaRef_(std::move(rhs.schemaRef_))
01386     {
01387         rhs.remoteProvider_ = 0;
01388         rhs.allocator_ = 0;
01389         rhs.ownAllocator_ = 0;
01390     }
01391 #endif
01392 
01393     //! Destructor
01394     ~GenericSchemaDocument() {
01395         while (!schemaMap_.Empty())
01396             schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
01397 
01398         RAPIDJSON_DELETE(ownAllocator_);
01399     }
01400 
01401     //! Get the root schema.
01402     const SchemaType& GetRoot() const { return *root_; }
01403 
01404 private:
01405     //! Prohibit copying
01406     GenericSchemaDocument(const GenericSchemaDocument&);
01407     //! Prohibit assignment
01408     GenericSchemaDocument& operator=(const GenericSchemaDocument&);
01409 
01410     struct SchemaRefEntry {
01411         SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
01412         PointerType source;
01413         PointerType target;
01414         const SchemaType** schema;
01415     };
01416 
01417     struct SchemaEntry {
01418         SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
01419         ~SchemaEntry() {
01420             if (owned) {
01421                 schema->~SchemaType();
01422                 Allocator::Free(schema);
01423             }
01424         }
01425         PointerType pointer;
01426         SchemaType* schema;
01427         bool owned;
01428     };
01429 
01430     void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
01431         if (schema)
01432             *schema = SchemaType::GetTypeless();
01433 
01434         if (v.GetType() == kObjectType) {
01435             const SchemaType* s = GetSchema(pointer);
01436             if (!s)
01437                 CreateSchema(schema, pointer, v, document);
01438 
01439             for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
01440                 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
01441         }
01442         else if (v.GetType() == kArrayType)
01443             for (SizeType i = 0; i < v.Size(); i++)
01444                 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
01445     }
01446 
01447     void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
01448         RAPIDJSON_ASSERT(pointer.IsValid());
01449         if (v.IsObject()) {
01450             if (!HandleRefSchema(pointer, schema, v, document)) {
01451                 SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
01452                 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
01453                 if (schema)
01454                     *schema = s;
01455             }
01456         }
01457     }
01458 
01459     bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
01460         static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
01461         static const ValueType kRefValue(kRefString, 4);
01462 
01463         typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
01464         if (itr == v.MemberEnd())
01465             return false;
01466 
01467         if (itr->value.IsString()) {
01468             SizeType len = itr->value.GetStringLength();
01469             if (len > 0) {
01470                 const Ch* s = itr->value.GetString();
01471                 SizeType i = 0;
01472                 while (i < len && s[i] != '#') // Find the first #
01473                     i++;
01474 
01475                 if (i > 0) { // Remote reference, resolve immediately
01476                     if (remoteProvider_) {
01477                         if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
01478                             PointerType pointer(&s[i], len - i, allocator_);
01479                             if (pointer.IsValid()) {
01480                                 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
01481                                     if (schema)
01482                                         *schema = sc;
01483                                     return true;
01484                                 }
01485                             }
01486                         }
01487                     }
01488                 }
01489                 else if (s[i] == '#') { // Local reference, defer resolution
01490                     PointerType pointer(&s[i], len - i, allocator_);
01491                     if (pointer.IsValid()) {
01492                         if (const ValueType* nv = pointer.Get(document))
01493                             if (HandleRefSchema(source, schema, *nv, document))
01494                                 return true;
01495 
01496                         new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
01497                         return true;
01498                     }
01499                 }
01500             }
01501         }
01502         return false;
01503     }
01504 
01505     const SchemaType* GetSchema(const PointerType& pointer) const {
01506         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
01507             if (pointer == target->pointer)
01508                 return target->schema;
01509         return 0;
01510     }
01511 
01512     PointerType GetPointer(const SchemaType* schema) const {
01513         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
01514             if (schema == target->schema)
01515                 return target->pointer;
01516         return PointerType();
01517     }
01518 
01519     static const size_t kInitialSchemaMapSize = 64;
01520     static const size_t kInitialSchemaRefSize = 64;
01521 
01522     IRemoteSchemaDocumentProviderType* remoteProvider_;
01523     Allocator *allocator_;
01524     Allocator *ownAllocator_;
01525     const SchemaType* root_;                //!< Root schema.
01526     internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas
01527     internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref
01528 };
01529 
01530 //! GenericSchemaDocument using Value type.
01531 typedef GenericSchemaDocument<Value> SchemaDocument;
01532 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
01533 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
01534 
01535 ///////////////////////////////////////////////////////////////////////////////
01536 // GenericSchemaValidator
01537 
01538 //! JSON Schema Validator.
01539 /*!
01540     A SAX style JSON schema validator.
01541     It uses a \c GenericSchemaDocument to validate SAX events.
01542     It delegates the incoming SAX events to an output handler.
01543     The default output handler does nothing.
01544     It can be reused multiple times by calling \c Reset().
01545 
01546     \tparam SchemaDocumentType Type of schema document.
01547     \tparam OutputHandler Type of output handler. Default handler does nothing.
01548     \tparam StateAllocator Allocator for storing the internal validation states.
01549 */
01550 template <
01551     typename SchemaDocumentType,
01552     typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
01553     typename StateAllocator = CrtAllocator>
01554 class GenericSchemaValidator :
01555     public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, 
01556     public internal::ISchemaValidator
01557 {
01558 public:
01559     typedef typename SchemaDocumentType::SchemaType SchemaType;
01560     typedef typename SchemaDocumentType::PointerType PointerType;
01561     typedef typename SchemaType::EncodingType EncodingType;
01562     typedef typename EncodingType::Ch Ch;
01563 
01564     //! Constructor without output handler.
01565     /*!
01566         \param schemaDocument The schema document to conform to.
01567         \param allocator Optional allocator for storing internal validation states.
01568         \param schemaStackCapacity Optional initial capacity of schema path stack.
01569         \param documentStackCapacity Optional initial capacity of document path stack.
01570     */
01571     GenericSchemaValidator(
01572         const SchemaDocumentType& schemaDocument,
01573         StateAllocator* allocator = 0, 
01574         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
01575         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
01576         :
01577         schemaDocument_(&schemaDocument),
01578         root_(schemaDocument.GetRoot()),
01579         outputHandler_(GetNullHandler()),
01580         stateAllocator_(allocator),
01581         ownStateAllocator_(0),
01582         schemaStack_(allocator, schemaStackCapacity),
01583         documentStack_(allocator, documentStackCapacity),
01584         valid_(true)
01585 #if RAPIDJSON_SCHEMA_VERBOSE
01586         , depth_(0)
01587 #endif
01588     {
01589     }
01590 
01591     //! Constructor with output handler.
01592     /*!
01593         \param schemaDocument The schema document to conform to.
01594         \param allocator Optional allocator for storing internal validation states.
01595         \param schemaStackCapacity Optional initial capacity of schema path stack.
01596         \param documentStackCapacity Optional initial capacity of document path stack.
01597     */
01598     GenericSchemaValidator(
01599         const SchemaDocumentType& schemaDocument,
01600         OutputHandler& outputHandler,
01601         StateAllocator* allocator = 0, 
01602         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
01603         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
01604         :
01605         schemaDocument_(&schemaDocument),
01606         root_(schemaDocument.GetRoot()),
01607         outputHandler_(outputHandler),
01608         stateAllocator_(allocator),
01609         ownStateAllocator_(0),
01610         schemaStack_(allocator, schemaStackCapacity),
01611         documentStack_(allocator, documentStackCapacity),
01612         valid_(true)
01613 #if RAPIDJSON_SCHEMA_VERBOSE
01614         , depth_(0)
01615 #endif
01616     {
01617     }
01618 
01619     //! Destructor.
01620     ~GenericSchemaValidator() {
01621         Reset();
01622         RAPIDJSON_DELETE(ownStateAllocator_);
01623     }
01624 
01625     //! Reset the internal states.
01626     void Reset() {
01627         while (!schemaStack_.Empty())
01628             PopSchema();
01629         documentStack_.Clear();
01630         valid_ = true;
01631     }
01632 
01633     //! Checks whether the current state is valid.
01634     // Implementation of ISchemaValidator
01635     virtual bool IsValid() const { return valid_; }
01636 
01637     //! Gets the JSON pointer pointed to the invalid schema.
01638     PointerType GetInvalidSchemaPointer() const {
01639         return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
01640     }
01641 
01642     //! Gets the keyword of invalid schema.
01643     const Ch* GetInvalidSchemaKeyword() const {
01644         return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
01645     }
01646 
01647     //! Gets the JSON pointer pointed to the invalid value.
01648     PointerType GetInvalidDocumentPointer() const {
01649         return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
01650     }
01651 
01652 #if RAPIDJSON_SCHEMA_VERBOSE
01653 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
01654 RAPIDJSON_MULTILINEMACRO_BEGIN\
01655     *documentStack_.template Push<Ch>() = '\0';\
01656     documentStack_.template Pop<Ch>(1);\
01657     internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
01658 RAPIDJSON_MULTILINEMACRO_END
01659 #else
01660 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
01661 #endif
01662 
01663 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
01664     if (!valid_) return false; \
01665     if (!BeginValue() || !CurrentSchema().method arg1) {\
01666         RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
01667         return valid_ = false;\
01668     }
01669 
01670 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
01671     for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
01672         if (context->hasher)\
01673             static_cast<HasherType*>(context->hasher)->method arg2;\
01674         if (context->validators)\
01675             for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
01676                 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
01677         if (context->patternPropertiesValidators)\
01678             for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
01679                 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
01680     }
01681 
01682 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
01683     return valid_ = EndValue() && outputHandler_.method arg2
01684 
01685 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
01686     RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\
01687     RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
01688     RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)
01689 
01690     bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()   ), ( )); }
01691     bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }
01692     bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }
01693     bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }
01694     bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }
01695     bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
01696     bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
01697     bool RawNumber(const Ch* str, SizeType length, bool copy)
01698                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
01699     bool String(const Ch* str, SizeType length, bool copy)
01700                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
01701 
01702     bool StartObject() {
01703         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
01704         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
01705         return valid_ = outputHandler_.StartObject();
01706     }
01707     
01708     bool Key(const Ch* str, SizeType len, bool copy) {
01709         if (!valid_) return false;
01710         AppendToken(str, len);
01711         if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
01712         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
01713         return valid_ = outputHandler_.Key(str, len, copy);
01714     }
01715     
01716     bool EndObject(SizeType memberCount) { 
01717         if (!valid_) return false;
01718         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
01719         if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
01720         RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
01721     }
01722 
01723     bool StartArray() {
01724         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
01725         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
01726         return valid_ = outputHandler_.StartArray();
01727     }
01728     
01729     bool EndArray(SizeType elementCount) {
01730         if (!valid_) return false;
01731         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
01732         if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
01733         RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
01734     }
01735 
01736 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
01737 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
01738 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
01739 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
01740 
01741     // Implementation of ISchemaStateFactory<SchemaType>
01742     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
01743         return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
01744 #if RAPIDJSON_SCHEMA_VERBOSE
01745         depth_ + 1,
01746 #endif
01747         &GetStateAllocator());
01748     }
01749 
01750     virtual void DestroySchemaValidator(ISchemaValidator* validator) {
01751         GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
01752         v->~GenericSchemaValidator();
01753         StateAllocator::Free(v);
01754     }
01755 
01756     virtual void* CreateHasher() {
01757         return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
01758     }
01759 
01760     virtual uint64_t GetHashCode(void* hasher) {
01761         return static_cast<HasherType*>(hasher)->GetHashCode();
01762     }
01763 
01764     virtual void DestroryHasher(void* hasher) {
01765         HasherType* h = static_cast<HasherType*>(hasher);
01766         h->~HasherType();
01767         StateAllocator::Free(h);
01768     }
01769 
01770     virtual void* MallocState(size_t size) {
01771         return GetStateAllocator().Malloc(size);
01772     }
01773 
01774     virtual void FreeState(void* p) {
01775         return StateAllocator::Free(p);
01776     }
01777 
01778 private:
01779     typedef typename SchemaType::Context Context;
01780     typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
01781     typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
01782 
01783     GenericSchemaValidator( 
01784         const SchemaDocumentType& schemaDocument,
01785         const SchemaType& root,
01786 #if RAPIDJSON_SCHEMA_VERBOSE
01787         unsigned depth,
01788 #endif
01789         StateAllocator* allocator = 0,
01790         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
01791         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
01792         :
01793         schemaDocument_(&schemaDocument),
01794         root_(root),
01795         outputHandler_(GetNullHandler()),
01796         stateAllocator_(allocator),
01797         ownStateAllocator_(0),
01798         schemaStack_(allocator, schemaStackCapacity),
01799         documentStack_(allocator, documentStackCapacity),
01800         valid_(true)
01801 #if RAPIDJSON_SCHEMA_VERBOSE
01802         , depth_(depth)
01803 #endif
01804     {
01805     }
01806 
01807     StateAllocator& GetStateAllocator() {
01808         if (!stateAllocator_)
01809             stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
01810         return *stateAllocator_;
01811     }
01812 
01813     bool BeginValue() {
01814         if (schemaStack_.Empty())
01815             PushSchema(root_);
01816         else {
01817             if (CurrentContext().inArray)
01818                 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
01819 
01820             if (!CurrentSchema().BeginValue(CurrentContext()))
01821                 return false;
01822 
01823             SizeType count = CurrentContext().patternPropertiesSchemaCount;
01824             const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
01825             typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
01826             bool valueUniqueness = CurrentContext().valueUniqueness;
01827             if (CurrentContext().valueSchema)
01828                 PushSchema(*CurrentContext().valueSchema);
01829 
01830             if (count > 0) {
01831                 CurrentContext().objectPatternValidatorType = patternValidatorType;
01832                 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
01833                 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
01834                 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
01835                 for (SizeType i = 0; i < count; i++)
01836                     va[validatorCount++] = CreateSchemaValidator(*sa[i]);
01837             }
01838 
01839             CurrentContext().arrayUniqueness = valueUniqueness;
01840         }
01841         return true;
01842     }
01843 
01844     bool EndValue() {
01845         if (!CurrentSchema().EndValue(CurrentContext()))
01846             return false;
01847 
01848 #if RAPIDJSON_SCHEMA_VERBOSE
01849         GenericStringBuffer<EncodingType> sb;
01850         schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
01851 
01852         *documentStack_.template Push<Ch>() = '\0';
01853         documentStack_.template Pop<Ch>(1);
01854         internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
01855 #endif
01856 
01857         uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
01858         
01859         PopSchema();
01860 
01861         if (!schemaStack_.Empty()) {
01862             Context& context = CurrentContext();
01863             if (context.valueUniqueness) {
01864                 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
01865                 if (!a)
01866                     CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
01867                 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
01868                     if (itr->GetUint64() == h)
01869                         RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
01870                 a->PushBack(h, GetStateAllocator());
01871             }
01872         }
01873 
01874         // Remove the last token of document pointer
01875         while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
01876             ;
01877 
01878         return true;
01879     }
01880 
01881     void AppendToken(const Ch* str, SizeType len) {
01882         documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
01883         *documentStack_.template PushUnsafe<Ch>() = '/';
01884         for (SizeType i = 0; i < len; i++) {
01885             if (str[i] == '~') {
01886                 *documentStack_.template PushUnsafe<Ch>() = '~';
01887                 *documentStack_.template PushUnsafe<Ch>() = '0';
01888             }
01889             else if (str[i] == '/') {
01890                 *documentStack_.template PushUnsafe<Ch>() = '~';
01891                 *documentStack_.template PushUnsafe<Ch>() = '1';
01892             }
01893             else
01894                 *documentStack_.template PushUnsafe<Ch>() = str[i];
01895         }
01896     }
01897 
01898     RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
01899     
01900     RAPIDJSON_FORCEINLINE void PopSchema() {
01901         Context* c = schemaStack_.template Pop<Context>(1);
01902         if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
01903             a->~HashCodeArray();
01904             StateAllocator::Free(a);
01905         }
01906         c->~Context();
01907     }
01908 
01909     const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
01910     Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
01911     const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
01912 
01913     static OutputHandler& GetNullHandler() {
01914         static OutputHandler nullHandler;
01915         return nullHandler;
01916     }
01917 
01918     static const size_t kDefaultSchemaStackCapacity = 1024;
01919     static const size_t kDefaultDocumentStackCapacity = 256;
01920     const SchemaDocumentType* schemaDocument_;
01921     const SchemaType& root_;
01922     OutputHandler& outputHandler_;
01923     StateAllocator* stateAllocator_;
01924     StateAllocator* ownStateAllocator_;
01925     internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)
01926     internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)
01927     bool valid_;
01928 #if RAPIDJSON_SCHEMA_VERBOSE
01929     unsigned depth_;
01930 #endif
01931 };
01932 
01933 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
01934 
01935 ///////////////////////////////////////////////////////////////////////////////
01936 // SchemaValidatingReader
01937 
01938 //! A helper class for parsing with validation.
01939 /*!
01940     This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
01941 
01942     \tparam parseFlags Combination of \ref ParseFlag.
01943     \tparam InputStream Type of input stream, implementing Stream concept.
01944     \tparam SourceEncoding Encoding of the input stream.
01945     \tparam SchemaDocumentType Type of schema document.
01946     \tparam StackAllocator Allocator type for stack.
01947 */
01948 template <
01949     unsigned parseFlags,
01950     typename InputStream,
01951     typename SourceEncoding,
01952     typename SchemaDocumentType = SchemaDocument,
01953     typename StackAllocator = CrtAllocator>
01954 class SchemaValidatingReader {
01955 public:
01956     typedef typename SchemaDocumentType::PointerType PointerType;
01957     typedef typename InputStream::Ch Ch;
01958 
01959     //! Constructor
01960     /*!
01961         \param is Input stream.
01962         \param sd Schema document.
01963     */
01964     SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
01965 
01966     template <typename Handler>
01967     bool operator()(Handler& handler) {
01968         GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
01969         GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
01970         parseResult_ = reader.template Parse<parseFlags>(is_, validator);
01971 
01972         isValid_ = validator.IsValid();
01973         if (isValid_) {
01974             invalidSchemaPointer_ = PointerType();
01975             invalidSchemaKeyword_ = 0;
01976             invalidDocumentPointer_ = PointerType();
01977         }
01978         else {
01979             invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
01980             invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
01981             invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
01982         }
01983 
01984         return parseResult_;
01985     }
01986 
01987     const ParseResult& GetParseResult() const { return parseResult_; }
01988     bool IsValid() const { return isValid_; }
01989     const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
01990     const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
01991     const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
01992 
01993 private:
01994     InputStream& is_;
01995     const SchemaDocumentType& sd_;
01996 
01997     ParseResult parseResult_;
01998     PointerType invalidSchemaPointer_;
01999     const Ch* invalidSchemaKeyword_;
02000     PointerType invalidDocumentPointer_;
02001     bool isValid_;
02002 };
02003 
02004 RAPIDJSON_NAMESPACE_END
02005 RAPIDJSON_DIAG_POP
02006 
02007 #endif // RAPIDJSON_SCHEMA_H_