File indexing completed on 2025-02-21 10:13:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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)
0062 #endif
0063
0064 RAPIDJSON_NAMESPACE_BEGIN
0065
0066
0067
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 }
0142
0143 #endif
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
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
0166
0167
0168
0169
0170
0171
0172
0173 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
0174 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
0175 #endif
0176
0177
0178 enum ValidateFlag {
0179 kValidateNoFlags = 0,
0180 kValidateContinueOnErrorFlag = 1,
0181 kValidateReadFlag = 2,
0182 kValidateWriteFlag = 4,
0183 kValidateDefaultFlags = RAPIDJSON_VALIDATE_DEFAULT_FLAGS
0184 };
0185
0186
0187
0188 enum SchemaDraft {
0189 kDraftUnknown = -1,
0190 kDraftNone = 0,
0191 kDraft03 = 3,
0192 kDraftMin = 4,
0193 kDraft04 = 4,
0194 kDraft05 = 5,
0195 kDraftMax = 5,
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,
0206 kVersion20 = 2,
0207 kVersion30 = 3,
0208 kVersionMax = 3,
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
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
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
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
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
0327
0328
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
0367
0368 h ^= Hash(Hash(0, kv[i * 2]), kv[i * 2 + 1]);
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]);
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
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
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;
0498 void* arrayElementHashCodes;
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
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),
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
0582
0583
0584
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
0596
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
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(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
0639 notValidatorIndex_ = validatorCount_;
0640 validatorCount_++;
0641 }
0642 }
0643
0644
0645
0646 const ValueType* properties = GetMember(value, GetPropertiesString());
0647 const ValueType* required = GetMember(value, GetRequiredString());
0648 const ValueType* dependencies = GetMember(value, GetDependenciesString());
0649 {
0650
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
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
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
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
0757 if (const ValueType* v = GetMember(value, GetItemsString())) {
0758 PointerType q = p.Append(GetItemsString(), allocator_);
0759 if (v->IsObject())
0760 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
0761 else if (v->IsArray()) {
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
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
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
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
0807 if (const ValueType* v = GetMember(value, GetDefaultValueString()))
0808 if (v->IsString())
0809 defaultValueLength_ = v->GetStringLength();
0810
0811
0812
0813
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
0822
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
0885 context.valueSchema = typeless_;
0886
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
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) {
0928 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
0929 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
0930 }
0931 }
0932
0933
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
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_) {
1095 SizeType count = patternPropertyCount_ + 1;
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) {
1148
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;
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();
1240 case kValidateErrorMinimum: return GetMinimumString();
1241 case kValidateErrorExclusiveMinimum: return GetMinimumString();
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();
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
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;
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
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
1458
1459
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
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
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
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);
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
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 ;
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);
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_;
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
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);
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);
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 }
1781
1782
1783
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
1796
1797 (void)spec;
1798
1799 return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
1800 }
1801 };
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
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
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
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(),
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
1871
1872 SetSchemaSpecification(document);
1873
1874
1875
1876
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();
1893 }
1894
1895 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1896
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
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
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
1942
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
1956 const SchemaType& GetRoot() const { return *root_; }
1957
1958
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
1982 void SchemaError(const SchemaErrorCode code, const PointerType& location) {
1983 currentError_ = GValue(kObjectType);
1984 AddCurrentError(code, location);
1985 }
1986
1987
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
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
2004 GenericSchemaDocument(const GenericSchemaDocument&);
2005
2006 GenericSchemaDocument& operator=(const GenericSchemaDocument&);
2007
2008 typedef const PointerType* SchemaRefPtr;
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
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
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
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
2110 return kDraftNone;
2111 }
2112
2113
2114
2115 static OpenApiVersion GetOpenApiVersion(const ValueType& document) {
2116 static const Ch kVersion20String[] = { '2', '.', '0', '\0' };
2117 static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' };
2118 static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' };
2119 static SizeType len = internal::StrLen<Ch>(kVersion30String);
2120
2121 if (!document.IsObject()) {
2122 return kVersionNone;
2123 }
2124
2125
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;
2132 const ValueType kVersion30Value(kVersion30String);
2133 if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30;
2134 const ValueType kVersion31Value(kVersion31String);
2135 if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31;
2136 return kVersionUnknown;
2137 }
2138
2139 return kVersionNone;
2140 }
2141
2142
2143
2144 void SetSchemaSpecification(const ValueType& document) {
2145
2146 SchemaDraft docDraft = GetSchemaDraft(document);
2147 OpenApiVersion docOapi = GetOpenApiVersion(document);
2148
2149 if (docDraft != kDraftNone && docOapi != kVersionNone)
2150 SchemaError(kSchemaErrorSpecIllegal, PointerType());
2151
2152 if (docDraft != kDraftNone)
2153 spec_ = Specification(docDraft);
2154 else if (docOapi != kVersionNone)
2155 spec_ = Specification(docOapi);
2156
2157 if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2158 SchemaError(kSchemaErrorSpecUnknown, PointerType());
2159 else if (!spec_.IsSupported())
2160 SchemaError(kSchemaErrorSpecUnsupported, PointerType());
2161 }
2162
2163
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
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
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
2205
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
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
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
2227
2228 PointerType basePointer = PointerType();
2229 const ValueType *base = FindId(document, ref, basePointer, docId_, false);
2230 if (!base) {
2231
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
2240 const PointerType pointer(s, len, allocator_);
2241 if (!pointer.IsValid())
2242 SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer);
2243 else {
2244
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
2255 SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2256 } else
2257 SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
2258 }
2259 }
2260 else {
2261 const Ch* s = ref.GetFragString();
2262 len = ref.GetFragStringLength();
2263 if (len <= 1 || s[1] == '/') {
2264
2265 const PointerType relPointer(s, len, allocator_);
2266 if (!relPointer.IsValid())
2267 SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
2268 else {
2269
2270 if (const ValueType *pv = relPointer.Get(*base)) {
2271
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
2279
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
2290
2291 PointerType pointer(allocator_);
2292 if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2293 SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2294
2295
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
2301
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
2315 if (schema)
2316 *schema = typeless_;
2317 AddSchemaRefs(typeless_);
2318 return true;
2319 }
2320
2321
2322
2323
2324
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
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
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
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
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
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
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_;
2404 SchemaType* typeless_;
2405 internal::Stack<Allocator> schemaMap_;
2406 internal::Stack<Allocator> schemaRef_;
2407 GValue uri_;
2408 UriType docId_;
2409 Specification spec_;
2410 GValue error_;
2411 GValue currentError_;
2412 };
2413
2414
2415 typedef GenericSchemaDocument<Value> SchemaDocument;
2416
2417 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
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
2452
2453
2454
2455
2456
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
2482
2483
2484
2485
2486
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
2513 ~GenericSchemaValidator() {
2514 Reset();
2515 RAPIDJSON_DELETE(ownStateAllocator_);
2516 }
2517
2518
2519 void Reset() {
2520 while (!schemaStack_.Empty())
2521 PopSchema();
2522 documentStack_.Clear();
2523 ResetError();
2524 }
2525
2526
2527 void ResetError() {
2528 error_.SetObject();
2529 currentError_.SetNull();
2530 missingDependents_.SetNull();
2531 valid_ = true;
2532 }
2533
2534
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
2548
2549
2550 ValueType& GetError() { return error_; }
2551 const ValueType& GetError() const { return error_; }
2552
2553
2554
2555 PointerType GetInvalidSchemaPointer() const {
2556 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2557 }
2558
2559
2560
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
2568
2569 ValidateErrorCode GetInvalidSchemaCode() const {
2570 if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
2571 if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
2572 return kValidateErrorNone;
2573 }
2574
2575
2576
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
2701 ValueType error(kObjectType);
2702 ValidateErrorCode code = kValidateErrorRequired;
2703 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2704 AddErrorCode(error, code);
2705 AddErrorInstanceLocation(error, false);
2706
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
2747 AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2748
2749
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
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
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);
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
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
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
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);
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_;
3169 internal::Stack<StateAllocator> documentStack_;
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
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
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
3207
3208
3209
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