all repos — mgba @ f6755a6e1b7b0cf2b944cd8ca842746f11d6bf82

mGBA Game Boy Advance Emulator

src/third-party/discord-rpc/include/rapidjson/schema.h (view raw)

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