Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-02-21 10:13:05

0001 // Tencent is pleased to support the open source community by making RapidJSON available->
0002 //
0003 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
0004 //
0005 // Licensed under the MIT License (the "License"); you may not use this file except
0006 // in compliance with the License-> You may obtain a copy of the License at
0007 //
0008 // http://opensource->org/licenses/MIT
0009 //
0010 // Unless required by applicable law or agreed to in writing, software distributed
0011 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
0012 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the
0013 // specific language governing permissions and limitations under the License->
0014 
0015 #ifndef RAPIDJSON_SCHEMA_H_
0016 #define RAPIDJSON_SCHEMA_H_
0017 
0018 #include "document.h"
0019 #include "pointer.h"
0020 #include "stringbuffer.h"
0021 #include "error/en.h"
0022 #include "uri.h"
0023 #include <cmath> // abs, floor
0024 
0025 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
0026 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
0027 #endif
0028 
0029 #if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) || !(__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
0030 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
0031 #endif
0032 
0033 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
0034 #include "internal/regex.h"
0035 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
0036 #include <regex>
0037 #endif
0038 
0039 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
0040 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
0041 #else
0042 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
0043 #endif
0044 
0045 #ifndef RAPIDJSON_SCHEMA_VERBOSE
0046 #define RAPIDJSON_SCHEMA_VERBOSE 0
0047 #endif
0048 
0049 RAPIDJSON_DIAG_PUSH
0050 
0051 #if defined(__GNUC__)
0052 RAPIDJSON_DIAG_OFF(effc++)
0053 #endif
0054 
0055 #ifdef __clang__
0056 RAPIDJSON_DIAG_OFF(weak-vtables)
0057 RAPIDJSON_DIAG_OFF(exit-time-destructors)
0058 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
0059 RAPIDJSON_DIAG_OFF(variadic-macros)
0060 #elif defined(_MSC_VER)
0061 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
0062 #endif
0063 
0064 RAPIDJSON_NAMESPACE_BEGIN
0065 
0066 ///////////////////////////////////////////////////////////////////////////////
0067 // Verbose Utilities
0068 
0069 #if RAPIDJSON_SCHEMA_VERBOSE
0070 
0071 namespace internal {
0072 
0073 inline void PrintInvalidKeywordData(const char* keyword) {
0074     printf("    Fail keyword: '%s'\n", keyword);
0075 }
0076 
0077 inline void PrintInvalidKeywordData(const wchar_t* keyword) {
0078     wprintf(L"    Fail keyword: '%ls'\n", keyword);
0079 }
0080 
0081 inline void PrintInvalidDocumentData(const char* document) {
0082     printf("    Fail document: '%s'\n", document);
0083 }
0084 
0085 inline void PrintInvalidDocumentData(const wchar_t* document) {
0086     wprintf(L"    Fail document: '%ls'\n", document);
0087 }
0088 
0089 inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) {
0090     printf("    Sch: %*s'%s'\n    Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
0091 }
0092 
0093 inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) {
0094     wprintf(L"    Sch: %*ls'%ls'\n    Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
0095 }
0096 
0097 inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) {
0098     printf("    Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
0099 }
0100 
0101 inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) {
0102     wprintf(L"    Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
0103 }
0104 
0105 inline void PrintMethodData(const char* method) {
0106     printf("%s\n", method);
0107 }
0108 
0109 inline void PrintMethodData(const char* method, bool b) {
0110     printf("%s, Data: '%s'\n", method, b ? "true" : "false");
0111 }
0112 
0113 inline void PrintMethodData(const char* method, int64_t i) {
0114     printf("%s, Data: '%" PRId64 "'\n", method, i);
0115 }
0116 
0117 inline void PrintMethodData(const char* method, uint64_t u) {
0118     printf("%s, Data: '%" PRIu64 "'\n", method, u);
0119 }
0120 
0121 inline void PrintMethodData(const char* method, double d) {
0122     printf("%s, Data: '%lf'\n", method, d);
0123 }
0124 
0125 inline void PrintMethodData(const char* method, const char* s) {
0126     printf("%s, Data: '%s'\n", method, s);
0127 }
0128 
0129 inline void PrintMethodData(const char* method, const wchar_t* s) {
0130     wprintf(L"%hs, Data: '%ls'\n", method, s);
0131 }
0132 
0133 inline void PrintMethodData(const char* method, const char* s1, const char* s2) {
0134     printf("%s, Data: '%s', '%s'\n", method, s1, s2);
0135 }
0136 
0137 inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) {
0138     wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
0139 }
0140 
0141 } // namespace internal
0142 
0143 #endif // RAPIDJSON_SCHEMA_VERBOSE
0144 
0145 #ifndef RAPIDJSON_SCHEMA_PRINT
0146 #if RAPIDJSON_SCHEMA_VERBOSE
0147 #define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
0148 #else
0149 #define RAPIDJSON_SCHEMA_PRINT(name, ...)
0150 #endif
0151 #endif
0152 
0153 ///////////////////////////////////////////////////////////////////////////////
0154 // RAPIDJSON_INVALID_KEYWORD_RETURN
0155 
0156 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
0157 RAPIDJSON_MULTILINEMACRO_BEGIN\
0158     context.invalidCode = code;\
0159     context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
0160     RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\
0161     return false;\
0162 RAPIDJSON_MULTILINEMACRO_END
0163 
0164 ///////////////////////////////////////////////////////////////////////////////
0165 // ValidateFlag
0166 
0167 /*! \def RAPIDJSON_VALIDATE_DEFAULT_FLAGS
0168     \ingroup RAPIDJSON_CONFIG
0169     \brief User-defined kValidateDefaultFlags definition.
0170 
0171     User can define this as any \c ValidateFlag combinations.
0172 */
0173 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
0174 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
0175 #endif
0176 
0177 //! Combination of validate flags
0178 enum ValidateFlag {
0179     kValidateNoFlags = 0,                                       //!< No flags are set.
0180     kValidateContinueOnErrorFlag = 1,                           //!< Don't stop after first validation error.
0181     kValidateReadFlag = 2,                                      //!< Validation is for a read semantic.
0182     kValidateWriteFlag = 4,                                     //!< Validation is for a write semantic.
0183     kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS    //!< Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
0184 };
0185 
0186 ///////////////////////////////////////////////////////////////////////////////
0187 // Specification
0188 enum SchemaDraft {
0189     kDraftUnknown = -1,
0190     kDraftNone = 0,
0191     kDraft03 = 3,
0192     kDraftMin = 4,                       //!< Current minimum supported draft
0193     kDraft04 = 4,
0194     kDraft05 = 5,
0195     kDraftMax = 5,                       //!< Current maximum supported draft
0196     kDraft06 = 6,
0197     kDraft07 = 7,
0198     kDraft2019_09 = 8,
0199     kDraft2020_12 = 9
0200 };
0201 
0202 enum OpenApiVersion {
0203     kVersionUnknown = -1,
0204     kVersionNone = 0,
0205     kVersionMin = 2,                      //!< Current minimum supported version
0206     kVersion20 = 2,
0207     kVersion30 = 3,
0208     kVersionMax = 3,                      //!< Current maximum supported version
0209     kVersion31 = 4,
0210 };
0211 
0212 struct Specification {
0213     Specification(SchemaDraft d) : draft(d), oapi(kVersionNone) {}
0214     Specification(OpenApiVersion o) : oapi(o) {
0215         if (oapi == kVersion20) draft = kDraft04;
0216         else if (oapi == kVersion30) draft = kDraft05;
0217         else if (oapi == kVersion31) draft = kDraft2020_12;
0218         else draft = kDraft04;
0219     }
0220     ~Specification() {}
0221     bool IsSupported() const {
0222         return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
0223     }
0224     SchemaDraft draft;
0225     OpenApiVersion oapi;
0226 };
0227 
0228 ///////////////////////////////////////////////////////////////////////////////
0229 // Forward declarations
0230 
0231 template <typename ValueType, typename Allocator>
0232 class GenericSchemaDocument;
0233 
0234 namespace internal {
0235 
0236 template <typename SchemaDocumentType>
0237 class Schema;
0238 
0239 ///////////////////////////////////////////////////////////////////////////////
0240 // ISchemaValidator
0241 
0242 class ISchemaValidator {
0243 public:
0244     virtual ~ISchemaValidator() {}
0245     virtual bool IsValid() const = 0;
0246     virtual void SetValidateFlags(unsigned flags) = 0;
0247     virtual unsigned GetValidateFlags() const = 0;
0248 };
0249 
0250 ///////////////////////////////////////////////////////////////////////////////
0251 // ISchemaStateFactory
0252 
0253 template <typename SchemaType>
0254 class ISchemaStateFactory {
0255 public:
0256     virtual ~ISchemaStateFactory() {}
0257     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
0258     virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
0259     virtual void* CreateHasher() = 0;
0260     virtual uint64_t GetHashCode(void* hasher) = 0;
0261     virtual void DestroryHasher(void* hasher) = 0;
0262     virtual void* MallocState(size_t size) = 0;
0263     virtual void FreeState(void* p) = 0;
0264 };
0265 
0266 ///////////////////////////////////////////////////////////////////////////////
0267 // IValidationErrorHandler
0268 
0269 template <typename SchemaType>
0270 class IValidationErrorHandler {
0271 public:
0272     typedef typename SchemaType::Ch Ch;
0273     typedef typename SchemaType::SValue SValue;
0274 
0275     virtual ~IValidationErrorHandler() {}
0276 
0277     virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
0278     virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
0279     virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
0280     virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
0281     virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
0282     virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
0283     virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
0284     virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
0285     virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
0286 
0287     virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
0288     virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
0289     virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
0290 
0291     virtual void DisallowedItem(SizeType index) = 0;
0292     virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
0293     virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
0294     virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
0295 
0296     virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
0297     virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
0298     virtual void StartMissingProperties() = 0;
0299     virtual void AddMissingProperty(const SValue& name) = 0;
0300     virtual bool EndMissingProperties() = 0;
0301     virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
0302     virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
0303 
0304     virtual void StartDependencyErrors() = 0;
0305     virtual void StartMissingDependentProperties() = 0;
0306     virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
0307     virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
0308     virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
0309     virtual bool EndDependencyErrors() = 0;
0310 
0311     virtual void DisallowedValue(const ValidateErrorCode code) = 0;
0312     virtual void StartDisallowedType() = 0;
0313     virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
0314     virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
0315     virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
0316     virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
0317     virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
0318     virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
0319     virtual void Disallowed() = 0;
0320     virtual void DisallowedWhenWriting() = 0;
0321     virtual void DisallowedWhenReading() = 0;
0322 };
0323 
0324 
0325 ///////////////////////////////////////////////////////////////////////////////
0326 // Hasher
0327 
0328 // For comparison of compound value
0329 template<typename Encoding, typename Allocator>
0330 class Hasher {
0331 public:
0332     typedef typename Encoding::Ch Ch;
0333 
0334     Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
0335 
0336     bool Null() { return WriteType(kNullType); }
0337     bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
0338     bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
0339     bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
0340     bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
0341     bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
0342     bool Double(double d) {
0343         Number n;
0344         if (d < 0) n.u.i = static_cast<int64_t>(d);
0345         else       n.u.u = static_cast<uint64_t>(d);
0346         n.d = d;
0347         return WriteNumber(n);
0348     }
0349 
0350     bool RawNumber(const Ch* str, SizeType len, bool) {
0351         WriteBuffer(kNumberType, str, len * sizeof(Ch));
0352         return true;
0353     }
0354 
0355     bool String(const Ch* str, SizeType len, bool) {
0356         WriteBuffer(kStringType, str, len * sizeof(Ch));
0357         return true;
0358     }
0359 
0360     bool StartObject() { return true; }
0361     bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
0362     bool EndObject(SizeType memberCount) { 
0363         uint64_t h = Hash(0, kObjectType);
0364         uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
0365         for (SizeType i = 0; i < memberCount; i++)
0366             // Issue #2205
0367             // Hasing the key to avoid key=value cases with bug-prone zero-value hash
0368             h ^= Hash(Hash(0, kv[i * 2]), kv[i * 2 + 1]);  // Use xor to achieve member order insensitive
0369         *stack_.template Push<uint64_t>() = h;
0370         return true;
0371     }
0372     
0373     bool StartArray() { return true; }
0374     bool EndArray(SizeType elementCount) { 
0375         uint64_t h = Hash(0, kArrayType);
0376         uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
0377         for (SizeType i = 0; i < elementCount; i++)
0378             h = Hash(h, e[i]); // Use hash to achieve element order sensitive
0379         *stack_.template Push<uint64_t>() = h;
0380         return true;
0381     }
0382 
0383     bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
0384 
0385     uint64_t GetHashCode() const {
0386         RAPIDJSON_ASSERT(IsValid());
0387         return *stack_.template Top<uint64_t>();
0388     }
0389 
0390 private:
0391     static const size_t kDefaultSize = 256;
0392     struct Number {
0393         union U {
0394             uint64_t u;
0395             int64_t i;
0396         }u;
0397         double d;
0398     };
0399 
0400     bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
0401     
0402     bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
0403     
0404     bool WriteBuffer(Type type, const void* data, size_t len) {
0405         // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
0406         uint64_t h = Hash(RAPIDJSON_UINT64_C2(0xcbf29ce4, 0x84222325), type);
0407         const unsigned char* d = static_cast<const unsigned char*>(data);
0408         for (size_t i = 0; i < len; i++)
0409             h = Hash(h, d[i]);
0410         *stack_.template Push<uint64_t>() = h;
0411         return true;
0412     }
0413 
0414     static uint64_t Hash(uint64_t h, uint64_t d) {
0415         static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
0416         h ^= d;
0417         h *= kPrime;
0418         return h;
0419     }
0420 
0421     Stack<Allocator> stack_;
0422 };
0423 
0424 ///////////////////////////////////////////////////////////////////////////////
0425 // SchemaValidationContext
0426 
0427 template <typename SchemaDocumentType>
0428 struct SchemaValidationContext {
0429     typedef Schema<SchemaDocumentType> SchemaType;
0430     typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
0431     typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
0432     typedef typename SchemaType::ValueType ValueType;
0433     typedef typename ValueType::Ch Ch;
0434 
0435     enum PatternValidatorType {
0436         kPatternValidatorOnly,
0437         kPatternValidatorWithProperty,
0438         kPatternValidatorWithAdditionalProperty
0439     };
0440 
0441     SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s, unsigned fl = 0) :
0442         factory(f),
0443         error_handler(eh),
0444         schema(s),
0445         flags(fl),
0446         valueSchema(),
0447         invalidKeyword(),
0448         invalidCode(),
0449         hasher(),
0450         arrayElementHashCodes(),
0451         validators(),
0452         validatorCount(),
0453         patternPropertiesValidators(),
0454         patternPropertiesValidatorCount(),
0455         patternPropertiesSchemas(),
0456         patternPropertiesSchemaCount(),
0457         valuePatternValidatorType(kPatternValidatorOnly),
0458         propertyExist(),
0459         inArray(false),
0460         valueUniqueness(false),
0461         arrayUniqueness(false)
0462     {
0463     }
0464 
0465     ~SchemaValidationContext() {
0466         if (hasher)
0467             factory.DestroryHasher(hasher);
0468         if (validators) {
0469             for (SizeType i = 0; i < validatorCount; i++) {
0470                 if (validators[i]) {
0471                     factory.DestroySchemaValidator(validators[i]);
0472                 }
0473             }
0474             factory.FreeState(validators);
0475         }
0476         if (patternPropertiesValidators) {
0477             for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) {
0478                 if (patternPropertiesValidators[i]) {
0479                     factory.DestroySchemaValidator(patternPropertiesValidators[i]);
0480                 }
0481             }
0482             factory.FreeState(patternPropertiesValidators);
0483         }
0484         if (patternPropertiesSchemas)
0485             factory.FreeState(patternPropertiesSchemas);
0486         if (propertyExist)
0487             factory.FreeState(propertyExist);
0488     }
0489 
0490     SchemaValidatorFactoryType& factory;
0491     ErrorHandlerType& error_handler;
0492     const SchemaType* schema;
0493     unsigned flags;
0494     const SchemaType* valueSchema;
0495     const Ch* invalidKeyword;
0496     ValidateErrorCode invalidCode;
0497     void* hasher; // Only validator access
0498     void* arrayElementHashCodes; // Only validator access this
0499     ISchemaValidator** validators;
0500     SizeType validatorCount;
0501     ISchemaValidator** patternPropertiesValidators;
0502     SizeType patternPropertiesValidatorCount;
0503     const SchemaType** patternPropertiesSchemas;
0504     SizeType patternPropertiesSchemaCount;
0505     PatternValidatorType valuePatternValidatorType;
0506     PatternValidatorType objectPatternValidatorType;
0507     SizeType arrayElementIndex;
0508     bool* propertyExist;
0509     bool inArray;
0510     bool valueUniqueness;
0511     bool arrayUniqueness;
0512 };
0513 
0514 ///////////////////////////////////////////////////////////////////////////////
0515 // Schema
0516 
0517 template <typename SchemaDocumentType>
0518 class Schema {
0519 public:
0520     typedef typename SchemaDocumentType::ValueType ValueType;
0521     typedef typename SchemaDocumentType::AllocatorType AllocatorType;
0522     typedef typename SchemaDocumentType::PointerType PointerType;
0523     typedef typename ValueType::EncodingType EncodingType;
0524     typedef typename EncodingType::Ch Ch;
0525     typedef SchemaValidationContext<SchemaDocumentType> Context;
0526     typedef Schema<SchemaDocumentType> SchemaType;
0527     typedef GenericValue<EncodingType, AllocatorType> SValue;
0528     typedef IValidationErrorHandler<Schema> ErrorHandler;
0529     typedef GenericUri<ValueType, AllocatorType> UriType;
0530     friend class GenericSchemaDocument<ValueType, AllocatorType>;
0531 
0532     Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) :
0533         allocator_(allocator),
0534         uri_(schemaDocument->GetURI(), *allocator),
0535         id_(id, allocator),
0536         spec_(schemaDocument->GetSpecification()),
0537         pointer_(p, allocator),
0538         typeless_(schemaDocument->GetTypeless()),
0539         enum_(),
0540         enumCount_(),
0541         not_(),
0542         type_((1 << kTotalSchemaType) - 1), // typeless
0543         validatorCount_(),
0544         notValidatorIndex_(),
0545         properties_(),
0546         additionalPropertiesSchema_(),
0547         patternProperties_(),
0548         patternPropertyCount_(),
0549         propertyCount_(),
0550         minProperties_(),
0551         maxProperties_(SizeType(~0)),
0552         additionalProperties_(true),
0553         hasDependencies_(),
0554         hasRequired_(),
0555         hasSchemaDependencies_(),
0556         additionalItemsSchema_(),
0557         itemsList_(),
0558         itemsTuple_(),
0559         itemsTupleCount_(),
0560         minItems_(),
0561         maxItems_(SizeType(~0)),
0562         additionalItems_(true),
0563         uniqueItems_(false),
0564         pattern_(),
0565         minLength_(0),
0566         maxLength_(~SizeType(0)),
0567         exclusiveMinimum_(false),
0568         exclusiveMaximum_(false),
0569         defaultValueLength_(0),
0570         readOnly_(false),
0571         writeOnly_(false),
0572         nullable_(false)
0573     {
0574         GenericStringBuffer<EncodingType> sb;
0575         p.StringifyUriFragment(sb);
0576         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
0577 
0578         typedef typename ValueType::ConstValueIterator ConstValueIterator;
0579         typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
0580 
0581         // PR #1393
0582         // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
0583         // recursion (with recursive schemas), since schemaDocument->getSchema() is always
0584         // checked before creating a new one. Don't cache typeless_, though.
0585         if (this != typeless_) {
0586           typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
0587           SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
0588           new (entry) SchemaEntry(pointer_, this, true, allocator_);
0589           schemaDocument->AddSchemaRefs(this);
0590         }
0591 
0592         if (!value.IsObject())
0593             return;
0594 
0595         // If we have an id property, resolve it with the in-scope id
0596         // Not supported for open api 2.0 or 3.0
0597         if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
0598         if (const ValueType* v = GetMember(value, GetIdString())) {
0599             if (v->IsString()) {
0600                 UriType local(*v, allocator);
0601                 id_ = local.Resolve(id_, allocator);
0602                     RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString());
0603             }
0604         }
0605 
0606         if (const ValueType* v = GetMember(value, GetTypeString())) {
0607             type_ = 0;
0608             if (v->IsString())
0609                 AddType(*v);
0610             else if (v->IsArray())
0611                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
0612                     AddType(*itr);
0613         }
0614 
0615         if (const ValueType* v = GetMember(value, GetEnumString())) {
0616             if (v->IsArray() && v->Size() > 0) {
0617                 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
0618                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
0619                     typedef Hasher<EncodingType, MemoryPoolAllocator<AllocatorType> > EnumHasherType;
0620                     char buffer[256u + 24];
0621                     MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer, sizeof(buffer));
0622                     EnumHasherType h(&hasherAllocator, 256);
0623                     itr->Accept(h);
0624                     enum_[enumCount_++] = h.GetHashCode();
0625                 }
0626             }
0627         }
0628 
0629         if (schemaDocument)
0630             AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
0631 
0632         // AnyOf, OneOf, Not not supported for open api 2.0
0633         if (schemaDocument && spec_.oapi != kVersion20) {
0634             AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
0635             AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
0636 
0637             if (const ValueType* v = GetMember(value, GetNotString())) {
0638                 schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document, id_);
0639                 notValidatorIndex_ = validatorCount_;
0640                 validatorCount_++;
0641             }
0642         }
0643 
0644         // Object
0645 
0646         const ValueType* properties = GetMember(value, GetPropertiesString());
0647         const ValueType* required = GetMember(value, GetRequiredString());
0648         const ValueType* dependencies = GetMember(value, GetDependenciesString());
0649         {
0650             // Gather properties from properties/required/dependencies
0651             SValue allProperties(kArrayType);
0652 
0653             if (properties && properties->IsObject())
0654                 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
0655                     AddUniqueElement(allProperties, itr->name);
0656 
0657             if (required && required->IsArray())
0658                 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
0659                     if (itr->IsString())
0660                         AddUniqueElement(allProperties, *itr);
0661 
0662             // Dependencies not supported for open api 2.0 and 3.0
0663             if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
0664             if (dependencies && dependencies->IsObject())
0665                 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
0666                     AddUniqueElement(allProperties, itr->name);
0667                     if (itr->value.IsArray())
0668                         for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
0669                             if (i->IsString())
0670                                 AddUniqueElement(allProperties, *i);
0671                 }
0672 
0673             if (allProperties.Size() > 0) {
0674                 propertyCount_ = allProperties.Size();
0675                 properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
0676                 for (SizeType i = 0; i < propertyCount_; i++) {
0677                     new (&properties_[i]) Property();
0678                     properties_[i].name = allProperties[i];
0679                     properties_[i].schema = typeless_;
0680                 }
0681             }
0682         }
0683 
0684         if (properties && properties->IsObject()) {
0685             PointerType q = p.Append(GetPropertiesString(), allocator_);
0686             for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
0687                 SizeType index;
0688                 if (FindPropertyIndex(itr->name, &index))
0689                     schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
0690             }
0691         }
0692 
0693         // PatternProperties not supported for open api 2.0 and 3.0
0694         if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
0695         if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
0696             PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
0697             patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
0698             patternPropertyCount_ = 0;
0699 
0700             for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
0701                 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
0702                 PointerType r = q.Append(itr->name, allocator_);
0703                 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
0704                 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
0705                 patternPropertyCount_++;
0706             }
0707         }
0708 
0709         if (required && required->IsArray())
0710             for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
0711                 if (itr->IsString()) {
0712                     SizeType index;
0713                     if (FindPropertyIndex(*itr, &index)) {
0714                         properties_[index].required = true;
0715                         hasRequired_ = true;
0716                     }
0717                 }
0718 
0719         // Dependencies not supported for open api 2.0 and 3.0
0720         if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
0721         if (dependencies && dependencies->IsObject()) {
0722             PointerType q = p.Append(GetDependenciesString(), allocator_);
0723             hasDependencies_ = true;
0724             for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
0725                 SizeType sourceIndex;
0726                 if (FindPropertyIndex(itr->name, &sourceIndex)) {
0727                     if (itr->value.IsArray()) {
0728                         properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
0729                         std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
0730                         for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
0731                             SizeType targetIndex;
0732                             if (FindPropertyIndex(*targetItr, &targetIndex))
0733                                 properties_[sourceIndex].dependencies[targetIndex] = true;
0734                         }
0735                     }
0736                     else if (itr->value.IsObject()) {
0737                         hasSchemaDependencies_ = true;
0738                         schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
0739                         properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
0740                         validatorCount_++;
0741                     }
0742                 }
0743             }
0744         }
0745 
0746         if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
0747             if (v->IsBool())
0748                 additionalProperties_ = v->GetBool();
0749             else if (v->IsObject())
0750                 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
0751         }
0752 
0753         AssignIfExist(minProperties_, value, GetMinPropertiesString());
0754         AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
0755 
0756         // Array
0757         if (const ValueType* v = GetMember(value, GetItemsString())) {
0758             PointerType q = p.Append(GetItemsString(), allocator_);
0759             if (v->IsObject()) // List validation
0760                 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
0761             else if (v->IsArray()) { // Tuple validation
0762                 itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
0763                 SizeType index = 0;
0764                 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
0765                     schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
0766             }
0767         }
0768 
0769         AssignIfExist(minItems_, value, GetMinItemsString());
0770         AssignIfExist(maxItems_, value, GetMaxItemsString());
0771 
0772         // AdditionalItems not supported for openapi 2.0 and 3.0
0773         if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
0774         if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
0775             if (v->IsBool())
0776                 additionalItems_ = v->GetBool();
0777             else if (v->IsObject())
0778                 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
0779         }
0780 
0781         AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
0782 
0783         // String
0784         AssignIfExist(minLength_, value, GetMinLengthString());
0785         AssignIfExist(maxLength_, value, GetMaxLengthString());
0786 
0787         if (const ValueType* v = GetMember(value, GetPatternString()))
0788             pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
0789 
0790         // Number
0791         if (const ValueType* v = GetMember(value, GetMinimumString()))
0792             if (v->IsNumber())
0793                 minimum_.CopyFrom(*v, *allocator_);
0794 
0795         if (const ValueType* v = GetMember(value, GetMaximumString()))
0796             if (v->IsNumber())
0797                 maximum_.CopyFrom(*v, *allocator_);
0798 
0799         AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
0800         AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
0801 
0802         if (const ValueType* v = GetMember(value, GetMultipleOfString()))
0803             if (v->IsNumber() && v->GetDouble() > 0.0)
0804                 multipleOf_.CopyFrom(*v, *allocator_);
0805 
0806         // Default
0807         if (const ValueType* v = GetMember(value, GetDefaultValueString()))
0808             if (v->IsString())
0809                 defaultValueLength_ = v->GetStringLength();
0810 
0811         // ReadOnly - open api only (until draft 7 supported)
0812         // WriteOnly - open api 3 only (until draft 7 supported)
0813         // Both can't be true
0814         if (spec_.oapi != kVersionNone)
0815             AssignIfExist(readOnly_, value, GetReadOnlyString());
0816         if (spec_.oapi >= kVersion30)
0817             AssignIfExist(writeOnly_, value, GetWriteOnlyString());
0818         if (readOnly_ && writeOnly_)
0819             schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
0820 
0821         // Nullable - open api 3 only
0822         // If true add 'null' as allowable type
0823         if (spec_.oapi >= kVersion30) {
0824             AssignIfExist(nullable_, value, GetNullableString());
0825             if (nullable_)
0826                 AddType(GetNullString());
0827         }
0828     }
0829 
0830     ~Schema() {
0831         AllocatorType::Free(enum_);
0832         if (properties_) {
0833             for (SizeType i = 0; i < propertyCount_; i++)
0834                 properties_[i].~Property();
0835             AllocatorType::Free(properties_);
0836         }
0837         if (patternProperties_) {
0838             for (SizeType i = 0; i < patternPropertyCount_; i++)
0839                 patternProperties_[i].~PatternProperty();
0840             AllocatorType::Free(patternProperties_);
0841         }
0842         AllocatorType::Free(itemsTuple_);
0843 #if RAPIDJSON_SCHEMA_HAS_REGEX
0844         if (pattern_) {
0845             pattern_->~RegexType();
0846             AllocatorType::Free(pattern_);
0847         }
0848 #endif
0849     }
0850 
0851     const SValue& GetURI() const {
0852         return uri_;
0853     }
0854 
0855     const UriType& GetId() const {
0856         return id_;
0857     }
0858 
0859     const Specification& GetSpecification() const {
0860         return spec_;
0861     }
0862 
0863     const PointerType& GetPointer() const {
0864         return pointer_;
0865     }
0866 
0867     bool BeginValue(Context& context) const {
0868         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
0869         if (context.inArray) {
0870             if (uniqueItems_)
0871                 context.valueUniqueness = true;
0872 
0873             if (itemsList_)
0874                 context.valueSchema = itemsList_;
0875             else if (itemsTuple_) {
0876                 if (context.arrayElementIndex < itemsTupleCount_)
0877                     context.valueSchema = itemsTuple_[context.arrayElementIndex];
0878                 else if (additionalItemsSchema_)
0879                     context.valueSchema = additionalItemsSchema_;
0880                 else if (additionalItems_)
0881                     context.valueSchema = typeless_;
0882                 else {
0883                     context.error_handler.DisallowedItem(context.arrayElementIndex);
0884                     // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
0885                     context.valueSchema = typeless_;
0886                     // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
0887                     context.arrayElementIndex++;
0888                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
0889                 }
0890             }
0891             else
0892                 context.valueSchema = typeless_;
0893 
0894             context.arrayElementIndex++;
0895         }
0896         return true;
0897     }
0898 
0899     RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
0900         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
0901         // Only check pattern properties if we have validators
0902         if (context.patternPropertiesValidatorCount > 0) {
0903             bool otherValid = false;
0904             SizeType count = context.patternPropertiesValidatorCount;
0905             if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
0906                 otherValid = context.patternPropertiesValidators[--count]->IsValid();
0907 
0908             bool patternValid = true;
0909             for (SizeType i = 0; i < count; i++)
0910                 if (!context.patternPropertiesValidators[i]->IsValid()) {
0911                     patternValid = false;
0912                     break;
0913                 }
0914 
0915             if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
0916                 if (!patternValid) {
0917                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
0918                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
0919                 }
0920             }
0921             else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
0922                 if (!patternValid || !otherValid) {
0923                     context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
0924                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
0925                 }
0926             }
0927             else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
0928                 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
0929                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
0930             }
0931         }
0932 
0933         // For enums only check if we have a hasher
0934         if (enum_ && context.hasher) {
0935             const uint64_t h = context.factory.GetHashCode(context.hasher);
0936             for (SizeType i = 0; i < enumCount_; i++)
0937                 if (enum_[i] == h)
0938                     goto foundEnum;
0939             context.error_handler.DisallowedValue(kValidateErrorEnum);
0940             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
0941             foundEnum:;
0942         }
0943 
0944         // Only check allOf etc if we have validators
0945         if (context.validatorCount > 0) {
0946             if (allOf_.schemas)
0947                 for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
0948                     if (!context.validators[i]->IsValid()) {
0949                         context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
0950                         RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
0951                     }
0952 
0953             if (anyOf_.schemas) {
0954                 for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
0955                     if (context.validators[i]->IsValid())
0956                         goto foundAny;
0957                 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
0958                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
0959                 foundAny:;
0960             }
0961 
0962             if (oneOf_.schemas) {
0963                 bool oneValid = false;
0964                 SizeType firstMatch = 0;
0965                 for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
0966                     if (context.validators[i]->IsValid()) {
0967                         if (oneValid) {
0968                             context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
0969                             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
0970                         } else {
0971                             oneValid = true;
0972                             firstMatch = i - oneOf_.begin;
0973                         }
0974                     }
0975                 if (!oneValid) {
0976                     context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
0977                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
0978                 }
0979             }
0980 
0981             if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
0982                 context.error_handler.Disallowed();
0983                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
0984             }
0985         }
0986 
0987         return true;
0988     }
0989 
0990     bool Null(Context& context) const {
0991         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
0992         if (!(type_ & (1 << kNullSchemaType))) {
0993             DisallowedType(context, GetNullString());
0994             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
0995         }
0996         return CreateParallelValidator(context);
0997     }
0998 
0999     bool Bool(Context& context, bool b) const {
1000         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b);
1001         if (!CheckBool(context, b))
1002             return false;
1003         return CreateParallelValidator(context);
1004     }
1005 
1006     bool Int(Context& context, int i) const {
1007         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i);
1008         if (!CheckInt(context, i))
1009             return false;
1010         return CreateParallelValidator(context);
1011     }
1012 
1013     bool Uint(Context& context, unsigned u) const {
1014         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u);
1015         if (!CheckUint(context, u))
1016             return false;
1017         return CreateParallelValidator(context);
1018     }
1019 
1020     bool Int64(Context& context, int64_t i) const {
1021         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i);
1022         if (!CheckInt(context, i))
1023             return false;
1024         return CreateParallelValidator(context);
1025     }
1026 
1027     bool Uint64(Context& context, uint64_t u) const {
1028         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u);
1029         if (!CheckUint(context, u))
1030             return false;
1031         return CreateParallelValidator(context);
1032     }
1033 
1034     bool Double(Context& context, double d) const {
1035         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d);
1036         if (!(type_ & (1 << kNumberSchemaType))) {
1037             DisallowedType(context, GetNumberString());
1038             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1039         }
1040 
1041         if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1042             return false;
1043 
1044         if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1045             return false;
1046 
1047         if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1048             return false;
1049 
1050         return CreateParallelValidator(context);
1051     }
1052 
1053     bool String(Context& context, const Ch* str, SizeType length, bool) const {
1054         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str);
1055         if (!(type_ & (1 << kStringSchemaType))) {
1056             DisallowedType(context, GetStringString());
1057             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1058         }
1059 
1060         if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
1061             SizeType count;
1062             if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
1063                 if (count < minLength_) {
1064                     context.error_handler.TooShort(str, length, minLength_);
1065                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
1066                 }
1067                 if (count > maxLength_) {
1068                     context.error_handler.TooLong(str, length, maxLength_);
1069                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
1070                 }
1071             }
1072         }
1073 
1074         if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
1075             context.error_handler.DoesNotMatch(str, length);
1076             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
1077         }
1078 
1079         return CreateParallelValidator(context);
1080     }
1081 
1082     bool StartObject(Context& context) const {
1083         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject");
1084         if (!(type_ & (1 << kObjectSchemaType))) {
1085             DisallowedType(context, GetObjectString());
1086             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1087         }
1088 
1089         if (hasDependencies_ || hasRequired_) {
1090             context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
1091             std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
1092         }
1093 
1094         if (patternProperties_) { // pre-allocate schema array
1095             SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
1096             context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
1097             context.patternPropertiesSchemaCount = 0;
1098             std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
1099         }
1100 
1101         return CreateParallelValidator(context);
1102     }
1103 
1104     bool Key(Context& context, const Ch* str, SizeType len, bool) const {
1105         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
1106 
1107         if (patternProperties_) {
1108             context.patternPropertiesSchemaCount = 0;
1109             for (SizeType i = 0; i < patternPropertyCount_; i++)
1110                 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
1111                     context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
1112                     context.valueSchema = typeless_;
1113                 }
1114         }
1115 
1116         SizeType index  = 0;
1117         if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
1118             if (context.patternPropertiesSchemaCount > 0) {
1119                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
1120                 context.valueSchema = typeless_;
1121                 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
1122             }
1123             else
1124                 context.valueSchema = properties_[index].schema;
1125 
1126             if (context.propertyExist)
1127                 context.propertyExist[index] = true;
1128 
1129             return true;
1130         }
1131 
1132         if (additionalPropertiesSchema_) {
1133             if (context.patternPropertiesSchemaCount > 0) {
1134                 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
1135                 context.valueSchema = typeless_;
1136                 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
1137             }
1138             else
1139                 context.valueSchema = additionalPropertiesSchema_;
1140             return true;
1141         }
1142         else if (additionalProperties_) {
1143             context.valueSchema = typeless_;
1144             return true;
1145         }
1146 
1147         if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
1148             // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
1149             context.valueSchema = typeless_;
1150             context.error_handler.DisallowedProperty(str, len);
1151             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
1152         }
1153 
1154         return true;
1155     }
1156 
1157     bool EndObject(Context& context, SizeType memberCount) const {
1158         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
1159         if (hasRequired_) {
1160             context.error_handler.StartMissingProperties();
1161             for (SizeType index = 0; index < propertyCount_; index++)
1162                 if (properties_[index].required && !context.propertyExist[index])
1163                     if (properties_[index].schema->defaultValueLength_ == 0 )
1164                         context.error_handler.AddMissingProperty(properties_[index].name);
1165             if (context.error_handler.EndMissingProperties())
1166                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
1167         }
1168 
1169         if (memberCount < minProperties_) {
1170             context.error_handler.TooFewProperties(memberCount, minProperties_);
1171             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
1172         }
1173 
1174         if (memberCount > maxProperties_) {
1175             context.error_handler.TooManyProperties(memberCount, maxProperties_);
1176             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
1177         }
1178 
1179         if (hasDependencies_) {
1180             context.error_handler.StartDependencyErrors();
1181             for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1182                 const Property& source = properties_[sourceIndex];
1183                 if (context.propertyExist[sourceIndex]) {
1184                     if (source.dependencies) {
1185                         context.error_handler.StartMissingDependentProperties();
1186                         for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1187                             if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1188                                 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1189                         context.error_handler.EndMissingDependentProperties(source.name);
1190                     }
1191                     else if (source.dependenciesSchema) {
1192                         ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1193                         if (!dependenciesValidator->IsValid())
1194                             context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1195                     }
1196                 }
1197             }
1198             if (context.error_handler.EndDependencyErrors())
1199                 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
1200         }
1201 
1202         return true;
1203     }
1204 
1205     bool StartArray(Context& context) const {
1206         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
1207         context.arrayElementIndex = 0;
1208         context.inArray = true;  // Ensure we note that we are in an array
1209 
1210         if (!(type_ & (1 << kArraySchemaType))) {
1211             DisallowedType(context, GetArrayString());
1212             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1213         }
1214 
1215         return CreateParallelValidator(context);
1216     }
1217 
1218     bool EndArray(Context& context, SizeType elementCount) const {
1219         RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray");
1220         context.inArray = false;
1221 
1222         if (elementCount < minItems_) {
1223             context.error_handler.TooFewItems(elementCount, minItems_);
1224             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
1225         }
1226 
1227         if (elementCount > maxItems_) {
1228             context.error_handler.TooManyItems(elementCount, maxItems_);
1229             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
1230         }
1231 
1232         return true;
1233     }
1234 
1235     static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
1236         switch (validateErrorCode) {
1237             case kValidateErrorMultipleOf:              return GetMultipleOfString();
1238             case kValidateErrorMaximum:                 return GetMaximumString();
1239             case kValidateErrorExclusiveMaximum:        return GetMaximumString(); // Same
1240             case kValidateErrorMinimum:                 return GetMinimumString();
1241             case kValidateErrorExclusiveMinimum:        return GetMinimumString(); // Same
1242 
1243             case kValidateErrorMaxLength:               return GetMaxLengthString();
1244             case kValidateErrorMinLength:               return GetMinLengthString();
1245             case kValidateErrorPattern:                 return GetPatternString();
1246 
1247             case kValidateErrorMaxItems:                return GetMaxItemsString();
1248             case kValidateErrorMinItems:                return GetMinItemsString();
1249             case kValidateErrorUniqueItems:             return GetUniqueItemsString();
1250             case kValidateErrorAdditionalItems:         return GetAdditionalItemsString();
1251 
1252             case kValidateErrorMaxProperties:           return GetMaxPropertiesString();
1253             case kValidateErrorMinProperties:           return GetMinPropertiesString();
1254             case kValidateErrorRequired:                return GetRequiredString();
1255             case kValidateErrorAdditionalProperties:    return GetAdditionalPropertiesString();
1256             case kValidateErrorPatternProperties:       return GetPatternPropertiesString();
1257             case kValidateErrorDependencies:            return GetDependenciesString();
1258 
1259             case kValidateErrorEnum:                    return GetEnumString();
1260             case kValidateErrorType:                    return GetTypeString();
1261 
1262             case kValidateErrorOneOf:                   return GetOneOfString();
1263             case kValidateErrorOneOfMatch:              return GetOneOfString(); // Same
1264             case kValidateErrorAllOf:                   return GetAllOfString();
1265             case kValidateErrorAnyOf:                   return GetAnyOfString();
1266             case kValidateErrorNot:                     return GetNotString();
1267 
1268             case kValidateErrorReadOnly:                return GetReadOnlyString();
1269             case kValidateErrorWriteOnly:               return GetWriteOnlyString();
1270 
1271             default:                                    return GetNullString();
1272         }
1273     }
1274 
1275 
1276     // Generate functions for string literal according to Ch
1277 #define RAPIDJSON_STRING_(name, ...) \
1278     static const ValueType& Get##name##String() {\
1279         static const Ch s[] = { __VA_ARGS__, '\0' };\
1280         static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1281         return v;\
1282     }
1283 
1284     RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1285     RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1286     RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1287     RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1288     RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1289     RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1290     RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1291     RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1292     RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1293     RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1294     RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1295     RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1296     RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1297     RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1298     RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1299     RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1300     RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1301     RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1302     RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1303     RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1304     RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1305     RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1306     RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1307     RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1308     RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1309     RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1310     RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1311     RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1312     RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1313     RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1314     RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1315     RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1316     RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1317     RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1318     RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
1319     RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
1320     RAPIDJSON_STRING_(Id, 'i', 'd')
1321     RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
1322     RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
1323     RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
1324     RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
1325     RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
1326 
1327 #undef RAPIDJSON_STRING_
1328 
1329 private:
1330     enum SchemaValueType {
1331         kNullSchemaType,
1332         kBooleanSchemaType,
1333         kObjectSchemaType,
1334         kArraySchemaType,
1335         kStringSchemaType,
1336         kNumberSchemaType,
1337         kIntegerSchemaType,
1338         kTotalSchemaType
1339     };
1340 
1341 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1342         typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1343 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1344         typedef std::basic_regex<Ch> RegexType;
1345 #else
1346         typedef char RegexType;
1347 #endif
1348 
1349     struct SchemaArray {
1350         SchemaArray() : schemas(), count() {}
1351         ~SchemaArray() { AllocatorType::Free(schemas); }
1352         const SchemaType** schemas;
1353         SizeType begin; // begin index of context.validators
1354         SizeType count;
1355     };
1356 
1357     template <typename V1, typename V2>
1358     void AddUniqueElement(V1& a, const V2& v) {
1359         for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1360             if (*itr == v)
1361                 return;
1362         V1 c(v, *allocator_);
1363         a.PushBack(c, *allocator_);
1364     }
1365 
1366     static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
1367         typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1368         return itr != value.MemberEnd() ? &(itr->value) : 0;
1369     }
1370 
1371     static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
1372         if (const ValueType* v = GetMember(value, name))
1373             if (v->IsBool())
1374                 out = v->GetBool();
1375     }
1376 
1377     static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
1378         if (const ValueType* v = GetMember(value, name))
1379             if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
1380                 out = static_cast<SizeType>(v->GetUint64());
1381     }
1382 
1383     void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
1384         if (const ValueType* v = GetMember(value, name)) {
1385             if (v->IsArray() && v->Size() > 0) {
1386                 PointerType q = p.Append(name, allocator_);
1387                 out.count = v->Size();
1388                 out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
1389                 memset(out.schemas, 0, sizeof(Schema*)* out.count);
1390                 for (SizeType i = 0; i < out.count; i++)
1391                     schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1392                 out.begin = validatorCount_;
1393                 validatorCount_ += out.count;
1394             }
1395         }
1396     }
1397 
1398 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1399     template <typename ValueType>
1400     RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
1401         if (value.IsString()) {
1402             RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1403             if (!r->IsValid()) {
1404                 sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1405                 r->~RegexType();
1406                 AllocatorType::Free(r);
1407                 r = 0;
1408             }
1409             return r;
1410         }
1411         return 0;
1412     }
1413 
1414     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1415         GenericRegexSearch<RegexType> rs(*pattern);
1416         return rs.Search(str);
1417     }
1418 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1419     template <typename ValueType>
1420     RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
1421         if (value.IsString()) {
1422             RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1423             try {
1424                 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1425             }
1426             catch (const std::regex_error& e) {
1427                 sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1428                 AllocatorType::Free(r);
1429             }
1430         }
1431         return 0;
1432     }
1433 
1434     static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1435         std::match_results<const Ch*> r;
1436         return std::regex_search(str, str + length, r, *pattern);
1437     }
1438 #else
1439     template <typename ValueType>
1440     RegexType* CreatePattern(const ValueType&) {
1441         return 0;
1442     }
1443 
1444     static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1445 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1446 
1447     void AddType(const ValueType& type) {
1448         if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;
1449         else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1450         else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1451         else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;
1452         else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1453         else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1454         else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1455     }
1456 
1457     // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required.
1458     // Also creates a hasher for enums and array uniqueness, if required.
1459     // Also a useful place to add type-independent error checks.
1460     bool CreateParallelValidator(Context& context) const {
1461         if (enum_ || context.arrayUniqueness)
1462             context.hasher = context.factory.CreateHasher();
1463 
1464         if (validatorCount_) {
1465             RAPIDJSON_ASSERT(context.validators == 0);
1466             context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1467             std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_);
1468             context.validatorCount = validatorCount_;
1469 
1470             // Always return after first failure for these sub-validators
1471             if (allOf_.schemas)
1472                 CreateSchemaValidators(context, allOf_, false);
1473 
1474             if (anyOf_.schemas)
1475                 CreateSchemaValidators(context, anyOf_, false);
1476 
1477             if (oneOf_.schemas)
1478                 CreateSchemaValidators(context, oneOf_, false);
1479 
1480             if (not_)
1481                 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
1482 
1483             if (hasSchemaDependencies_) {
1484                 for (SizeType i = 0; i < propertyCount_; i++)
1485                     if (properties_[i].dependenciesSchema)
1486                         context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
1487             }
1488         }
1489 
1490         // Add any other type-independent checks here
1491         if (readOnly_ && (context.flags & kValidateWriteFlag)) {
1492             context.error_handler.DisallowedWhenWriting();
1493             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly);
1494         }
1495         if (writeOnly_ && (context.flags & kValidateReadFlag)) {
1496             context.error_handler.DisallowedWhenReading();
1497             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly);
1498         }
1499 
1500         return true;
1501     }
1502 
1503     void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
1504         for (SizeType i = 0; i < schemas.count; i++)
1505             context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1506     }
1507 
1508     // O(n)
1509     bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
1510         SizeType len = name.GetStringLength();
1511         const Ch* str = name.GetString();
1512         for (SizeType index = 0; index < propertyCount_; index++)
1513             if (properties_[index].name.GetStringLength() == len &&
1514                 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1515             {
1516                 *outIndex = index;
1517                 return true;
1518             }
1519         return false;
1520     }
1521 
1522     bool CheckBool(Context& context, bool) const {
1523         if (!(type_ & (1 << kBooleanSchemaType))) {
1524             DisallowedType(context, GetBooleanString());
1525             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1526         }
1527         return true;
1528     }
1529 
1530     bool CheckInt(Context& context, int64_t i) const {
1531         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1532             DisallowedType(context, GetIntegerString());
1533             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1534         }
1535 
1536         if (!minimum_.IsNull()) {
1537             if (minimum_.IsInt64()) {
1538                 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1539                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1540                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1541                 }
1542             }
1543             else if (minimum_.IsUint64()) {
1544                 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1545                 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1546             }
1547             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1548                 return false;
1549         }
1550 
1551         if (!maximum_.IsNull()) {
1552             if (maximum_.IsInt64()) {
1553                 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1554                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1555                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1556                 }
1557             }
1558             else if (maximum_.IsUint64()) { }
1559                 /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1560             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1561                 return false;
1562         }
1563 
1564         if (!multipleOf_.IsNull()) {
1565             if (multipleOf_.IsUint64()) {
1566                 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1567                     context.error_handler.NotMultipleOf(i, multipleOf_);
1568                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1569                 }
1570             }
1571             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1572                 return false;
1573         }
1574 
1575         return true;
1576     }
1577 
1578     bool CheckUint(Context& context, uint64_t i) const {
1579         if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1580             DisallowedType(context, GetIntegerString());
1581             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1582         }
1583 
1584         if (!minimum_.IsNull()) {
1585             if (minimum_.IsUint64()) {
1586                 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1587                     context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1588                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1589                 }
1590             }
1591             else if (minimum_.IsInt64())
1592                 /* do nothing */; // i >= 0 > minimum.Getint64()
1593             else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1594                 return false;
1595         }
1596 
1597         if (!maximum_.IsNull()) {
1598             if (maximum_.IsUint64()) {
1599                 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1600                     context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1601                     RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1602                 }
1603             }
1604             else if (maximum_.IsInt64()) {
1605                 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1606                 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum); // i >= 0 > maximum_
1607             }
1608             else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1609                 return false;
1610         }
1611 
1612         if (!multipleOf_.IsNull()) {
1613             if (multipleOf_.IsUint64()) {
1614                 if (i % multipleOf_.GetUint64() != 0) {
1615                     context.error_handler.NotMultipleOf(i, multipleOf_);
1616                     RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1617                 }
1618             }
1619             else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1620                 return false;
1621         }
1622 
1623         return true;
1624     }
1625 
1626     bool CheckDoubleMinimum(Context& context, double d) const {
1627         if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1628             context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1629             RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum);
1630         }
1631         return true;
1632     }
1633 
1634     bool CheckDoubleMaximum(Context& context, double d) const {
1635         if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1636             context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1637             RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum);
1638         }
1639         return true;
1640     }
1641 
1642     bool CheckDoubleMultipleOf(Context& context, double d) const {
1643         double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1644         double q = a / b;
1645         double qRounded = std::floor(q + 0.5);
1646         double scaledEpsilon = (q + qRounded) * std::numeric_limits<double>::epsilon();
1647         double difference = std::abs(qRounded - q);
1648         bool isMultiple = (difference <= scaledEpsilon)
1649                                         || (difference < std::numeric_limits<double>::min());
1650         if (!isMultiple) {
1651             context.error_handler.NotMultipleOf(d, multipleOf_);
1652             RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1653         }
1654         return true;
1655     }
1656 
1657     void DisallowedType(Context& context, const ValueType& actualType) const {
1658         ErrorHandler& eh = context.error_handler;
1659         eh.StartDisallowedType();
1660 
1661         if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1662         if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1663         if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1664         if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1665         if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1666 
1667         if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1668         else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1669 
1670         eh.EndDisallowedType(actualType);
1671     }
1672 
1673     struct Property {
1674         Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1675         ~Property() { AllocatorType::Free(dependencies); }
1676         SValue name;
1677         const SchemaType* schema;
1678         const SchemaType* dependenciesSchema;
1679         SizeType dependenciesValidatorIndex;
1680         bool* dependencies;
1681         bool required;
1682     };
1683 
1684     struct PatternProperty {
1685         PatternProperty() : schema(), pattern() {}
1686         ~PatternProperty() {
1687             if (pattern) {
1688                 pattern->~RegexType();
1689                 AllocatorType::Free(pattern);
1690             }
1691         }
1692         const SchemaType* schema;
1693         RegexType* pattern;
1694     };
1695 
1696     AllocatorType* allocator_;
1697     SValue uri_;
1698     UriType id_;
1699     Specification spec_;
1700     PointerType pointer_;
1701     const SchemaType* typeless_;
1702     uint64_t* enum_;
1703     SizeType enumCount_;
1704     SchemaArray allOf_;
1705     SchemaArray anyOf_;
1706     SchemaArray oneOf_;
1707     const SchemaType* not_;
1708     unsigned type_; // bitmask of kSchemaType
1709     SizeType validatorCount_;
1710     SizeType notValidatorIndex_;
1711 
1712     Property* properties_;
1713     const SchemaType* additionalPropertiesSchema_;
1714     PatternProperty* patternProperties_;
1715     SizeType patternPropertyCount_;
1716     SizeType propertyCount_;
1717     SizeType minProperties_;
1718     SizeType maxProperties_;
1719     bool additionalProperties_;
1720     bool hasDependencies_;
1721     bool hasRequired_;
1722     bool hasSchemaDependencies_;
1723 
1724     const SchemaType* additionalItemsSchema_;
1725     const SchemaType* itemsList_;
1726     const SchemaType** itemsTuple_;
1727     SizeType itemsTupleCount_;
1728     SizeType minItems_;
1729     SizeType maxItems_;
1730     bool additionalItems_;
1731     bool uniqueItems_;
1732 
1733     RegexType* pattern_;
1734     SizeType minLength_;
1735     SizeType maxLength_;
1736 
1737     SValue minimum_;
1738     SValue maximum_;
1739     SValue multipleOf_;
1740     bool exclusiveMinimum_;
1741     bool exclusiveMaximum_;
1742 
1743     SizeType defaultValueLength_;
1744 
1745     bool readOnly_;
1746     bool writeOnly_;
1747     bool nullable_;
1748 };
1749 
1750 template<typename Stack, typename Ch>
1751 struct TokenHelper {
1752     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1753         *documentStack.template Push<Ch>() = '/';
1754         char buffer[21];
1755         size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1756         for (size_t i = 0; i < length; i++)
1757             *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1758     }
1759 };
1760 
1761 // Partial specialized version for char to prevent buffer copying.
1762 template <typename Stack>
1763 struct TokenHelper<Stack, char> {
1764     RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1765         if (sizeof(SizeType) == 4) {
1766             char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1767             *buffer++ = '/';
1768             const char* end = internal::u32toa(index, buffer);
1769              documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1770         }
1771         else {
1772             char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1773             *buffer++ = '/';
1774             const char* end = internal::u64toa(index, buffer);
1775             documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1776         }
1777     }
1778 };
1779 
1780 } // namespace internal
1781 
1782 ///////////////////////////////////////////////////////////////////////////////
1783 // IGenericRemoteSchemaDocumentProvider
1784 
1785 template <typename SchemaDocumentType>
1786 class IGenericRemoteSchemaDocumentProvider {
1787 public:
1788     typedef typename SchemaDocumentType::Ch Ch;
1789     typedef typename SchemaDocumentType::ValueType ValueType;
1790     typedef typename SchemaDocumentType::AllocatorType AllocatorType;
1791 
1792     virtual ~IGenericRemoteSchemaDocumentProvider() {}
1793     virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1794     virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri<ValueType, AllocatorType> uri, Specification& spec) {
1795         // Default implementation just calls through for compatibility
1796         // Following line suppresses unused parameter warning
1797         (void)spec;
1798         // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
1799         return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
1800     }
1801 };
1802 
1803 ///////////////////////////////////////////////////////////////////////////////
1804 // GenericSchemaDocument
1805 
1806 //! JSON schema document.
1807 /*!
1808     A JSON schema document is a compiled version of a JSON schema.
1809     It is basically a tree of internal::Schema.
1810 
1811     \note This is an immutable class (i.e. its instance cannot be modified after construction).
1812     \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1813     \tparam Allocator Allocator type for allocating memory of this document.
1814 */
1815 template <typename ValueT, typename Allocator = CrtAllocator>
1816 class GenericSchemaDocument {
1817 public:
1818     typedef ValueT ValueType;
1819     typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1820     typedef Allocator AllocatorType;
1821     typedef typename ValueType::EncodingType EncodingType;
1822     typedef typename EncodingType::Ch Ch;
1823     typedef internal::Schema<GenericSchemaDocument> SchemaType;
1824     typedef GenericPointer<ValueType, Allocator> PointerType;
1825     typedef GenericValue<EncodingType, AllocatorType> GValue;
1826     typedef GenericUri<ValueType, Allocator> UriType;
1827     typedef GenericStringRef<Ch> StringRefType;
1828     friend class internal::Schema<GenericSchemaDocument>;
1829     template <typename, typename, typename>
1830     friend class GenericSchemaValidator;
1831 
1832     //! Constructor.
1833     /*!
1834         Compile a JSON document into schema document.
1835 
1836         \param document A JSON document as source.
1837         \param uri The base URI of this schema document for purposes of violation reporting.
1838         \param uriLength Length of \c name, in code points.
1839         \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1840         \param allocator An optional allocator instance for allocating memory. Can be null.
1841         \param pointer An optional JSON pointer to the start of the schema document
1842         \param spec Optional schema draft or OpenAPI version. Used if no specification in document. Defaults to draft-04.
1843     */
1844     explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
1845         IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
1846         const PointerType& pointer = PointerType(), // PR #1393
1847         const Specification& spec = Specification(kDraft04)) :
1848         remoteProvider_(remoteProvider),
1849         allocator_(allocator),
1850         ownAllocator_(),
1851         root_(),
1852         typeless_(),
1853         schemaMap_(allocator, kInitialSchemaMapSize),
1854         schemaRef_(allocator, kInitialSchemaRefSize),
1855         spec_(spec),
1856         error_(kObjectType),
1857         currentError_()
1858     {
1859         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
1860         if (!allocator_)
1861             ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1862 
1863         Ch noUri[1] = {0};
1864         uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1865         docId_ = UriType(uri_, allocator_);
1866 
1867         typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1868         new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
1869 
1870         // Establish the schema draft or open api version.
1871         // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
1872         SetSchemaSpecification(document);
1873 
1874         // Generate root schema, it will call CreateSchema() to create sub-schemas,
1875         // And call HandleRefSchema() if there are $ref.
1876         // PR #1393 use input pointer if supplied
1877         root_ = typeless_;
1878         if (pointer.GetTokenCount() == 0) {
1879             CreateSchemaRecursive(&root_, pointer, document, document, docId_);
1880         }
1881         else if (const ValueType* v = pointer.Get(document)) {
1882             CreateSchema(&root_, pointer, *v, document, docId_);
1883         }
1884         else {
1885             GenericStringBuffer<EncodingType> sb;
1886             pointer.StringifyUriFragment(sb);
1887             SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
1888         }
1889 
1890         RAPIDJSON_ASSERT(root_ != 0);
1891 
1892         schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1893     }
1894 
1895 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1896     //! Move constructor in C++11
1897     GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1898         remoteProvider_(rhs.remoteProvider_),
1899         allocator_(rhs.allocator_),
1900         ownAllocator_(rhs.ownAllocator_),
1901         root_(rhs.root_),
1902         typeless_(rhs.typeless_),
1903         schemaMap_(std::move(rhs.schemaMap_)),
1904         schemaRef_(std::move(rhs.schemaRef_)),
1905         uri_(std::move(rhs.uri_)),
1906         docId_(std::move(rhs.docId_)),
1907         spec_(rhs.spec_),
1908         error_(std::move(rhs.error_)),
1909         currentError_(std::move(rhs.currentError_))
1910     {
1911         rhs.remoteProvider_ = 0;
1912         rhs.allocator_ = 0;
1913         rhs.ownAllocator_ = 0;
1914         rhs.typeless_ = 0;
1915     }
1916 #endif
1917 
1918     //! Destructor
1919     ~GenericSchemaDocument() {
1920         while (!schemaMap_.Empty())
1921             schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1922 
1923         if (typeless_) {
1924             typeless_->~SchemaType();
1925             Allocator::Free(typeless_);
1926         }
1927 
1928         // these may contain some allocator data so clear before deleting ownAllocator_
1929         uri_.SetNull();
1930         error_.SetNull();
1931         currentError_.SetNull();
1932 
1933         RAPIDJSON_DELETE(ownAllocator_);
1934     }
1935 
1936     const GValue& GetURI() const { return uri_; }
1937 
1938     const Specification& GetSpecification() const { return spec_; }
1939     bool IsSupportedSpecification() const { return spec_.IsSupported(); }
1940 
1941     //! Static method to get the specification of any schema document
1942     //  Returns kDraftNone if document is silent
1943     static const Specification GetSpecification(const ValueType& document) {
1944       SchemaDraft draft = GetSchemaDraft(document);
1945       if (draft != kDraftNone)
1946         return Specification(draft);
1947       else {
1948         OpenApiVersion oapi = GetOpenApiVersion(document);
1949         if (oapi != kVersionNone)
1950           return Specification(oapi);
1951       }
1952       return Specification(kDraftNone);
1953     }
1954 
1955     //! Get the root schema.
1956     const SchemaType& GetRoot() const { return *root_; }
1957 
1958     //! Gets the error object.
1959     GValue& GetError() { return error_; }
1960     const GValue& GetError() const { return error_; }
1961 
1962     static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) {
1963         switch (schemaErrorCode) {
1964             case kSchemaErrorStartUnknown:             return GetStartUnknownString();
1965             case kSchemaErrorRefPlainName:             return GetRefPlainNameString();
1966             case kSchemaErrorRefInvalid:               return GetRefInvalidString();
1967             case kSchemaErrorRefPointerInvalid:        return GetRefPointerInvalidString();
1968             case kSchemaErrorRefUnknown:               return GetRefUnknownString();
1969             case kSchemaErrorRefCyclical:              return GetRefCyclicalString();
1970             case kSchemaErrorRefNoRemoteProvider:      return GetRefNoRemoteProviderString();
1971             case kSchemaErrorRefNoRemoteSchema:        return GetRefNoRemoteSchemaString();
1972             case kSchemaErrorRegexInvalid:             return GetRegexInvalidString();
1973             case kSchemaErrorSpecUnknown:              return GetSpecUnknownString();
1974             case kSchemaErrorSpecUnsupported:          return GetSpecUnsupportedString();
1975             case kSchemaErrorSpecIllegal:              return GetSpecIllegalString();
1976             case kSchemaErrorReadOnlyAndWriteOnly:     return GetReadOnlyAndWriteOnlyString();
1977             default:                                   return GetNullString();
1978         }
1979     }
1980 
1981     //! Default error method
1982     void SchemaError(const SchemaErrorCode code, const PointerType& location) {
1983       currentError_ = GValue(kObjectType);
1984       AddCurrentError(code, location);
1985     }
1986 
1987     //! Method for error with single string value insert
1988     void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) {
1989       currentError_ = GValue(kObjectType);
1990       currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1991       AddCurrentError(code, location);
1992     }
1993 
1994     //! Method for error with invalid pointer
1995     void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) {
1996       currentError_ = GValue(kObjectType);
1997       currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1998       currentError_.AddMember(GetOffsetString(), static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_);
1999       AddCurrentError(code, location);
2000     }
2001 
2002   private:
2003     //! Prohibit copying
2004     GenericSchemaDocument(const GenericSchemaDocument&);
2005     //! Prohibit assignment
2006     GenericSchemaDocument& operator=(const GenericSchemaDocument&);
2007 
2008     typedef const PointerType* SchemaRefPtr; // PR #1393
2009 
2010     struct SchemaEntry {
2011         SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
2012         ~SchemaEntry() {
2013             if (owned) {
2014                 schema->~SchemaType();
2015                 Allocator::Free(schema);
2016             }
2017         }
2018         PointerType pointer;
2019         SchemaType* schema;
2020         bool owned;
2021     };
2022 
2023     void AddErrorInstanceLocation(GValue& result, const PointerType& location) {
2024       GenericStringBuffer<EncodingType> sb;
2025       location.StringifyUriFragment(sb);
2026       GValue instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
2027       result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2028     }
2029 
2030     void AddError(GValue& keyword, GValue& error) {
2031       typename GValue::MemberIterator member = error_.FindMember(keyword);
2032       if (member == error_.MemberEnd())
2033         error_.AddMember(keyword, error, *allocator_);
2034       else {
2035         if (member->value.IsObject()) {
2036           GValue errors(kArrayType);
2037           errors.PushBack(member->value, *allocator_);
2038           member->value = errors;
2039         }
2040         member->value.PushBack(error, *allocator_);
2041       }
2042     }
2043 
2044     void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
2045       RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2046       currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2047       AddErrorInstanceLocation(currentError_, location);
2048       AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2049     }
2050 
2051 #define RAPIDJSON_STRING_(name, ...) \
2052     static const StringRefType& Get##name##String() {\
2053         static const Ch s[] = { __VA_ARGS__, '\0' };\
2054         static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2055         return v;\
2056     }
2057 
2058     RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2059     RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2060     RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
2061     RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
2062 
2063     RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
2064     RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2065     RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
2066     RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
2067     RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2068     RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
2069     RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2070     RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2071     RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2072     RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
2073     RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r')
2074     RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
2075     RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
2076     RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2077 
2078 #undef RAPIDJSON_STRING_
2079 
2080     // Static method to get schema draft of any schema document
2081     static SchemaDraft GetSchemaDraft(const ValueType& document) {
2082         static const Ch kDraft03String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
2083         static const Ch kDraft04String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
2084         static const Ch kDraft05String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
2085         static const Ch kDraft06String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
2086         static const Ch kDraft07String[] = { 'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0', '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0' };
2087         static const Ch kDraft2019_09String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
2088         static const Ch kDraft2020_12String[] = { 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/', '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0' };
2089 
2090         if (!document.IsObject()) {
2091             return kDraftNone;
2092         }
2093 
2094         // Get the schema draft from the $schema keyword at the supplied location
2095         typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
2096         if (itr != document.MemberEnd()) {
2097             if (!itr->value.IsString()) return kDraftUnknown;
2098             const UriType draftUri(itr->value);
2099             // Check base uri for match
2100             if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04;
2101             if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05;
2102             if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06;
2103             if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07;
2104             if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03;
2105             if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09;
2106             if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12;
2107             return kDraftUnknown;
2108         }
2109         // $schema not found
2110         return kDraftNone;
2111     }
2112 
2113 
2114     // Get open api version of any schema document
2115     static OpenApiVersion GetOpenApiVersion(const ValueType& document) {
2116         static const Ch kVersion20String[] = { '2', '.', '0', '\0' };
2117         static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level
2118         static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level
2119         static SizeType len = internal::StrLen<Ch>(kVersion30String);
2120 
2121         if (!document.IsObject()) {
2122             return kVersionNone;
2123         }
2124 
2125         // Get the open api version from the swagger / openapi keyword at the supplied location
2126         typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
2127         if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
2128         if (itr != document.MemberEnd()) {
2129             if (!itr->value.IsString()) return kVersionUnknown;
2130             const ValueType kVersion20Value(kVersion20String);
2131             if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly
2132             const ValueType kVersion30Value(kVersion30String);
2133             if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x
2134             const ValueType kVersion31Value(kVersion31String);
2135             if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x
2136             return kVersionUnknown;
2137         }
2138         // swagger or openapi not found
2139         return kVersionNone;
2140     }
2141 
2142     // Get the draft of the schema or the open api version (which implies the draft).
2143     // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on.
2144     void SetSchemaSpecification(const ValueType& document) {
2145         // Look for '$schema', 'swagger' or 'openapi' keyword at document root
2146         SchemaDraft docDraft = GetSchemaDraft(document);
2147         OpenApiVersion docOapi = GetOpenApiVersion(document);
2148         // Error if both in document
2149         if (docDraft != kDraftNone && docOapi != kVersionNone)
2150           SchemaError(kSchemaErrorSpecIllegal, PointerType());
2151         // Use document draft or open api version if present or use spec from constructor
2152         if (docDraft != kDraftNone)
2153             spec_ = Specification(docDraft);
2154         else if (docOapi != kVersionNone)
2155             spec_ = Specification(docOapi);
2156         // Error if draft or version unknown
2157         if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2158           SchemaError(kSchemaErrorSpecUnknown, PointerType());
2159         else if (!spec_.IsSupported())
2160             SchemaError(kSchemaErrorSpecUnsupported, PointerType());
2161     }
2162 
2163     // Changed by PR #1393
2164     void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
2165         if (v.GetType() == kObjectType) {
2166             UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
2167 
2168             for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
2169                 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2170         }
2171         else if (v.GetType() == kArrayType)
2172             for (SizeType i = 0; i < v.Size(); i++)
2173                 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
2174     }
2175 
2176     // Changed by PR #1393
2177     const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
2178         RAPIDJSON_ASSERT(pointer.IsValid());
2179         GenericStringBuffer<EncodingType> sb;
2180         pointer.StringifyUriFragment(sb);
2181         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
2182         if (v.IsObject()) {
2183             if (const SchemaType* sc = GetSchema(pointer)) {
2184                 if (schema)
2185                     *schema = sc;
2186                 AddSchemaRefs(const_cast<SchemaType*>(sc));
2187             }
2188             else if (!HandleRefSchema(pointer, schema, v, document, id)) {
2189                 // The new schema constructor adds itself and its $ref(s) to schemaMap_
2190                 SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id);
2191                 if (schema)
2192                     *schema = s;
2193                 return s->GetId();
2194             }
2195         }
2196         else {
2197             if (schema)
2198                 *schema = typeless_;
2199             AddSchemaRefs(typeless_);
2200         }
2201         return id;
2202     }
2203 
2204     // Changed by PR #1393
2205     // TODO should this return a UriType& ?
2206     bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) {
2207         typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2208         if (itr == v.MemberEnd())
2209             return false;
2210 
2211         GenericStringBuffer<EncodingType> sb;
2212         source.StringifyUriFragment(sb);
2213         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
2214         // Resolve the source pointer to the $ref'ed schema (finally)
2215         new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2216 
2217         if (itr->value.IsString()) {
2218             SizeType len = itr->value.GetStringLength();
2219             if (len == 0)
2220                 SchemaError(kSchemaErrorRefInvalid, source);
2221             else {
2222                 // First resolve $ref against the in-scope id
2223                 UriType scopeId = UriType(id, allocator_);
2224                 UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2225                 RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
2226                 // See if the resolved $ref minus the fragment matches a resolved id in this document
2227                 // Search from the root. Returns the subschema in the document and its absolute JSON pointer.
2228                 PointerType basePointer = PointerType();
2229                 const ValueType *base = FindId(document, ref, basePointer, docId_, false);
2230                 if (!base) {
2231                     // Remote reference - call the remote document provider
2232                     if (!remoteProvider_)
2233                         SchemaError(kSchemaErrorRefNoRemoteProvider, source);
2234                     else {
2235                         if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
2236                             const Ch* s = ref.GetFragString();
2237                             len = ref.GetFragStringLength();
2238                             if (len <= 1 || s[1] == '/') {
2239                                 // JSON pointer fragment, absolute in the remote schema
2240                                 const PointerType pointer(s, len, allocator_);
2241                                 if (!pointer.IsValid())
2242                                     SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer);
2243                                 else {
2244                                     // Get the subschema
2245                                     if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
2246                                         if (schema)
2247                                             *schema = sc;
2248                                         AddSchemaRefs(const_cast<SchemaType *>(sc));
2249                                         return true;
2250                                     } else
2251                                         SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2252                                 }
2253                             } else
2254                                 // Plain name fragment, not allowed in remote schema
2255                                 SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2256                         } else
2257                           SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
2258                     }
2259                 }
2260                 else { // Local reference
2261                     const Ch* s = ref.GetFragString();
2262                     len = ref.GetFragStringLength();
2263                     if (len <= 1 || s[1] == '/') {
2264                         // JSON pointer fragment, relative to the resolved URI
2265                         const PointerType relPointer(s, len, allocator_);
2266                         if (!relPointer.IsValid())
2267                             SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
2268                         else {
2269                             // Get the subschema
2270                             if (const ValueType *pv = relPointer.Get(*base)) {
2271                                 // Now get the absolute JSON pointer by adding relative to base
2272                                 PointerType pointer(basePointer, allocator_);
2273                                 for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2274                                     pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2275                                 if (IsCyclicRef(pointer))
2276                                     SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2277                                 else {
2278                                     // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
2279                                     // TODO: cache pointer <-> id mapping
2280                                     size_t unresolvedTokenIndex;
2281                                     scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2282                                     CreateSchema(schema, pointer, *pv, document, scopeId);
2283                                     return true;
2284                                 }
2285                             } else
2286                                 SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2287                         }
2288                     } else {
2289                         // Plain name fragment, relative to the resolved URI
2290                         // Not supported in open api 2.0 and 3.0
2291                         PointerType pointer(allocator_);
2292                         if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2293                             SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2294                         // See if the fragment matches an id in this document.
2295                         // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
2296                         else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
2297                             if (IsCyclicRef(pointer))
2298                                 SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2299                             else {
2300                                 // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
2301                                 // TODO: cache pointer <-> id mapping
2302                                 size_t unresolvedTokenIndex;
2303                                 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2304                                 CreateSchema(schema, pointer, *pv, document, scopeId);
2305                                 return true;
2306                             }
2307                         } else
2308                             SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2309                     }
2310                 }
2311             }
2312         }
2313 
2314         // Invalid/Unknown $ref
2315         if (schema)
2316             *schema = typeless_;
2317         AddSchemaRefs(typeless_);
2318         return true;
2319     }
2320 
2321     //! Find the first subschema with a resolved 'id' that matches the specified URI.
2322     // If full specified use all URI else ignore fragment.
2323     // If found, return a pointer to the subschema and its JSON pointer.
2324     // TODO cache pointer <-> id mapping
2325     ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const {
2326         SizeType i = 0;
2327         ValueType* resval = 0;
2328         UriType tempuri = UriType(finduri, allocator_);
2329         UriType localuri = UriType(baseuri, allocator_);
2330         if (doc.GetType() == kObjectType) {
2331             // Establish the base URI of this object
2332             typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
2333             if (m != doc.MemberEnd() && m->value.GetType() == kStringType) {
2334                 localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
2335             }
2336             // See if it matches
2337             if (localuri.Match(finduri, full)) {
2338                 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
2339                 resval = const_cast<ValueType *>(&doc);
2340                 resptr = here;
2341                 return resval;
2342             }
2343             // No match, continue looking
2344             for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
2345                 if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) {
2346                     resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
2347                 }
2348                 if (resval) break;
2349             }
2350         } else if (doc.GetType() == kArrayType) {
2351             // Continue looking
2352             for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
2353                 if (v->GetType() == kObjectType || v->GetType() == kArrayType) {
2354                     resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
2355                 }
2356                 if (resval) break;
2357                 i++;
2358             }
2359         }
2360         return resval;
2361     }
2362 
2363     // Added by PR #1393
2364     void AddSchemaRefs(SchemaType* schema) {
2365         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
2366         while (!schemaRef_.Empty()) {
2367             SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
2368             SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
2369             new (entry) SchemaEntry(**ref, schema, false, allocator_);
2370         }
2371     }
2372 
2373     // Added by PR #1393
2374     bool IsCyclicRef(const PointerType& pointer) const {
2375         for (const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
2376             if (pointer == **ref)
2377                 return true;
2378         return false;
2379     }
2380 
2381     const SchemaType* GetSchema(const PointerType& pointer) const {
2382         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2383             if (pointer == target->pointer)
2384                 return target->schema;
2385         return 0;
2386     }
2387 
2388     PointerType GetPointer(const SchemaType* schema) const {
2389         for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2390             if (schema == target->schema)
2391                 return target->pointer;
2392         return PointerType();
2393     }
2394 
2395     const SchemaType* GetTypeless() const { return typeless_; }
2396 
2397     static const size_t kInitialSchemaMapSize = 64;
2398     static const size_t kInitialSchemaRefSize = 64;
2399 
2400     IRemoteSchemaDocumentProviderType* remoteProvider_;
2401     Allocator *allocator_;
2402     Allocator *ownAllocator_;
2403     const SchemaType* root_;                //!< Root schema.
2404     SchemaType* typeless_;
2405     internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas
2406     internal::Stack<Allocator> schemaRef_;  // Stores Pointer(s) from $ref(s) until resolved
2407     GValue uri_;                            // Schema document URI
2408     UriType docId_;
2409     Specification spec_;
2410     GValue error_;
2411     GValue currentError_;
2412 };
2413 
2414 //! GenericSchemaDocument using Value type.
2415 typedef GenericSchemaDocument<Value> SchemaDocument;
2416 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
2417 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
2418 
2419 ///////////////////////////////////////////////////////////////////////////////
2420 // GenericSchemaValidator
2421 
2422 //! JSON Schema Validator.
2423 /*!
2424     A SAX style JSON schema validator.
2425     It uses a \c GenericSchemaDocument to validate SAX events.
2426     It delegates the incoming SAX events to an output handler.
2427     The default output handler does nothing.
2428     It can be reused multiple times by calling \c Reset().
2429 
2430     \tparam SchemaDocumentType Type of schema document.
2431     \tparam OutputHandler Type of output handler. Default handler does nothing.
2432     \tparam StateAllocator Allocator for storing the internal validation states.
2433 */
2434 template <
2435     typename SchemaDocumentType,
2436     typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
2437     typename StateAllocator = CrtAllocator>
2438 class GenericSchemaValidator :
2439     public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, 
2440     public internal::ISchemaValidator,
2441     public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
2442 public:
2443     typedef typename SchemaDocumentType::SchemaType SchemaType;
2444     typedef typename SchemaDocumentType::PointerType PointerType;
2445     typedef typename SchemaType::EncodingType EncodingType;
2446     typedef typename SchemaType::SValue SValue;
2447     typedef typename EncodingType::Ch Ch;
2448     typedef GenericStringRef<Ch> StringRefType;
2449     typedef GenericValue<EncodingType, StateAllocator> ValueType;
2450 
2451     //! Constructor without output handler.
2452     /*!
2453         \param schemaDocument The schema document to conform to.
2454         \param allocator Optional allocator for storing internal validation states.
2455         \param schemaStackCapacity Optional initial capacity of schema path stack.
2456         \param documentStackCapacity Optional initial capacity of document path stack.
2457     */
2458     GenericSchemaValidator(
2459         const SchemaDocumentType& schemaDocument,
2460         StateAllocator* allocator = 0, 
2461         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2462         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2463         :
2464         schemaDocument_(&schemaDocument),
2465         root_(schemaDocument.GetRoot()),
2466         stateAllocator_(allocator),
2467         ownStateAllocator_(0),
2468         schemaStack_(allocator, schemaStackCapacity),
2469         documentStack_(allocator, documentStackCapacity),
2470         outputHandler_(0),
2471         error_(kObjectType),
2472         currentError_(),
2473         missingDependents_(),
2474         valid_(true),
2475         flags_(kValidateDefaultFlags),
2476         depth_(0)
2477     {
2478         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
2479     }
2480 
2481     //! Constructor with output handler.
2482     /*!
2483         \param schemaDocument The schema document to conform to.
2484         \param allocator Optional allocator for storing internal validation states.
2485         \param schemaStackCapacity Optional initial capacity of schema path stack.
2486         \param documentStackCapacity Optional initial capacity of document path stack.
2487     */
2488     GenericSchemaValidator(
2489         const SchemaDocumentType& schemaDocument,
2490         OutputHandler& outputHandler,
2491         StateAllocator* allocator = 0, 
2492         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2493         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2494         :
2495         schemaDocument_(&schemaDocument),
2496         root_(schemaDocument.GetRoot()),
2497         stateAllocator_(allocator),
2498         ownStateAllocator_(0),
2499         schemaStack_(allocator, schemaStackCapacity),
2500         documentStack_(allocator, documentStackCapacity),
2501         outputHandler_(&outputHandler),
2502         error_(kObjectType),
2503         currentError_(),
2504         missingDependents_(),
2505         valid_(true),
2506         flags_(kValidateDefaultFlags),
2507         depth_(0)
2508     {
2509         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)");
2510     }
2511 
2512     //! Destructor.
2513     ~GenericSchemaValidator() {
2514         Reset();
2515         RAPIDJSON_DELETE(ownStateAllocator_);
2516     }
2517 
2518     //! Reset the internal states.
2519     void Reset() {
2520         while (!schemaStack_.Empty())
2521             PopSchema();
2522         documentStack_.Clear();
2523         ResetError();
2524     }
2525 
2526     //! Reset the error state.
2527     void ResetError() {
2528         error_.SetObject();
2529         currentError_.SetNull();
2530         missingDependents_.SetNull();
2531         valid_ = true;
2532     }
2533 
2534     //! Implementation of ISchemaValidator
2535     void SetValidateFlags(unsigned flags) {
2536         flags_ = flags;
2537     }
2538     virtual unsigned GetValidateFlags() const {
2539         return flags_;
2540     }
2541 
2542     virtual bool IsValid() const {
2543         if (!valid_) return false;
2544         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
2545         return true;
2546     }
2547     //! End of Implementation of ISchemaValidator
2548 
2549     //! Gets the error object.
2550     ValueType& GetError() { return error_; }
2551     const ValueType& GetError() const { return error_; }
2552 
2553     //! Gets the JSON pointer pointed to the invalid schema.
2554     //  If reporting all errors, the stack will be empty.
2555     PointerType GetInvalidSchemaPointer() const {
2556         return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2557     }
2558 
2559     //! Gets the keyword of invalid schema.
2560     //  If reporting all errors, the stack will be empty, so return "errors".
2561     const Ch* GetInvalidSchemaKeyword() const {
2562         if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
2563         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return static_cast<const Ch*>(GetErrorsString());
2564         return 0;
2565     }
2566 
2567     //! Gets the error code of invalid schema.
2568     //  If reporting all errors, the stack will be empty, so return kValidateErrors.
2569     ValidateErrorCode GetInvalidSchemaCode() const {
2570         if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
2571         if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
2572         return kValidateErrorNone;
2573     }
2574 
2575     //! Gets the JSON pointer pointed to the invalid value.
2576     //  If reporting all errors, the stack will be empty.
2577     PointerType GetInvalidDocumentPointer() const {
2578         if (documentStack_.Empty()) {
2579             return PointerType();
2580         }
2581         else {
2582             return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
2583         }
2584     }
2585 
2586     void NotMultipleOf(int64_t actual, const SValue& expected) {
2587         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2588     }
2589     void NotMultipleOf(uint64_t actual, const SValue& expected) {
2590         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2591     }
2592     void NotMultipleOf(double actual, const SValue& expected) {
2593         AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2594     }
2595     void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
2596         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2597             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2598     }
2599     void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
2600         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2601             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2602     }
2603     void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
2604         AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2605             exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2606     }
2607     void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
2608         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2609             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2610     }
2611     void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
2612         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2613             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2614     }
2615     void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
2616         AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2617             exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2618     }
2619 
2620     void TooLong(const Ch* str, SizeType length, SizeType expected) {
2621         AddNumberError(kValidateErrorMaxLength,
2622             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2623     }
2624     void TooShort(const Ch* str, SizeType length, SizeType expected) {
2625         AddNumberError(kValidateErrorMinLength,
2626             ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2627     }
2628     void DoesNotMatch(const Ch* str, SizeType length) {
2629         currentError_.SetObject();
2630         currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2631         AddCurrentError(kValidateErrorPattern);
2632     }
2633 
2634     void DisallowedItem(SizeType index) {
2635         currentError_.SetObject();
2636         currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2637         AddCurrentError(kValidateErrorAdditionalItems, true);
2638     }
2639     void TooFewItems(SizeType actualCount, SizeType expectedCount) {
2640         AddNumberError(kValidateErrorMinItems,
2641             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2642     }
2643     void TooManyItems(SizeType actualCount, SizeType expectedCount) {
2644         AddNumberError(kValidateErrorMaxItems,
2645             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2646     }
2647     void DuplicateItems(SizeType index1, SizeType index2) {
2648         ValueType duplicates(kArrayType);
2649         duplicates.PushBack(index1, GetStateAllocator());
2650         duplicates.PushBack(index2, GetStateAllocator());
2651         currentError_.SetObject();
2652         currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2653         AddCurrentError(kValidateErrorUniqueItems, true);
2654     }
2655 
2656     void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
2657         AddNumberError(kValidateErrorMaxProperties,
2658             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2659     }
2660     void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
2661         AddNumberError(kValidateErrorMinProperties,
2662             ValueType(actualCount).Move(), SValue(expectedCount).Move());
2663     }
2664     void StartMissingProperties() {
2665         currentError_.SetArray();
2666     }
2667     void AddMissingProperty(const SValue& name) {
2668         currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2669     }
2670     bool EndMissingProperties() {
2671         if (currentError_.Empty())
2672             return false;
2673         ValueType error(kObjectType);
2674         error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2675         currentError_ = error;
2676         AddCurrentError(kValidateErrorRequired);
2677         return true;
2678     }
2679     void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
2680         for (SizeType i = 0; i < count; ++i)
2681             MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2682     }
2683     void DisallowedProperty(const Ch* name, SizeType length) {
2684         currentError_.SetObject();
2685         currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2686         AddCurrentError(kValidateErrorAdditionalProperties, true);
2687     }
2688 
2689     void StartDependencyErrors() {
2690         currentError_.SetObject();
2691     }
2692     void StartMissingDependentProperties() {
2693         missingDependents_.SetArray();
2694     }
2695     void AddMissingDependentProperty(const SValue& targetName) {
2696         missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2697     }
2698     void EndMissingDependentProperties(const SValue& sourceName) {
2699         if (!missingDependents_.Empty()) {
2700             // Create equivalent 'required' error
2701             ValueType error(kObjectType);
2702             ValidateErrorCode code = kValidateErrorRequired;
2703             error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2704             AddErrorCode(error, code);
2705             AddErrorInstanceLocation(error, false);
2706             // When appending to a pointer ensure its allocator is used
2707             PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2708             AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2709             ValueType wrapper(kObjectType);
2710             wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2711             currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2712         }
2713     }
2714     void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2715         currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2716             static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2717     }
2718     bool EndDependencyErrors() {
2719         if (currentError_.ObjectEmpty())
2720             return false;
2721         ValueType error(kObjectType);
2722         error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2723         currentError_ = error;
2724         AddCurrentError(kValidateErrorDependencies);
2725         return true;
2726     }
2727 
2728     void DisallowedValue(const ValidateErrorCode code = kValidateErrorEnum) {
2729         currentError_.SetObject();
2730         AddCurrentError(code);
2731     }
2732     void StartDisallowedType() {
2733         currentError_.SetArray();
2734     }
2735     void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
2736         currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2737     }
2738     void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
2739         ValueType error(kObjectType);
2740         error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2741         error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2742         currentError_ = error;
2743         AddCurrentError(kValidateErrorType);
2744     }
2745     void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2746         // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
2747         AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2748         //for (SizeType i = 0; i < count; ++i) {
2749         //    MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2750         //}
2751     }
2752     void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2753         AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
2754     }
2755     void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2756         AddErrorArray(kValidateErrorOneOf, subvalidators, count);
2757     }
2758     void MultipleOneOf(SizeType index1, SizeType index2) {
2759         ValueType matches(kArrayType);
2760         matches.PushBack(index1, GetStateAllocator());
2761         matches.PushBack(index2, GetStateAllocator());
2762         currentError_.SetObject();
2763         currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
2764         AddCurrentError(kValidateErrorOneOfMatch);
2765     }
2766     void Disallowed() {
2767         currentError_.SetObject();
2768         AddCurrentError(kValidateErrorNot);
2769     }
2770     void DisallowedWhenWriting() {
2771         currentError_.SetObject();
2772         AddCurrentError(kValidateErrorReadOnly);
2773     }
2774     void DisallowedWhenReading() {
2775         currentError_.SetObject();
2776         AddCurrentError(kValidateErrorWriteOnly);
2777     }
2778 
2779 #define RAPIDJSON_STRING_(name, ...) \
2780     static const StringRefType& Get##name##String() {\
2781         static const Ch s[] = { __VA_ARGS__, '\0' };\
2782         static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2783         return v;\
2784     }
2785 
2786     RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2787     RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2788     RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2789     RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2790     RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2791     RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2792     RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2793     RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2794     RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2795     RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2796     RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
2797 
2798 #undef RAPIDJSON_STRING_
2799 
2800 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2801     if (!valid_) return false; \
2802     if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2803         *documentStack_.template Push<Ch>() = '\0';\
2804         documentStack_.template Pop<Ch>(1);\
2805         RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
2806         valid_ = false;\
2807         return valid_;\
2808     }
2809 
2810 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2811     for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2812         if (context->hasher)\
2813             static_cast<HasherType*>(context->hasher)->method arg2;\
2814         if (context->validators)\
2815             for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2816                 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2817         if (context->patternPropertiesValidators)\
2818             for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2819                 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2820     }
2821 
2822 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2823     valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2824     return valid_;
2825 
2826 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2827     RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\
2828     RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2829     RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)
2830 
2831     bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()), ( )); }
2832     bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }
2833     bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }
2834     bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }
2835     bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }
2836     bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2837     bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2838     bool RawNumber(const Ch* str, SizeType length, bool copy)
2839                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2840     bool String(const Ch* str, SizeType length, bool copy)
2841                                     { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2842 
2843     bool StartObject() {
2844         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
2845         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2846         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2847         valid_ = !outputHandler_ || outputHandler_->StartObject();
2848         return valid_;
2849     }
2850     
2851     bool Key(const Ch* str, SizeType len, bool copy) {
2852         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
2853         if (!valid_) return false;
2854         AppendToken(str, len);
2855         if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
2856             valid_ = false;
2857             return valid_;
2858         }
2859         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2860         valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2861         return valid_;
2862     }
2863     
2864     bool EndObject(SizeType memberCount) {
2865         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
2866         if (!valid_) return false;
2867         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2868         if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) { 
2869             valid_ = false; 
2870             return valid_; 
2871         }
2872         RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2873     }
2874 
2875     bool StartArray() {
2876         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
2877         RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2878         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2879         valid_ = !outputHandler_ || outputHandler_->StartArray();
2880         return valid_;
2881     }
2882     
2883     bool EndArray(SizeType elementCount) {
2884         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
2885         if (!valid_) return false;
2886         RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2887         if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
2888             valid_ = false;
2889             return valid_;
2890         }
2891         RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2892     }
2893 
2894 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2895 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2896 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2897 
2898     // Implementation of ISchemaStateFactory<SchemaType>
2899     virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
2900         *documentStack_.template Push<Ch>() = '\0';
2901         documentStack_.template Pop<Ch>(1);
2902         ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2903         depth_ + 1,
2904         &GetStateAllocator());
2905         sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~static_cast<unsigned>(kValidateContinueOnErrorFlag));
2906         return sv;
2907     }
2908 
2909     virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2910         GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
2911         v->~GenericSchemaValidator();
2912         StateAllocator::Free(v);
2913     }
2914 
2915     virtual void* CreateHasher() {
2916         return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
2917     }
2918 
2919     virtual uint64_t GetHashCode(void* hasher) {
2920         return static_cast<HasherType*>(hasher)->GetHashCode();
2921     }
2922 
2923     virtual void DestroryHasher(void* hasher) {
2924         HasherType* h = static_cast<HasherType*>(hasher);
2925         h->~HasherType();
2926         StateAllocator::Free(h);
2927     }
2928 
2929     virtual void* MallocState(size_t size) {
2930         return GetStateAllocator().Malloc(size);
2931     }
2932 
2933     virtual void FreeState(void* p) {
2934         StateAllocator::Free(p);
2935     }
2936     // End of implementation of ISchemaStateFactory<SchemaType>
2937 
2938 private:
2939     typedef typename SchemaType::Context Context;
2940     typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2941     typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2942 
2943     GenericSchemaValidator( 
2944         const SchemaDocumentType& schemaDocument,
2945         const SchemaType& root,
2946         const char* basePath, size_t basePathSize,
2947         unsigned depth,
2948         StateAllocator* allocator = 0,
2949         size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2950         size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2951         :
2952         schemaDocument_(&schemaDocument),
2953         root_(root),
2954         stateAllocator_(allocator),
2955         ownStateAllocator_(0),
2956         schemaStack_(allocator, schemaStackCapacity),
2957         documentStack_(allocator, documentStackCapacity),
2958         outputHandler_(0),
2959         error_(kObjectType),
2960         currentError_(),
2961         missingDependents_(),
2962         valid_(true),
2963         flags_(kValidateDefaultFlags),
2964         depth_(depth)
2965     {
2966         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : "");
2967         if (basePath && basePathSize)
2968             memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2969     }
2970 
2971     StateAllocator& GetStateAllocator() {
2972         if (!stateAllocator_)
2973             stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
2974         return *stateAllocator_;
2975     }
2976 
2977     bool GetContinueOnErrors() const {
2978         return flags_ & kValidateContinueOnErrorFlag;
2979     }
2980 
2981     bool BeginValue() {
2982         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
2983         if (schemaStack_.Empty())
2984             PushSchema(root_);
2985         else {
2986             if (CurrentContext().inArray)
2987                 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2988 
2989             if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2990                 return false;
2991 
2992             SizeType count = CurrentContext().patternPropertiesSchemaCount;
2993             const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2994             typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2995             bool valueUniqueness = CurrentContext().valueUniqueness;
2996             RAPIDJSON_ASSERT(CurrentContext().valueSchema);
2997             PushSchema(*CurrentContext().valueSchema);
2998 
2999             if (count > 0) {
3000                 CurrentContext().objectPatternValidatorType = patternValidatorType;
3001                 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3002                 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3003                 va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
3004                 std::memset(va, 0, sizeof(ISchemaValidator*) * count);
3005                 for (SizeType i = 0; i < count; i++)
3006                     va[validatorCount++] = CreateSchemaValidator(*sa[i], true);  // Inherit continueOnError
3007             }
3008 
3009             CurrentContext().arrayUniqueness = valueUniqueness;
3010         }
3011         return true;
3012     }
3013 
3014     bool EndValue() {
3015         RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
3016         if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3017             return false;
3018 
3019         GenericStringBuffer<EncodingType> sb;
3020         schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3021         *documentStack_.template Push<Ch>() = '\0';
3022         documentStack_.template Pop<Ch>(1);
3023         RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3024         void* hasher = CurrentContext().hasher;
3025         uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
3026         
3027         PopSchema();
3028 
3029         if (!schemaStack_.Empty()) {
3030             Context& context = CurrentContext();
3031             // Only check uniqueness if there is a hasher
3032             if (hasher && context.valueUniqueness) {
3033                 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
3034                 if (!a)
3035                     CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
3036                 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
3037                     if (itr->GetUint64() == h) {
3038                         DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
3039                         // Cleanup before returning if continuing
3040                         if (GetContinueOnErrors()) {
3041                             a->PushBack(h, GetStateAllocator());
3042                             while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
3043                         }
3044                         RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
3045                     }
3046                 a->PushBack(h, GetStateAllocator());
3047             }
3048         }
3049 
3050         // Remove the last token of document pointer
3051         while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
3052             ;
3053 
3054         return true;
3055     }
3056 
3057     void AppendToken(const Ch* str, SizeType len) {
3058         documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
3059         *documentStack_.template PushUnsafe<Ch>() = '/';
3060         for (SizeType i = 0; i < len; i++) {
3061             if (str[i] == '~') {
3062                 *documentStack_.template PushUnsafe<Ch>() = '~';
3063                 *documentStack_.template PushUnsafe<Ch>() = '0';
3064             }
3065             else if (str[i] == '/') {
3066                 *documentStack_.template PushUnsafe<Ch>() = '~';
3067                 *documentStack_.template PushUnsafe<Ch>() = '1';
3068             }
3069             else
3070                 *documentStack_.template PushUnsafe<Ch>() = str[i];
3071         }
3072     }
3073 
3074     RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_); }
3075     
3076     RAPIDJSON_FORCEINLINE void PopSchema() {
3077         Context* c = schemaStack_.template Pop<Context>(1);
3078         if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
3079             a->~HashCodeArray();
3080             StateAllocator::Free(a);
3081         }
3082         c->~Context();
3083     }
3084 
3085     void AddErrorInstanceLocation(ValueType& result, bool parent) {
3086         GenericStringBuffer<EncodingType> sb;
3087         PointerType instancePointer = GetInvalidDocumentPointer();
3088         ((parent && instancePointer.GetTokenCount() > 0)
3089          ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3090          : instancePointer).StringifyUriFragment(sb);
3091         ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
3092                               GetStateAllocator());
3093         result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3094     }
3095 
3096     void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
3097         GenericStringBuffer<EncodingType> sb;
3098         SizeType len = CurrentSchema().GetURI().GetStringLength();
3099         if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
3100         if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
3101         else GetInvalidSchemaPointer().StringifyUriFragment(sb);
3102         ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
3103             GetStateAllocator());
3104         result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3105     }
3106 
3107     void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
3108         result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3109     }
3110 
3111     void AddError(ValueType& keyword, ValueType& error) {
3112         typename ValueType::MemberIterator member = error_.FindMember(keyword);
3113         if (member == error_.MemberEnd())
3114             error_.AddMember(keyword, error, GetStateAllocator());
3115         else {
3116             if (member->value.IsObject()) {
3117                 ValueType errors(kArrayType);
3118                 errors.PushBack(member->value, GetStateAllocator());
3119                 member->value = errors;
3120             }
3121             member->value.PushBack(error, GetStateAllocator());
3122         }
3123     }
3124 
3125     void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
3126         AddErrorCode(currentError_, code);
3127         AddErrorInstanceLocation(currentError_, parent);
3128         AddErrorSchemaLocation(currentError_);
3129         AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
3130     }
3131 
3132     void MergeError(ValueType& other) {
3133         for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
3134             AddError(it->name, it->value);
3135         }
3136     }
3137 
3138     void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
3139         const typename SchemaType::ValueType& (*exclusive)() = 0) {
3140         currentError_.SetObject();
3141         currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
3142         currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
3143         if (exclusive)
3144             currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
3145         AddCurrentError(code);
3146     }
3147 
3148     void AddErrorArray(const ValidateErrorCode code,
3149         ISchemaValidator** subvalidators, SizeType count) {
3150         ValueType errors(kArrayType);
3151         for (SizeType i = 0; i < count; ++i)
3152             errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
3153         currentError_.SetObject();
3154         currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
3155         AddCurrentError(code);
3156     }
3157 
3158     const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
3159     Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
3160     const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
3161 
3162     static const size_t kDefaultSchemaStackCapacity = 1024;
3163     static const size_t kDefaultDocumentStackCapacity = 256;
3164     const SchemaDocumentType* schemaDocument_;
3165     const SchemaType& root_;
3166     StateAllocator* stateAllocator_;
3167     StateAllocator* ownStateAllocator_;
3168     internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)
3169     internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)
3170     OutputHandler* outputHandler_;
3171     ValueType error_;
3172     ValueType currentError_;
3173     ValueType missingDependents_;
3174     bool valid_;
3175     unsigned flags_;
3176     unsigned depth_;
3177 };
3178 
3179 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
3180 
3181 ///////////////////////////////////////////////////////////////////////////////
3182 // SchemaValidatingReader
3183 
3184 //! A helper class for parsing with validation.
3185 /*!
3186     This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
3187 
3188     \tparam parseFlags Combination of \ref ParseFlag.
3189     \tparam InputStream Type of input stream, implementing Stream concept.
3190     \tparam SourceEncoding Encoding of the input stream.
3191     \tparam SchemaDocumentType Type of schema document.
3192     \tparam StackAllocator Allocator type for stack.
3193 */
3194 template <
3195     unsigned parseFlags,
3196     typename InputStream,
3197     typename SourceEncoding,
3198     typename SchemaDocumentType = SchemaDocument,
3199     typename StackAllocator = CrtAllocator>
3200 class SchemaValidatingReader {
3201 public:
3202     typedef typename SchemaDocumentType::PointerType PointerType;
3203     typedef typename InputStream::Ch Ch;
3204     typedef GenericValue<SourceEncoding, StackAllocator> ValueType;
3205 
3206     //! Constructor
3207     /*!
3208         \param is Input stream.
3209         \param sd Schema document.
3210     */
3211     SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
3212 
3213     template <typename Handler>
3214     bool operator()(Handler& handler) {
3215         GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
3216         GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
3217         parseResult_ = reader.template Parse<parseFlags>(is_, validator);
3218 
3219         isValid_ = validator.IsValid();
3220         if (isValid_) {
3221             invalidSchemaPointer_ = PointerType();
3222             invalidSchemaKeyword_ = 0;
3223             invalidDocumentPointer_ = PointerType();
3224             error_.SetObject();
3225         }
3226         else {
3227             invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
3228             invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
3229             invalidSchemaCode_ = validator.GetInvalidSchemaCode();
3230             invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
3231             error_.CopyFrom(validator.GetError(), allocator_);
3232         }
3233 
3234         return parseResult_;
3235     }
3236 
3237     const ParseResult& GetParseResult() const { return parseResult_; }
3238     bool IsValid() const { return isValid_; }
3239     const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
3240     const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
3241     const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
3242     const ValueType& GetError() const { return error_; }
3243     ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
3244 
3245 private:
3246     InputStream& is_;
3247     const SchemaDocumentType& sd_;
3248 
3249     ParseResult parseResult_;
3250     PointerType invalidSchemaPointer_;
3251     const Ch* invalidSchemaKeyword_;
3252     PointerType invalidDocumentPointer_;
3253     ValidateErrorCode invalidSchemaCode_;
3254     StackAllocator allocator_;
3255     ValueType error_;
3256     bool isValid_;
3257 };
3258 
3259 RAPIDJSON_NAMESPACE_END
3260 RAPIDJSON_DIAG_POP
3261 
3262 #endif // RAPIDJSON_SCHEMA_H_