schema.h

Engine/source/persistence/rapidjson/schema.h

More...

Classes:

Namespaces:

namespace

Public Defines

define
RAPIDJSON_INVALID_KEYWORD_RETURN(keyword) RAPIDJSON_MULTILINEMACRO_BEGIN\
    context.invalidKeyword = keyword.GetString();\
    (keyword.GetString());\
    return false;\
RAPIDJSON_MULTILINEMACRO_END
define
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)      (!valid_) return false; \
     (!BeginValue() || !CurrentSchema().method arg1) {\
        ();\
        return valid_ = false;\
    }
define
RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)     return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
define
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)      (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
         (context->hasher)\
            static_cast<HasherType*>(context->hasher)->method arg2;\
         (context->validators)\
             ( i_ = 0; i_ < context->validatorCount; i_++)\
                static_cast<*>(context->validators[i_])->method arg2;\
         (context->patternPropertiesValidators)\
             ( i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
                static_cast<*>(context->patternPropertiesValidators[i_])->method arg2;\
    }
define
RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)        (method, arg1);\
    (method, arg2);\
         (method, arg2)
define
RAPIDJSON_STRING_(name, ...)     static  ValueType& Get##name##() {\
        static  Ch s[] = { __VA_ARGS__, '\0' };\
        static  ValueType v(s, static_cast<>(sizeof(s) / sizeof(Ch) - 1));\
        return v;\
    }
define
RAPIDJSON_STRING_(name, ...)     static  StringRefType& Get##name##() {\
        static  Ch s[] = { __VA_ARGS__, '\0' };\
        static  StringRefType v(s, static_cast<>(sizeof(s) / sizeof(Ch) - 1)); \
        return v;\
    }

Public Typedefs

SchemaDocument 

GenericSchemaDocument using Value type.

Detailed Description

Public Defines

RAPIDJSON_INVALID_KEYWORD_RETURN(keyword) RAPIDJSON_MULTILINEMACRO_BEGIN\
    context.invalidKeyword = keyword.GetString();\
    (keyword.GetString());\
    return false;\
RAPIDJSON_MULTILINEMACRO_END
RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) 
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)      (!valid_) return false; \
     (!BeginValue() || !CurrentSchema().method arg1) {\
        ();\
        return valid_ = false;\
    }
RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() 
RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)     return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)      (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
         (context->hasher)\
            static_cast<HasherType*>(context->hasher)->method arg2;\
         (context->validators)\
             ( i_ = 0; i_ < context->validatorCount; i_++)\
                static_cast<*>(context->validators[i_])->method arg2;\
         (context->patternPropertiesValidators)\
             ( i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
                static_cast<*>(context->patternPropertiesValidators[i_])->method arg2;\
    }
RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)        (method, arg1);\
    (method, arg2);\
         (method, arg2)
RAPIDJSON_SCHEMA_HAS_REGEX() 1
RAPIDJSON_SCHEMA_USE_INTERNALREGEX() 1
RAPIDJSON_SCHEMA_USE_STDREGEX() 0
RAPIDJSON_SCHEMA_VERBOSE() 0
RAPIDJSON_STRING_(name, ...)     static  ValueType& Get##name##() {\
        static  Ch s[] = { __VA_ARGS__, '\0' };\
        static  ValueType v(s, static_cast<>(sizeof(s) / sizeof(Ch) - 1));\
        return v;\
    }
RAPIDJSON_STRING_(name, ...)     static  StringRefType& Get##name##() {\
        static  Ch s[] = { __VA_ARGS__, '\0' };\
        static  StringRefType v(s, static_cast<>(sizeof(s) / sizeof(Ch) - 1)); \
        return v;\
    }

Public Typedefs

typedef IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider 

IGenericRemoteSchemaDocumentProvider using SchemaDocument.

typedef GenericSchemaDocument< Value > SchemaDocument 

GenericSchemaDocument using Value type.

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