/home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/schema.h Source File

/home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/schema.h Source File#

Composable Kernel: /home/docs/checkouts/readthedocs.org/user_builds/advanced-micro-devices-composable-kernel/checkouts/develop/include/rapidjson/schema.h Source File
schema.h
Go to the documentation of this file.
1 // Tencent is pleased to support the open source community by making RapidJSON available->
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License-> You may obtain a copy of the License at
7 //
8 // http://opensource->org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied-> See the License for the
13 // specific language governing permissions and limitations under the License->
14 
15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
17 
18 #include "document.h"
19 #include "pointer.h"
20 #include "stringbuffer.h"
21 #include "error/en.h"
22 #include "uri.h"
23 #include <cmath> // abs, floor
24 
25 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
26 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
27 #endif
28 
29 #if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) || !(__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
30 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
31 #endif
32 
33 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
34 #include "internal/regex.h"
35 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
36 #include <regex>
37 #endif
38 
39 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
40 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
41 #else
42 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
43 #endif
44 
45 #ifndef RAPIDJSON_SCHEMA_VERBOSE
46 #define RAPIDJSON_SCHEMA_VERBOSE 0
47 #endif
48 
49 RAPIDJSON_DIAG_PUSH
50 
51 #if defined(__GNUC__)
52 RAPIDJSON_DIAG_OFF(effc++)
53 #endif
54 
55 #ifdef __clang__
56 RAPIDJSON_DIAG_OFF(weak-vtables)
57 RAPIDJSON_DIAG_OFF(exit-time-destructors)
58 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
59 RAPIDJSON_DIAG_OFF(variadic-macros)
60 #elif defined(_MSC_VER)
61 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
62 #endif
63 
65 
67 // Verbose Utilities
68 
69 #if RAPIDJSON_SCHEMA_VERBOSE
70 
71 namespace internal {
72 
73 inline void PrintInvalidKeywordData(const char* keyword) {
74  printf(" Fail keyword: '%s'\n", keyword);
75 }
76 
77 inline void PrintInvalidKeywordData(const wchar_t* keyword) {
78  wprintf(L" Fail keyword: '%ls'\n", keyword);
79 }
80 
81 inline void PrintInvalidDocumentData(const char* document) {
82  printf(" Fail document: '%s'\n", document);
83 }
84 
85 inline void PrintInvalidDocumentData(const wchar_t* document) {
86  wprintf(L" Fail document: '%ls'\n", document);
87 }
88 
89 inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth) {
90  printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
91 }
92 
93 inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth) {
94  wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
95 }
96 
97 inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved) {
98  printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
99 }
100 
101 inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved) {
102  wprintf(L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
103 }
104 
105 inline void PrintMethodData(const char* method) {
106  printf("%s\n", method);
107 }
108 
109 inline void PrintMethodData(const char* method, bool b) {
110  printf("%s, Data: '%s'\n", method, b ? "true" : "false");
111 }
112 
113 inline void PrintMethodData(const char* method, int64_t i) {
114  printf("%s, Data: '%" PRId64 "'\n", method, i);
115 }
116 
117 inline void PrintMethodData(const char* method, uint64_t u) {
118  printf("%s, Data: '%" PRIu64 "'\n", method, u);
119 }
120 
121 inline void PrintMethodData(const char* method, double d) {
122  printf("%s, Data: '%lf'\n", method, d);
123 }
124 
125 inline void PrintMethodData(const char* method, const char* s) {
126  printf("%s, Data: '%s'\n", method, s);
127 }
128 
129 inline void PrintMethodData(const char* method, const wchar_t* s) {
130  wprintf(L"%hs, Data: '%ls'\n", method, s);
131 }
132 
133 inline void PrintMethodData(const char* method, const char* s1, const char* s2) {
134  printf("%s, Data: '%s', '%s'\n", method, s1, s2);
135 }
136 
137 inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2) {
138  wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
139 }
140 
141 } // namespace internal
142 
143 #endif // RAPIDJSON_SCHEMA_VERBOSE
144 
145 #ifndef RAPIDJSON_SCHEMA_PRINT
146 #if RAPIDJSON_SCHEMA_VERBOSE
147 #define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
148 #else
149 #define RAPIDJSON_SCHEMA_PRINT(name, ...)
150 #endif
151 #endif
152 
154 // RAPIDJSON_INVALID_KEYWORD_RETURN
155 
156 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
157 RAPIDJSON_MULTILINEMACRO_BEGIN\
158  context.invalidCode = code;\
159  context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
160  RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\
161  return false;\
162 RAPIDJSON_MULTILINEMACRO_END
163 
165 // ValidateFlag
166 
173 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
174 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
175 #endif
176 
184 };
185 
187 // Specification
191  kDraft03 = 3,
192  kDraftMin = 4,
193  kDraft04 = 4,
194  kDraft05 = 5,
195  kDraftMax = 5,
196  kDraft06 = 6,
197  kDraft07 = 7,
199  kDraft2020_12 = 9
200 };
201 
210 };
211 
215  if (oapi == kVersion20) draft = kDraft04;
216  else if (oapi == kVersion30) draft = kDraft05;
217  else if (oapi == kVersion31) draft = kDraft2020_12;
218  else draft = kDraft04;
219  }
221  bool IsSupported() const {
222  return ((draft >= kDraftMin && draft <= kDraftMax) && ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
223  }
226 };
227 
229 // Forward declarations
230 
231 template <typename ValueType, typename Allocator>
233 
234 namespace internal {
235 
236 template <typename SchemaDocumentType>
237 class Schema;
238 
240 // ISchemaValidator
241 
243 public:
244  virtual ~ISchemaValidator() {}
245  virtual bool IsValid() const = 0;
246  virtual void SetValidateFlags(unsigned flags) = 0;
247  virtual unsigned GetValidateFlags() const = 0;
248 };
249 
251 // ISchemaStateFactory
252 
253 template <typename SchemaType>
255 public:
256  virtual ~ISchemaStateFactory() {}
257  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&, const bool inheritContinueOnErrors) = 0;
258  virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
259  virtual void* CreateHasher() = 0;
260  virtual uint64_t GetHashCode(void* hasher) = 0;
261  virtual void DestroryHasher(void* hasher) = 0;
262  virtual void* MallocState(size_t size) = 0;
263  virtual void FreeState(void* p) = 0;
264 };
265 
267 // IValidationErrorHandler
268 
269 template <typename SchemaType>
271 public:
272  typedef typename SchemaType::Ch Ch;
273  typedef typename SchemaType::SValue SValue;
274 
276 
277  virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
278  virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
279  virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
280  virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
281  virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
282  virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
283  virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
284  virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
285  virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
286 
287  virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
288  virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
289  virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
290 
291  virtual void DisallowedItem(SizeType index) = 0;
292  virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
293  virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
294  virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
295 
296  virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
297  virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
298  virtual void StartMissingProperties() = 0;
299  virtual void AddMissingProperty(const SValue& name) = 0;
300  virtual bool EndMissingProperties() = 0;
301  virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
302  virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
303 
304  virtual void StartDependencyErrors() = 0;
306  virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
307  virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
308  virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
309  virtual bool EndDependencyErrors() = 0;
310 
311  virtual void DisallowedValue(const ValidateErrorCode code) = 0;
312  virtual void StartDisallowedType() = 0;
313  virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
314  virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
315  virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
316  virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
317  virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
318  virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
319  virtual void Disallowed() = 0;
320  virtual void DisallowedWhenWriting() = 0;
321  virtual void DisallowedWhenReading() = 0;
322 };
323 
324 
326 // Hasher
327 
328 // For comparison of compound value
329 template<typename Encoding, typename Allocator>
330 class Hasher {
331 public:
332  typedef typename Encoding::Ch Ch;
333 
334  Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
335 
336  bool Null() { return WriteType(kNullType); }
337  bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
338  bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
339  bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
340  bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
341  bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
342  bool Double(double d) {
343  Number n;
344  if (d < 0) n.u.i = static_cast<int64_t>(d);
345  else n.u.u = static_cast<uint64_t>(d);
346  n.d = d;
347  return WriteNumber(n);
348  }
349 
350  bool RawNumber(const Ch* str, SizeType len, bool) {
351  WriteBuffer(kNumberType, str, len * sizeof(Ch));
352  return true;
353  }
354 
355  bool String(const Ch* str, SizeType len, bool) {
356  WriteBuffer(kStringType, str, len * sizeof(Ch));
357  return true;
358  }
359 
360  bool StartObject() { return true; }
361  bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
362  bool EndObject(SizeType memberCount) {
363  uint64_t h = Hash(0, kObjectType);
364  uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
365  for (SizeType i = 0; i < memberCount; i++)
366  // Issue #2205
367  // Hasing the key to avoid key=value cases with bug-prone zero-value hash
368  h ^= Hash(Hash(0, kv[i * 2]), kv[i * 2 + 1]); // Use xor to achieve member order insensitive
369  *stack_.template Push<uint64_t>() = h;
370  return true;
371  }
372 
373  bool StartArray() { return true; }
374  bool EndArray(SizeType elementCount) {
375  uint64_t h = Hash(0, kArrayType);
376  uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
377  for (SizeType i = 0; i < elementCount; i++)
378  h = Hash(h, e[i]); // Use hash to achieve element order sensitive
379  *stack_.template Push<uint64_t>() = h;
380  return true;
381  }
382 
383  bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
384 
387  return *stack_.template Top<uint64_t>();
388  }
389 
390 private:
391  static const size_t kDefaultSize = 256;
392  struct Number {
393  union U {
396  }u;
397  double d;
398  };
399 
400  bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
401 
402  bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
403 
404  bool WriteBuffer(Type type, const void* data, size_t len) {
405  // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
406  uint64_t h = Hash(RAPIDJSON_UINT64_C2(0xcbf29ce4, 0x84222325), type);
407  const unsigned char* d = static_cast<const unsigned char*>(data);
408  for (size_t i = 0; i < len; i++)
409  h = Hash(h, d[i]);
410  *stack_.template Push<uint64_t>() = h;
411  return true;
412  }
413 
414  static uint64_t Hash(uint64_t h, uint64_t d) {
415  static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
416  h ^= d;
417  h *= kPrime;
418  return h;
419  }
420 
421  Stack<Allocator> stack_;
422 };
423 
425 // SchemaValidationContext
426 
427 template <typename SchemaDocumentType>
433  typedef typename ValueType::Ch Ch;
434 
439  };
440 
442  factory(f),
443  error_handler(eh),
444  schema(s),
445  flags(fl),
446  valueSchema(),
447  invalidKeyword(),
448  invalidCode(),
449  hasher(),
451  validators(),
452  validatorCount(),
458  propertyExist(),
459  inArray(false),
460  valueUniqueness(false),
461  arrayUniqueness(false)
462  {
463  }
464 
466  if (hasher)
468  if (validators) {
469  for (SizeType i = 0; i < validatorCount; i++) {
470  if (validators[i]) {
472  }
473  }
475  }
477  for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) {
480  }
481  }
483  }
486  if (propertyExist)
488  }
489 
493  unsigned flags;
497  void* hasher; // Only validator access
498  void* arrayElementHashCodes; // Only validator access this
509  bool inArray;
512 };
513 
515 // Schema
516 
517 template <typename SchemaDocumentType>
518 class Schema {
519 public:
520  typedef typename SchemaDocumentType::ValueType ValueType;
521  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
522  typedef typename SchemaDocumentType::PointerType PointerType;
523  typedef typename ValueType::EncodingType EncodingType;
524  typedef typename EncodingType::Ch Ch;
531 
532  Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator, const UriType& id = UriType()) :
533  allocator_(allocator),
534  uri_(schemaDocument->GetURI(), *allocator),
535  id_(id, allocator),
536  spec_(schemaDocument->GetSpecification()),
537  pointer_(p, allocator),
538  typeless_(schemaDocument->GetTypeless()),
539  enum_(),
540  enumCount_(),
541  not_(),
542  type_((1 << kTotalSchemaType) - 1), // typeless
543  validatorCount_(),
544  notValidatorIndex_(),
545  properties_(),
546  additionalPropertiesSchema_(),
547  patternProperties_(),
548  patternPropertyCount_(),
549  propertyCount_(),
550  minProperties_(),
551  maxProperties_(SizeType(~0)),
552  additionalProperties_(true),
553  hasDependencies_(),
554  hasRequired_(),
555  hasSchemaDependencies_(),
556  additionalItemsSchema_(),
557  itemsList_(),
558  itemsTuple_(),
559  itemsTupleCount_(),
560  minItems_(),
561  maxItems_(SizeType(~0)),
562  additionalItems_(true),
563  uniqueItems_(false),
564  pattern_(),
565  minLength_(0),
566  maxLength_(~SizeType(0)),
567  exclusiveMinimum_(false),
568  exclusiveMaximum_(false),
569  defaultValueLength_(0),
570  readOnly_(false),
571  writeOnly_(false),
572  nullable_(false)
573  {
575  p.StringifyUriFragment(sb);
576  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
577 
578  typedef typename ValueType::ConstValueIterator ConstValueIterator;
579  typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
580 
581  // PR #1393
582  // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
583  // recursion (with recursive schemas), since schemaDocument->getSchema() is always
584  // checked before creating a new one. Don't cache typeless_, though.
585  if (this != typeless_) {
586  typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
587  SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
588  new (entry) SchemaEntry(pointer_, this, true, allocator_);
589  schemaDocument->AddSchemaRefs(this);
590  }
591 
592  if (!value.IsObject())
593  return;
594 
595  // If we have an id property, resolve it with the in-scope id
596  // Not supported for open api 2.0 or 3.0
597  if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
598  if (const ValueType* v = GetMember(value, GetIdString())) {
599  if (v->IsString()) {
600  UriType local(*v, allocator);
601  id_ = local.Resolve(id_, allocator);
602  RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), v->GetString(), id_.GetString());
603  }
604  }
605 
606  if (const ValueType* v = GetMember(value, GetTypeString())) {
607  type_ = 0;
608  if (v->IsString())
609  AddType(*v);
610  else if (v->IsArray())
611  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
612  AddType(*itr);
613  }
614 
615  if (const ValueType* v = GetMember(value, GetEnumString())) {
616  if (v->IsArray() && v->Size() > 0) {
617  enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
618  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
620  char buffer[256u + 24];
621  MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer, sizeof(buffer));
622  EnumHasherType h(&hasherAllocator, 256);
623  itr->Accept(h);
624  enum_[enumCount_++] = h.GetHashCode();
625  }
626  }
627  }
628 
629  if (schemaDocument)
630  AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
631 
632  // AnyOf, OneOf, Not not supported for open api 2.0
633  if (schemaDocument && spec_.oapi != kVersion20) {
634  AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
635  AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
636 
637  if (const ValueType* v = GetMember(value, GetNotString())) {
638  schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document, id_);
639  notValidatorIndex_ = validatorCount_;
640  validatorCount_++;
641  }
642  }
643 
644  // Object
645 
646  const ValueType* properties = GetMember(value, GetPropertiesString());
647  const ValueType* required = GetMember(value, GetRequiredString());
648  const ValueType* dependencies = GetMember(value, GetDependenciesString());
649  {
650  // Gather properties from properties/required/dependencies
651  SValue allProperties(kArrayType);
652 
653  if (properties && properties->IsObject())
654  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
655  AddUniqueElement(allProperties, itr->name);
656 
657  if (required && required->IsArray())
658  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
659  if (itr->IsString())
660  AddUniqueElement(allProperties, *itr);
661 
662  // Dependencies not supported for open api 2.0 and 3.0
663  if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
664  if (dependencies && dependencies->IsObject())
665  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
666  AddUniqueElement(allProperties, itr->name);
667  if (itr->value.IsArray())
668  for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
669  if (i->IsString())
670  AddUniqueElement(allProperties, *i);
671  }
672 
673  if (allProperties.Size() > 0) {
674  propertyCount_ = allProperties.Size();
675  properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
676  for (SizeType i = 0; i < propertyCount_; i++) {
677  new (&properties_[i]) Property();
678  properties_[i].name = allProperties[i];
679  properties_[i].schema = typeless_;
680  }
681  }
682  }
683 
684  if (properties && properties->IsObject()) {
685  PointerType q = p.Append(GetPropertiesString(), allocator_);
686  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
687  SizeType index;
688  if (FindPropertyIndex(itr->name, &index))
689  schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
690  }
691  }
692 
693  // PatternProperties not supported for open api 2.0 and 3.0
694  if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
695  if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
696  PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
697  patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
698  patternPropertyCount_ = 0;
699 
700  for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
701  new (&patternProperties_[patternPropertyCount_]) PatternProperty();
702  PointerType r = q.Append(itr->name, allocator_);
703  patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
704  schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
705  patternPropertyCount_++;
706  }
707  }
708 
709  if (required && required->IsArray())
710  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
711  if (itr->IsString()) {
712  SizeType index;
713  if (FindPropertyIndex(*itr, &index)) {
714  properties_[index].required = true;
715  hasRequired_ = true;
716  }
717  }
718 
719  // Dependencies not supported for open api 2.0 and 3.0
720  if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
721  if (dependencies && dependencies->IsObject()) {
722  PointerType q = p.Append(GetDependenciesString(), allocator_);
723  hasDependencies_ = true;
724  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
725  SizeType sourceIndex;
726  if (FindPropertyIndex(itr->name, &sourceIndex)) {
727  if (itr->value.IsArray()) {
728  properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
729  std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
730  for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
731  SizeType targetIndex;
732  if (FindPropertyIndex(*targetItr, &targetIndex))
733  properties_[sourceIndex].dependencies[targetIndex] = true;
734  }
735  }
736  else if (itr->value.IsObject()) {
737  hasSchemaDependencies_ = true;
738  schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
739  properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
740  validatorCount_++;
741  }
742  }
743  }
744  }
745 
746  if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
747  if (v->IsBool())
748  additionalProperties_ = v->GetBool();
749  else if (v->IsObject())
750  schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
751  }
752 
753  AssignIfExist(minProperties_, value, GetMinPropertiesString());
754  AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
755 
756  // Array
757  if (const ValueType* v = GetMember(value, GetItemsString())) {
758  PointerType q = p.Append(GetItemsString(), allocator_);
759  if (v->IsObject()) // List validation
760  schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
761  else if (v->IsArray()) { // Tuple validation
762  itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
763  SizeType index = 0;
764  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
765  schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
766  }
767  }
768 
769  AssignIfExist(minItems_, value, GetMinItemsString());
770  AssignIfExist(maxItems_, value, GetMaxItemsString());
771 
772  // AdditionalItems not supported for openapi 2.0 and 3.0
773  if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
774  if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
775  if (v->IsBool())
776  additionalItems_ = v->GetBool();
777  else if (v->IsObject())
778  schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
779  }
780 
781  AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
782 
783  // String
784  AssignIfExist(minLength_, value, GetMinLengthString());
785  AssignIfExist(maxLength_, value, GetMaxLengthString());
786 
787  if (const ValueType* v = GetMember(value, GetPatternString()))
788  pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
789 
790  // Number
791  if (const ValueType* v = GetMember(value, GetMinimumString()))
792  if (v->IsNumber())
793  minimum_.CopyFrom(*v, *allocator_);
794 
795  if (const ValueType* v = GetMember(value, GetMaximumString()))
796  if (v->IsNumber())
797  maximum_.CopyFrom(*v, *allocator_);
798 
799  AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
800  AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
801 
802  if (const ValueType* v = GetMember(value, GetMultipleOfString()))
803  if (v->IsNumber() && v->GetDouble() > 0.0)
804  multipleOf_.CopyFrom(*v, *allocator_);
805 
806  // Default
807  if (const ValueType* v = GetMember(value, GetDefaultValueString()))
808  if (v->IsString())
809  defaultValueLength_ = v->GetStringLength();
810 
811  // ReadOnly - open api only (until draft 7 supported)
812  // WriteOnly - open api 3 only (until draft 7 supported)
813  // Both can't be true
814  if (spec_.oapi != kVersionNone)
815  AssignIfExist(readOnly_, value, GetReadOnlyString());
816  if (spec_.oapi >= kVersion30)
817  AssignIfExist(writeOnly_, value, GetWriteOnlyString());
818  if (readOnly_ && writeOnly_)
819  schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
820 
821  // Nullable - open api 3 only
822  // If true add 'null' as allowable type
823  if (spec_.oapi >= kVersion30) {
824  AssignIfExist(nullable_, value, GetNullableString());
825  if (nullable_)
826  AddType(GetNullString());
827  }
828  }
829 
831  AllocatorType::Free(enum_);
832  if (properties_) {
833  for (SizeType i = 0; i < propertyCount_; i++)
834  properties_[i].~Property();
835  AllocatorType::Free(properties_);
836  }
837  if (patternProperties_) {
838  for (SizeType i = 0; i < patternPropertyCount_; i++)
839  patternProperties_[i].~PatternProperty();
840  AllocatorType::Free(patternProperties_);
841  }
842  AllocatorType::Free(itemsTuple_);
843 #if RAPIDJSON_SCHEMA_HAS_REGEX
844  if (pattern_) {
845  pattern_->~RegexType();
846  AllocatorType::Free(pattern_);
847  }
848 #endif
849  }
850 
851  const SValue& GetURI() const {
852  return uri_;
853  }
854 
855  const UriType& GetId() const {
856  return id_;
857  }
858 
860  return spec_;
861  }
862 
863  const PointerType& GetPointer() const {
864  return pointer_;
865  }
866 
867  bool BeginValue(Context& context) const {
868  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
869  if (context.inArray) {
870  if (uniqueItems_)
871  context.valueUniqueness = true;
872 
873  if (itemsList_)
874  context.valueSchema = itemsList_;
875  else if (itemsTuple_) {
876  if (context.arrayElementIndex < itemsTupleCount_)
877  context.valueSchema = itemsTuple_[context.arrayElementIndex];
878  else if (additionalItemsSchema_)
879  context.valueSchema = additionalItemsSchema_;
880  else if (additionalItems_)
881  context.valueSchema = typeless_;
882  else {
884  // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
885  context.valueSchema = typeless_;
886  // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
887  context.arrayElementIndex++;
889  }
890  }
891  else
892  context.valueSchema = typeless_;
893 
894  context.arrayElementIndex++;
895  }
896  return true;
897  }
898 
899  RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
900  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
901  // Only check pattern properties if we have validators
902  if (context.patternPropertiesValidatorCount > 0) {
903  bool otherValid = false;
906  otherValid = context.patternPropertiesValidators[--count]->IsValid();
907 
908  bool patternValid = true;
909  for (SizeType i = 0; i < count; i++)
910  if (!context.patternPropertiesValidators[i]->IsValid()) {
911  patternValid = false;
912  break;
913  }
914 
916  if (!patternValid) {
919  }
920  }
922  if (!patternValid || !otherValid) {
925  }
926  }
927  else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
930  }
931  }
932 
933  // For enums only check if we have a hasher
934  if (enum_ && context.hasher) {
935  const uint64_t h = context.factory.GetHashCode(context.hasher);
936  for (SizeType i = 0; i < enumCount_; i++)
937  if (enum_[i] == h)
938  goto foundEnum;
941  foundEnum:;
942  }
943 
944  // Only check allOf etc if we have validators
945  if (context.validatorCount > 0) {
946  if (allOf_.schemas)
947  for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
948  if (!context.validators[i]->IsValid()) {
949  context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
951  }
952 
953  if (anyOf_.schemas) {
954  for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
955  if (context.validators[i]->IsValid())
956  goto foundAny;
957  context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
959  foundAny:;
960  }
961 
962  if (oneOf_.schemas) {
963  bool oneValid = false;
964  SizeType firstMatch = 0;
965  for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
966  if (context.validators[i]->IsValid()) {
967  if (oneValid) {
968  context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
970  } else {
971  oneValid = true;
972  firstMatch = i - oneOf_.begin;
973  }
974  }
975  if (!oneValid) {
976  context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
978  }
979  }
980 
981  if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
982  context.error_handler.Disallowed();
984  }
985  }
986 
987  return true;
988  }
989 
990  bool Null(Context& context) const {
991  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
992  if (!(type_ & (1 << kNullSchemaType))) {
993  DisallowedType(context, GetNullString());
995  }
996  return CreateParallelValidator(context);
997  }
998 
999  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());
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());
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_);
1066  }
1067  if (count > maxLength_) {
1068  context.error_handler.TooLong(str, length, maxLength_);
1070  }
1071  }
1072  }
1073 
1074  if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
1075  context.error_handler.DoesNotMatch(str, length);
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());
1087  }
1088 
1089  if (hasDependencies_ || hasRequired_) {
1090  context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
1091  std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
1092  }
1093 
1094  if (patternProperties_) { // pre-allocate schema array
1095  SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
1096  context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
1097  context.patternPropertiesSchemaCount = 0;
1098  std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
1099  }
1100 
1101  return CreateParallelValidator(context);
1102  }
1103 
1104  bool Key(Context& context, const Ch* str, SizeType len, bool) const {
1105  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
1106 
1107  if (patternProperties_) {
1108  context.patternPropertiesSchemaCount = 0;
1109  for (SizeType i = 0; i < patternPropertyCount_; i++)
1110  if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
1111  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
1112  context.valueSchema = typeless_;
1113  }
1114  }
1115 
1116  SizeType index = 0;
1117  if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
1118  if (context.patternPropertiesSchemaCount > 0) {
1119  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
1120  context.valueSchema = typeless_;
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_;
1137  }
1138  else
1139  context.valueSchema = additionalPropertiesSchema_;
1140  return true;
1141  }
1142  else if (additionalProperties_) {
1143  context.valueSchema = typeless_;
1144  return true;
1145  }
1146 
1147  if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
1148  // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports spurious type error
1149  context.valueSchema = typeless_;
1150  context.error_handler.DisallowedProperty(str, len);
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_) {
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())
1167  }
1168 
1169  if (memberCount < minProperties_) {
1170  context.error_handler.TooFewProperties(memberCount, minProperties_);
1172  }
1173 
1174  if (memberCount > maxProperties_) {
1175  context.error_handler.TooManyProperties(memberCount, maxProperties_);
1177  }
1178 
1179  if (hasDependencies_) {
1181  for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1182  const Property& source = properties_[sourceIndex];
1183  if (context.propertyExist[sourceIndex]) {
1184  if (source.dependencies) {
1186  for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1187  if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1188  context.error_handler.AddMissingDependentProperty(properties_[targetIndex].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())
1200  }
1201 
1202  return true;
1203  }
1204 
1205  bool StartArray(Context& context) const {
1206  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
1207  context.arrayElementIndex = 0;
1208  context.inArray = true; // Ensure we note that we are in an array
1209 
1210  if (!(type_ & (1 << kArraySchemaType))) {
1211  DisallowedType(context, GetArrayString());
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_);
1225  }
1226 
1227  if (elementCount > maxItems_) {
1228  context.error_handler.TooManyItems(elementCount, maxItems_);
1230  }
1231 
1232  return true;
1233  }
1234 
1235  static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
1236  switch (validateErrorCode) {
1237  case kValidateErrorMultipleOf: return GetMultipleOfString();
1238  case kValidateErrorMaximum: return GetMaximumString();
1239  case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
1240  case kValidateErrorMinimum: return GetMinimumString();
1241  case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
1242 
1243  case kValidateErrorMaxLength: return GetMaxLengthString();
1244  case kValidateErrorMinLength: return GetMinLengthString();
1245  case kValidateErrorPattern: return GetPatternString();
1246 
1247  case kValidateErrorMaxItems: return GetMaxItemsString();
1248  case kValidateErrorMinItems: return GetMinItemsString();
1249  case kValidateErrorUniqueItems: return GetUniqueItemsString();
1250  case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
1251 
1252  case kValidateErrorMaxProperties: return GetMaxPropertiesString();
1253  case kValidateErrorMinProperties: return GetMinPropertiesString();
1254  case kValidateErrorRequired: return GetRequiredString();
1255  case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
1256  case kValidateErrorPatternProperties: return GetPatternPropertiesString();
1257  case kValidateErrorDependencies: return GetDependenciesString();
1258 
1259  case kValidateErrorEnum: return GetEnumString();
1260  case kValidateErrorType: return GetTypeString();
1261 
1262  case kValidateErrorOneOf: return GetOneOfString();
1263  case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
1264  case kValidateErrorAllOf: return GetAllOfString();
1265  case kValidateErrorAnyOf: return GetAnyOfString();
1266  case kValidateErrorNot: return GetNotString();
1267 
1268  case kValidateErrorReadOnly: return GetReadOnlyString();
1269  case kValidateErrorWriteOnly: return GetWriteOnlyString();
1270 
1271  default: return GetNullString();
1272  }
1273  }
1274 
1275 
1276  // Generate functions for string literal according to Ch
1277 #define RAPIDJSON_STRING_(name, ...) \
1278  static const ValueType& Get##name##String() {\
1279  static const Ch s[] = { __VA_ARGS__, '\0' };\
1280  static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1281  return v;\
1282  }
1283 
1284  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1285  RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1286  RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1287  RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1288  RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1289  RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1290  RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1291  RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1292  RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1293  RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1294  RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1295  RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1296  RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1297  RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1298  RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1299  RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1300  RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1301  RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1302  RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1303  RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1304  RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1305  RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1306  RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1307  RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1308  RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1309  RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1310  RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1311  RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1312  RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1313  RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1314  RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1315  RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1316  RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1317  RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1318  RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
1319  RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
1320  RAPIDJSON_STRING_(Id, 'i', 'd')
1321  RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
1322  RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
1323  RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
1324  RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
1325  RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
1326 
1327 #undef RAPIDJSON_STRING_
1328 
1329 private:
1330  enum SchemaValueType {
1331  kNullSchemaType,
1332  kBooleanSchemaType,
1333  kObjectSchemaType,
1334  kArraySchemaType,
1335  kStringSchemaType,
1336  kNumberSchemaType,
1337  kIntegerSchemaType,
1338  kTotalSchemaType
1339  };
1340 
1341 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1343 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1344  typedef std::basic_regex<Ch> RegexType;
1345 #else
1346  typedef char RegexType;
1347 #endif
1348 
1349  struct SchemaArray {
1350  SchemaArray() : schemas(), count() {}
1351  ~SchemaArray() { AllocatorType::Free(schemas); }
1352  const SchemaType** schemas;
1353  SizeType begin; // begin index of context.validators
1354  SizeType count;
1355  };
1356 
1357  template <typename V1, typename V2>
1358  void AddUniqueElement(V1& a, const V2& v) {
1359  for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1360  if (*itr == v)
1361  return;
1362  V1 c(v, *allocator_);
1363  a.PushBack(c, *allocator_);
1364  }
1365 
1366  static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
1367  typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1368  return itr != value.MemberEnd() ? &(itr->value) : 0;
1369  }
1370 
1371  static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
1372  if (const ValueType* v = GetMember(value, name))
1373  if (v->IsBool())
1374  out = v->GetBool();
1375  }
1376 
1377  static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
1378  if (const ValueType* v = GetMember(value, name))
1379  if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
1380  out = static_cast<SizeType>(v->GetUint64());
1381  }
1382 
1383  void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
1384  if (const ValueType* v = GetMember(value, name)) {
1385  if (v->IsArray() && v->Size() > 0) {
1386  PointerType q = p.Append(name, allocator_);
1387  out.count = v->Size();
1388  out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
1389  memset(out.schemas, 0, sizeof(Schema*)* out.count);
1390  for (SizeType i = 0; i < out.count; i++)
1391  schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1392  out.begin = validatorCount_;
1393  validatorCount_ += out.count;
1394  }
1395  }
1396  }
1397 
1398 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1399  template <typename ValueType>
1400  RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p) {
1401  if (value.IsString()) {
1402  RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1403  if (!r->IsValid()) {
1404  sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1405  r->~RegexType();
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());
1429  }
1430  }
1431  return 0;
1432  }
1433 
1434  static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1435  std::match_results<const Ch*> r;
1436  return std::regex_search(str, str + length, r, *pattern);
1437  }
1438 #else
1439  template <typename ValueType>
1440  RegexType* CreatePattern(const ValueType&) {
1441  return 0;
1442  }
1443 
1444  static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1445 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1446 
1447  void AddType(const ValueType& type) {
1448  if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1449  else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1450  else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1451  else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1452  else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1453  else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1454  else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1455  }
1456 
1457  // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if required.
1458  // Also creates a hasher for enums and array uniqueness, if required.
1459  // Also a useful place to add type-independent error checks.
1460  bool CreateParallelValidator(Context& context) const {
1461  if (enum_ || context.arrayUniqueness)
1462  context.hasher = context.factory.CreateHasher();
1463 
1464  if (validatorCount_) {
1465  RAPIDJSON_ASSERT(context.validators == 0);
1466  context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1467  std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_);
1468  context.validatorCount = validatorCount_;
1469 
1470  // Always return after first failure for these sub-validators
1471  if (allOf_.schemas)
1472  CreateSchemaValidators(context, allOf_, false);
1473 
1474  if (anyOf_.schemas)
1475  CreateSchemaValidators(context, anyOf_, false);
1476 
1477  if (oneOf_.schemas)
1478  CreateSchemaValidators(context, oneOf_, false);
1479 
1480  if (not_)
1481  context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_, false);
1482 
1483  if (hasSchemaDependencies_) {
1484  for (SizeType i = 0; i < propertyCount_; i++)
1485  if (properties_[i].dependenciesSchema)
1486  context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema, false);
1487  }
1488  }
1489 
1490  // Add any other type-independent checks here
1491  if (readOnly_ && (context.flags & kValidateWriteFlag)) {
1492  context.error_handler.DisallowedWhenWriting();
1494  }
1495  if (writeOnly_ && (context.flags & kValidateReadFlag)) {
1496  context.error_handler.DisallowedWhenReading();
1498  }
1499 
1500  return true;
1501  }
1502 
1503  void CreateSchemaValidators(Context& context, const SchemaArray& schemas, const bool inheritContinueOnErrors) const {
1504  for (SizeType i = 0; i < schemas.count; i++)
1505  context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1506  }
1507 
1508  // O(n)
1509  bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
1510  SizeType len = name.GetStringLength();
1511  const Ch* str = name.GetString();
1512  for (SizeType index = 0; index < propertyCount_; index++)
1513  if (properties_[index].name.GetStringLength() == len &&
1514  (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1515  {
1516  *outIndex = index;
1517  return true;
1518  }
1519  return false;
1520  }
1521 
1522  bool CheckBool(Context& context, bool) const {
1523  if (!(type_ & (1 << kBooleanSchemaType))) {
1524  DisallowedType(context, GetBooleanString());
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());
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_);
1541  }
1542  }
1543  else if (minimum_.IsUint64()) {
1544  context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1545  RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1546  }
1547  else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1548  return false;
1549  }
1550 
1551  if (!maximum_.IsNull()) {
1552  if (maximum_.IsInt64()) {
1553  if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1554  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1556  }
1557  }
1558  else if (maximum_.IsUint64()) { }
1559  /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1560  else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1561  return false;
1562  }
1563 
1564  if (!multipleOf_.IsNull()) {
1565  if (multipleOf_.IsUint64()) {
1566  if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1567  context.error_handler.NotMultipleOf(i, multipleOf_);
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());
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_);
1589  }
1590  }
1591  else if (minimum_.IsInt64())
1592  /* do nothing */; // i >= 0 > minimum.Getint64()
1593  else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1594  return false;
1595  }
1596 
1597  if (!maximum_.IsNull()) {
1598  if (maximum_.IsUint64()) {
1599  if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1600  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1602  }
1603  }
1604  else if (maximum_.IsInt64()) {
1605  context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
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_);
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_);
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_);
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 || difference < (std::numeric_limits<double>::min)();
1649  if (!isMultiple) {
1650  context.error_handler.NotMultipleOf(d, multipleOf_);
1652  }
1653  return true;
1654  }
1655 
1656  void DisallowedType(Context& context, const ValueType& actualType) const {
1657  ErrorHandler& eh = context.error_handler;
1658  eh.StartDisallowedType();
1659 
1660  if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1661  if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1662  if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1663  if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1664  if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1665 
1666  if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1667  else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1668 
1669  eh.EndDisallowedType(actualType);
1670  }
1671 
1672  struct Property {
1673  Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1674  ~Property() { AllocatorType::Free(dependencies); }
1675  SValue name;
1676  const SchemaType* schema;
1677  const SchemaType* dependenciesSchema;
1678  SizeType dependenciesValidatorIndex;
1679  bool* dependencies;
1680  bool required;
1681  };
1682 
1683  struct PatternProperty {
1684  PatternProperty() : schema(), pattern() {}
1685  ~PatternProperty() {
1686  if (pattern) {
1687  pattern->~RegexType();
1688  AllocatorType::Free(pattern);
1689  }
1690  }
1691  const SchemaType* schema;
1692  RegexType* pattern;
1693  };
1694 
1695  AllocatorType* allocator_;
1696  SValue uri_;
1697  UriType id_;
1698  Specification spec_;
1699  PointerType pointer_;
1700  const SchemaType* typeless_;
1701  uint64_t* enum_;
1702  SizeType enumCount_;
1703  SchemaArray allOf_;
1704  SchemaArray anyOf_;
1705  SchemaArray oneOf_;
1706  const SchemaType* not_;
1707  unsigned type_; // bitmask of kSchemaType
1708  SizeType validatorCount_;
1709  SizeType notValidatorIndex_;
1710 
1711  Property* properties_;
1712  const SchemaType* additionalPropertiesSchema_;
1713  PatternProperty* patternProperties_;
1714  SizeType patternPropertyCount_;
1715  SizeType propertyCount_;
1716  SizeType minProperties_;
1717  SizeType maxProperties_;
1718  bool additionalProperties_;
1719  bool hasDependencies_;
1720  bool hasRequired_;
1721  bool hasSchemaDependencies_;
1722 
1723  const SchemaType* additionalItemsSchema_;
1724  const SchemaType* itemsList_;
1725  const SchemaType** itemsTuple_;
1726  SizeType itemsTupleCount_;
1727  SizeType minItems_;
1728  SizeType maxItems_;
1729  bool additionalItems_;
1730  bool uniqueItems_;
1731 
1732  RegexType* pattern_;
1733  SizeType minLength_;
1734  SizeType maxLength_;
1735 
1736  SValue minimum_;
1737  SValue maximum_;
1738  SValue multipleOf_;
1739  bool exclusiveMinimum_;
1740  bool exclusiveMaximum_;
1741 
1742  SizeType defaultValueLength_;
1743 
1744  bool readOnly_;
1745  bool writeOnly_;
1746  bool nullable_;
1747 };
1748 
1749 template<typename Stack, typename Ch>
1750 struct TokenHelper {
1751  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1752  *documentStack.template Push<Ch>() = '/';
1753  char buffer[21];
1754  size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1755  for (size_t i = 0; i < length; i++)
1756  *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1757  }
1758 };
1759 
1760 // Partial specialized version for char to prevent buffer copying.
1761 template <typename Stack>
1762 struct TokenHelper<Stack, char> {
1763  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1764  RAPIDJSON_IF_CONSTEXPR (sizeof(SizeType) == 4) {
1765  char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1766  *buffer++ = '/';
1767  const char* end = internal::u32toa(index, buffer);
1768  documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1769  }
1770  else {
1771  char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1772  *buffer++ = '/';
1773  const char* end = internal::u64toa(index, buffer);
1774  documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1775  }
1776  }
1777 };
1778 
1779 } // namespace internal
1780 
1782 // IGenericRemoteSchemaDocumentProvider
1783 
1784 template <typename SchemaDocumentType>
1786 public:
1787  typedef typename SchemaDocumentType::Ch Ch;
1788  typedef typename SchemaDocumentType::ValueType ValueType;
1789  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
1790 
1792  virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1793  virtual const SchemaDocumentType* GetRemoteDocument(const GenericUri<ValueType, AllocatorType> uri, Specification& spec) {
1794  // Default implementation just calls through for compatibility
1795  // Following line suppresses unused parameter warning
1796  (void)spec;
1797  // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
1799  }
1800 };
1801 
1803 // GenericSchemaDocument
1804 
1806 
1814 template <typename ValueT, typename Allocator = CrtAllocator>
1816 public:
1817  typedef ValueT ValueType;
1820  typedef typename ValueType::EncodingType EncodingType;
1821  typedef typename EncodingType::Ch Ch;
1828  template <typename, typename, typename>
1830 
1832 
1843  explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
1844  IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0,
1845  const PointerType& pointer = PointerType(), // PR #1393
1846  const Specification& spec = Specification(kDraft04)) :
1847  remoteProvider_(remoteProvider),
1848  allocator_(allocator),
1849  ownAllocator_(),
1850  root_(),
1851  typeless_(),
1852  schemaMap_(allocator, kInitialSchemaMapSize),
1853  schemaRef_(allocator, kInitialSchemaRefSize),
1854  spec_(spec),
1855  error_(kObjectType),
1856  currentError_()
1857  {
1858  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
1859  if (!allocator_)
1860  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1861 
1862  Ch noUri[1] = {0};
1863  uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1864  docId_ = UriType(uri_, allocator_);
1865 
1866  typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1867  new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_, docId_);
1868 
1869  // Establish the schema draft or open api version.
1870  // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
1871  SetSchemaSpecification(document);
1872 
1873  // Generate root schema, it will call CreateSchema() to create sub-schemas,
1874  // And call HandleRefSchema() if there are $ref.
1875  // PR #1393 use input pointer if supplied
1876  root_ = typeless_;
1877  if (pointer.GetTokenCount() == 0) {
1878  CreateSchemaRecursive(&root_, pointer, document, document, docId_);
1879  }
1880  else if (const ValueType* v = pointer.Get(document)) {
1881  CreateSchema(&root_, pointer, *v, document, docId_);
1882  }
1883  else {
1885  pointer.StringifyUriFragment(sb);
1886  SchemaErrorValue(kSchemaErrorStartUnknown, PointerType(), sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
1887  }
1888 
1889  RAPIDJSON_ASSERT(root_ != 0);
1890 
1891  schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1892  }
1893 
1894 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1896  GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1897  remoteProvider_(rhs.remoteProvider_),
1898  allocator_(rhs.allocator_),
1899  ownAllocator_(rhs.ownAllocator_),
1900  root_(rhs.root_),
1901  typeless_(rhs.typeless_),
1902  schemaMap_(std::move(rhs.schemaMap_)),
1903  schemaRef_(std::move(rhs.schemaRef_)),
1904  uri_(std::move(rhs.uri_)),
1905  docId_(std::move(rhs.docId_)),
1906  spec_(rhs.spec_),
1907  error_(std::move(rhs.error_)),
1908  currentError_(std::move(rhs.currentError_))
1909  {
1910  rhs.remoteProvider_ = 0;
1911  rhs.allocator_ = 0;
1912  rhs.ownAllocator_ = 0;
1913  rhs.typeless_ = 0;
1914  }
1915 #endif
1916 
1919  while (!schemaMap_.Empty())
1920  schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1921 
1922  if (typeless_) {
1923  typeless_->~SchemaType();
1924  Allocator::Free(typeless_);
1925  }
1926 
1927  // these may contain some allocator data so clear before deleting ownAllocator_
1928  uri_.SetNull();
1929  error_.SetNull();
1930  currentError_.SetNull();
1931 
1932  RAPIDJSON_DELETE(ownAllocator_);
1933  }
1934 
1935  const GValue& GetURI() const { return uri_; }
1936 
1937  const Specification& GetSpecification() const { return spec_; }
1938  bool IsSupportedSpecification() const { return spec_.IsSupported(); }
1939 
1941  // Returns kDraftNone if document is silent
1942  static const Specification GetSpecification(const ValueType& document) {
1943  SchemaDraft draft = GetSchemaDraft(document);
1944  if (draft != kDraftNone)
1945  return Specification(draft);
1946  else {
1947  OpenApiVersion oapi = GetOpenApiVersion(document);
1948  if (oapi != kVersionNone)
1949  return Specification(oapi);
1950  }
1951  return Specification(kDraftNone);
1952  }
1953 
1955  const SchemaType& GetRoot() const { return *root_; }
1956 
1958  GValue& GetError() { return error_; }
1959  const GValue& GetError() const { return error_; }
1960 
1961  static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) {
1962  switch (schemaErrorCode) {
1963  case kSchemaErrorStartUnknown: return GetStartUnknownString();
1964  case kSchemaErrorRefPlainName: return GetRefPlainNameString();
1965  case kSchemaErrorRefInvalid: return GetRefInvalidString();
1966  case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString();
1967  case kSchemaErrorRefUnknown: return GetRefUnknownString();
1968  case kSchemaErrorRefCyclical: return GetRefCyclicalString();
1969  case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
1970  case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
1971  case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
1972  case kSchemaErrorSpecUnknown: return GetSpecUnknownString();
1973  case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString();
1974  case kSchemaErrorSpecIllegal: return GetSpecIllegalString();
1975  case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString();
1976  default: return GetNullString();
1977  }
1978  }
1979 
1981  void SchemaError(const SchemaErrorCode code, const PointerType& location) {
1982  currentError_ = GValue(kObjectType);
1983  AddCurrentError(code, location);
1984  }
1985 
1987  void SchemaErrorValue(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length) {
1988  currentError_ = GValue(kObjectType);
1989  currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1990  AddCurrentError(code, location);
1991  }
1992 
1994  void SchemaErrorPointer(const SchemaErrorCode code, const PointerType& location, const Ch* value, SizeType length, const PointerType& pointer) {
1995  currentError_ = GValue(kObjectType);
1996  currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1997  currentError_.AddMember(GetOffsetString(), static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)), *allocator_);
1998  AddCurrentError(code, location);
1999  }
2000 
2001  private:
2005  GenericSchemaDocument& operator=(const GenericSchemaDocument&);
2006 
2007  typedef const PointerType* SchemaRefPtr; // PR #1393
2008 
2009  struct SchemaEntry {
2010  SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
2011  ~SchemaEntry() {
2012  if (owned) {
2013  schema->~SchemaType();
2014  Allocator::Free(schema);
2015  }
2016  }
2018  SchemaType* schema;
2019  bool owned;
2020  };
2021 
2022  void AddErrorInstanceLocation(GValue& result, const PointerType& location) {
2024  location.StringifyUriFragment(sb);
2025  GValue instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
2026  result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2027  }
2028 
2029  void AddError(GValue& keyword, GValue& error) {
2030  typename GValue::MemberIterator member = error_.FindMember(keyword);
2031  if (member == error_.MemberEnd())
2032  error_.AddMember(keyword, error, *allocator_);
2033  else {
2034  if (member->value.IsObject()) {
2035  GValue errors(kArrayType);
2036  errors.PushBack(member->value, *allocator_);
2037  member->value = errors;
2038  }
2039  member->value.PushBack(error, *allocator_);
2040  }
2041  }
2042 
2043  void AddCurrentError(const SchemaErrorCode code, const PointerType& location) {
2044  RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2045  currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2046  AddErrorInstanceLocation(currentError_, location);
2047  AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2048  }
2049 
2050 #define RAPIDJSON_STRING_(name, ...) \
2051  static const StringRefType& Get##name##String() {\
2052  static const Ch s[] = { __VA_ARGS__, '\0' };\
2053  static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2054  return v;\
2055  }
2056 
2057  RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2058  RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2059  RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
2060  RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
2061 
2062  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
2063  RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2064  RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
2065  RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
2066  RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2067  RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
2068  RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2069  RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2070  RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2071  RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
2072  RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r')
2073  RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
2074  RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
2075  RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2076 
2077 #undef RAPIDJSON_STRING_
2078 
2079  // Static method to get schema draft of any schema document
2080  static SchemaDraft GetSchemaDraft(const ValueType& document) {
2081  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' };
2082  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' };
2083  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' };
2084  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' };
2085  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' };
2086  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' };
2087  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' };
2088 
2089  if (!document.IsObject()) {
2090  return kDraftNone;
2091  }
2092 
2093  // Get the schema draft from the $schema keyword at the supplied location
2094  typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
2095  if (itr != document.MemberEnd()) {
2096  if (!itr->value.IsString()) return kDraftUnknown;
2097  const UriType draftUri(itr->value);
2098  // Check base uri for match
2099  if (draftUri.Match(UriType(kDraft04String), false)) return kDraft04;
2100  if (draftUri.Match(UriType(kDraft05String), false)) return kDraft05;
2101  if (draftUri.Match(UriType(kDraft06String), false)) return kDraft06;
2102  if (draftUri.Match(UriType(kDraft07String), false)) return kDraft07;
2103  if (draftUri.Match(UriType(kDraft03String), false)) return kDraft03;
2104  if (draftUri.Match(UriType(kDraft2019_09String), false)) return kDraft2019_09;
2105  if (draftUri.Match(UriType(kDraft2020_12String), false)) return kDraft2020_12;
2106  return kDraftUnknown;
2107  }
2108  // $schema not found
2109  return kDraftNone;
2110  }
2111 
2112 
2113  // Get open api version of any schema document
2114  static OpenApiVersion GetOpenApiVersion(const ValueType& document) {
2115  static const Ch kVersion20String[] = { '2', '.', '0', '\0' };
2116  static const Ch kVersion30String[] = { '3', '.', '0', '.', '\0' }; // ignore patch level
2117  static const Ch kVersion31String[] = { '3', '.', '1', '.', '\0' }; // ignore patch level
2118  static SizeType len = internal::StrLen<Ch>(kVersion30String);
2119 
2120  if (!document.IsObject()) {
2121  return kVersionNone;
2122  }
2123 
2124  // Get the open api version from the swagger / openapi keyword at the supplied location
2125  typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
2126  if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
2127  if (itr != document.MemberEnd()) {
2128  if (!itr->value.IsString()) return kVersionUnknown;
2129  const ValueType kVersion20Value(kVersion20String);
2130  if (kVersion20Value == itr->value) return kVersion20; // must match 2.0 exactly
2131  const ValueType kVersion30Value(kVersion30String);
2132  if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len)) return kVersion30; // must match 3.0.x
2133  const ValueType kVersion31Value(kVersion31String);
2134  if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len)) return kVersion31; // must match 3.1.x
2135  return kVersionUnknown;
2136  }
2137  // swagger or openapi not found
2138  return kVersionNone;
2139  }
2140 
2141  // Get the draft of the schema or the open api version (which implies the draft).
2142  // Report an error if schema draft or open api version not supported or not recognized, or both in document, and carry on.
2143  void SetSchemaSpecification(const ValueType& document) {
2144  // Look for '$schema', 'swagger' or 'openapi' keyword at document root
2145  SchemaDraft docDraft = GetSchemaDraft(document);
2146  OpenApiVersion docOapi = GetOpenApiVersion(document);
2147  // Error if both in document
2148  if (docDraft != kDraftNone && docOapi != kVersionNone)
2150  // Use document draft or open api version if present or use spec from constructor
2151  if (docDraft != kDraftNone)
2152  spec_ = Specification(docDraft);
2153  else if (docOapi != kVersionNone)
2154  spec_ = Specification(docOapi);
2155  // Error if draft or version unknown
2156  if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2158  else if (!spec_.IsSupported())
2160  }
2161 
2162  // Changed by PR #1393
2163  void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
2164  if (v.GetType() == kObjectType) {
2165  UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
2166 
2167  for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
2168  CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2169  }
2170  else if (v.GetType() == kArrayType)
2171  for (SizeType i = 0; i < v.Size(); i++)
2172  CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
2173  }
2174 
2175  // Changed by PR #1393
2176  const UriType& CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document, const UriType& id) {
2177  RAPIDJSON_ASSERT(pointer.IsValid());
2179  pointer.StringifyUriFragment(sb);
2180  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
2181  if (v.IsObject()) {
2182  if (const SchemaType* sc = GetSchema(pointer)) {
2183  if (schema)
2184  *schema = sc;
2185  AddSchemaRefs(const_cast<SchemaType*>(sc));
2186  }
2187  else if (!HandleRefSchema(pointer, schema, v, document, id)) {
2188  // The new schema constructor adds itself and its $ref(s) to schemaMap_
2189  SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_, id);
2190  if (schema)
2191  *schema = s;
2192  return s->GetId();
2193  }
2194  }
2195  else {
2196  if (schema)
2197  *schema = typeless_;
2198  AddSchemaRefs(typeless_);
2199  }
2200  return id;
2201  }
2202 
2203  // Changed by PR #1393
2204  // TODO should this return a UriType& ?
2205  bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document, const UriType& id) {
2206  typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2207  if (itr == v.MemberEnd())
2208  return false;
2209 
2211  source.StringifyUriFragment(sb);
2212  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
2213  // Resolve the source pointer to the $ref'ed schema (finally)
2214  new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2215 
2216  if (itr->value.IsString()) {
2217  SizeType len = itr->value.GetStringLength();
2218  if (len == 0)
2220  else {
2221  // First resolve $ref against the in-scope id
2222  UriType scopeId = UriType(id, allocator_);
2223  UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2224  RAPIDJSON_SCHEMA_PRINT(SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
2225  // See if the resolved $ref minus the fragment matches a resolved id in this document
2226  // Search from the root. Returns the subschema in the document and its absolute JSON pointer.
2227  PointerType basePointer = PointerType();
2228  const ValueType *base = FindId(document, ref, basePointer, docId_, false);
2229  if (!base) {
2230  // Remote reference - call the remote document provider
2231  if (!remoteProvider_)
2233  else {
2234  if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
2235  const Ch* s = ref.GetFragString();
2236  len = ref.GetFragStringLength();
2237  if (len <= 1 || s[1] == '/') {
2238  // JSON pointer fragment, absolute in the remote schema
2239  const PointerType pointer(s, len, allocator_);
2240  if (!pointer.IsValid())
2242  else {
2243  // Get the subschema
2244  if (const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
2245  if (schema)
2246  *schema = sc;
2247  AddSchemaRefs(const_cast<SchemaType *>(sc));
2248  return true;
2249  } else
2250  SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2251  }
2252  } else
2253  // Plain name fragment, not allowed in remote schema
2255  } else
2256  SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
2257  }
2258  }
2259  else { // Local reference
2260  const Ch* s = ref.GetFragString();
2261  len = ref.GetFragStringLength();
2262  if (len <= 1 || s[1] == '/') {
2263  // JSON pointer fragment, relative to the resolved URI
2264  const PointerType relPointer(s, len, allocator_);
2265  if (!relPointer.IsValid())
2267  else {
2268  // Get the subschema
2269  if (const ValueType *pv = relPointer.Get(*base)) {
2270  // Now get the absolute JSON pointer by adding relative to base
2271  PointerType pointer(basePointer, allocator_);
2272  for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2273  pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2274  if (IsCyclicRef(pointer))
2275  SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2276  else {
2277  // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
2278  // TODO: cache pointer <-> id mapping
2279  size_t unresolvedTokenIndex;
2280  scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2281  CreateSchema(schema, pointer, *pv, document, scopeId);
2282  return true;
2283  }
2284  } else
2285  SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2286  }
2287  } else {
2288  // Plain name fragment, relative to the resolved URI
2289  // Not supported in open api 2.0 and 3.0
2290  PointerType pointer(allocator_);
2291  if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2293  // See if the fragment matches an id in this document.
2294  // Search from the base we just established. Returns the subschema in the document and its absolute JSON pointer.
2295  else if (const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_), true, basePointer)) {
2296  if (IsCyclicRef(pointer))
2297  SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2298  else {
2299  // Call CreateSchema recursively, but first compute the in-scope id for the $ref target as we have jumped there
2300  // TODO: cache pointer <-> id mapping
2301  size_t unresolvedTokenIndex;
2302  scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2303  CreateSchema(schema, pointer, *pv, document, scopeId);
2304  return true;
2305  }
2306  } else
2307  SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2308  }
2309  }
2310  }
2311  }
2312 
2313  // Invalid/Unknown $ref
2314  if (schema)
2315  *schema = typeless_;
2316  AddSchemaRefs(typeless_);
2317  return true;
2318  }
2319 
2321  // If full specified use all URI else ignore fragment.
2322  // If found, return a pointer to the subschema and its JSON pointer.
2323  // TODO cache pointer <-> id mapping
2324  ValueType* FindId(const ValueType& doc, const UriType& finduri, PointerType& resptr, const UriType& baseuri, bool full, const PointerType& here = PointerType()) const {
2325  SizeType i = 0;
2326  ValueType* resval = 0;
2327  UriType tempuri = UriType(finduri, allocator_);
2328  UriType localuri = UriType(baseuri, allocator_);
2329  if (doc.GetType() == kObjectType) {
2330  // Establish the base URI of this object
2331  typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
2332  if (m != doc.MemberEnd() && m->value.GetType() == kStringType) {
2333  localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
2334  }
2335  // See if it matches
2336  if (localuri.Match(finduri, full)) {
2337  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
2338  resval = const_cast<ValueType *>(&doc);
2339  resptr = here;
2340  return resval;
2341  }
2342  // No match, continue looking
2343  for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
2344  if (m->value.GetType() == kObjectType || m->value.GetType() == kArrayType) {
2345  resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
2346  }
2347  if (resval) break;
2348  }
2349  } else if (doc.GetType() == kArrayType) {
2350  // Continue looking
2351  for (typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
2352  if (v->GetType() == kObjectType || v->GetType() == kArrayType) {
2353  resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
2354  }
2355  if (resval) break;
2356  i++;
2357  }
2358  }
2359  return resval;
2360  }
2361 
2362  // Added by PR #1393
2363  void AddSchemaRefs(SchemaType* schema) {
2364  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
2365  while (!schemaRef_.Empty()) {
2366  SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
2367  SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
2368  new (entry) SchemaEntry(**ref, schema, false, allocator_);
2369  }
2370  }
2371 
2372  // Added by PR #1393
2373  bool IsCyclicRef(const PointerType& pointer) const {
2374  for (const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
2375  if (pointer == **ref)
2376  return true;
2377  return false;
2378  }
2379 
2380  const SchemaType* GetSchema(const PointerType& pointer) const {
2381  for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2382  if (pointer == target->pointer)
2383  return target->schema;
2384  return 0;
2385  }
2386 
2387  PointerType GetPointer(const SchemaType* schema) const {
2388  for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2389  if (schema == target->schema)
2390  return target->pointer;
2391  return PointerType();
2392  }
2393 
2394  const SchemaType* GetTypeless() const { return typeless_; }
2395 
2396  static const size_t kInitialSchemaMapSize = 64;
2397  static const size_t kInitialSchemaRefSize = 64;
2398 
2399  IRemoteSchemaDocumentProviderType* remoteProvider_;
2400  Allocator *allocator_;
2401  Allocator *ownAllocator_;
2402  const SchemaType* root_;
2403  SchemaType* typeless_;
2404  internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
2405  internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
2406  GValue uri_; // Schema document URI
2407  UriType docId_;
2408  Specification spec_;
2409  GValue error_;
2410  GValue currentError_;
2411 };
2412 
2417 
2419 // GenericSchemaValidator
2420 
2422 
2433 template <
2434  typename SchemaDocumentType,
2436  typename StateAllocator = CrtAllocator>
2438  public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
2440  public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
2441 public:
2442  typedef typename SchemaDocumentType::SchemaType SchemaType;
2443  typedef typename SchemaDocumentType::PointerType PointerType;
2444  typedef typename SchemaType::EncodingType EncodingType;
2445  typedef typename SchemaType::SValue SValue;
2446  typedef typename EncodingType::Ch Ch;
2449 
2451 
2458  const SchemaDocumentType& schemaDocument,
2459  StateAllocator* allocator = 0,
2460  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2461  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2462  :
2463  schemaDocument_(&schemaDocument),
2464  root_(schemaDocument.GetRoot()),
2465  stateAllocator_(allocator),
2466  ownStateAllocator_(0),
2467  schemaStack_(allocator, schemaStackCapacity),
2468  documentStack_(allocator, documentStackCapacity),
2469  outputHandler_(0),
2470  error_(kObjectType),
2471  currentError_(),
2472  missingDependents_(),
2473  valid_(true),
2474  flags_(kValidateDefaultFlags),
2475  depth_(0)
2476  {
2477  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
2478  }
2479 
2481 
2488  const SchemaDocumentType& schemaDocument,
2489  OutputHandler& outputHandler,
2490  StateAllocator* allocator = 0,
2491  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2492  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2493  :
2494  schemaDocument_(&schemaDocument),
2495  root_(schemaDocument.GetRoot()),
2496  stateAllocator_(allocator),
2497  ownStateAllocator_(0),
2498  schemaStack_(allocator, schemaStackCapacity),
2499  documentStack_(allocator, documentStackCapacity),
2500  outputHandler_(&outputHandler),
2501  error_(kObjectType),
2502  currentError_(),
2503  missingDependents_(),
2504  valid_(true),
2505  flags_(kValidateDefaultFlags),
2506  depth_(0)
2507  {
2508  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (output handler)");
2509  }
2510 
2513  Reset();
2514  RAPIDJSON_DELETE(ownStateAllocator_);
2515  }
2516 
2518  void Reset() {
2519  while (!schemaStack_.Empty())
2520  PopSchema();
2521  documentStack_.Clear();
2522  ResetError();
2523  }
2524 
2526  void ResetError() {
2527  error_.SetObject();
2528  currentError_.SetNull();
2529  missingDependents_.SetNull();
2530  valid_ = true;
2531  }
2532 
2534  void SetValidateFlags(unsigned flags) {
2535  flags_ = flags;
2536  }
2537  virtual unsigned GetValidateFlags() const {
2538  return flags_;
2539  }
2540 
2541  virtual bool IsValid() const {
2542  if (!valid_) return false;
2543  if (GetContinueOnErrors() && !error_.ObjectEmpty()) return false;
2544  return true;
2545  }
2547 
2549  ValueType& GetError() { return error_; }
2550  const ValueType& GetError() const { return error_; }
2551 
2553  // If reporting all errors, the stack will be empty.
2555  return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2556  }
2557 
2559  // If reporting all errors, the stack will be empty, so return "errors".
2560  const Ch* GetInvalidSchemaKeyword() const {
2561  if (!schemaStack_.Empty()) return CurrentContext().invalidKeyword;
2562  if (GetContinueOnErrors() && !error_.ObjectEmpty()) return static_cast<const Ch*>(GetErrorsString());
2563  return 0;
2564  }
2565 
2567  // If reporting all errors, the stack will be empty, so return kValidateErrors.
2569  if (!schemaStack_.Empty()) return CurrentContext().invalidCode;
2570  if (GetContinueOnErrors() && !error_.ObjectEmpty()) return kValidateErrors;
2571  return kValidateErrorNone;
2572  }
2573 
2575  // If reporting all errors, the stack will be empty.
2577  if (documentStack_.Empty()) {
2578  return PointerType();
2579  }
2580  else {
2581  return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
2582  }
2583  }
2584 
2585  void NotMultipleOf(int64_t actual, const SValue& expected) {
2586  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2587  }
2588  void NotMultipleOf(uint64_t actual, const SValue& expected) {
2589  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2590  }
2591  void NotMultipleOf(double actual, const SValue& expected) {
2592  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2593  }
2594  void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
2595  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2596  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2597  }
2598  void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
2599  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2600  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2601  }
2602  void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
2603  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum, ValueType(actual).Move(), expected,
2604  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2605  }
2606  void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
2607  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2608  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2609  }
2610  void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
2611  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2612  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2613  }
2614  void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
2615  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum, ValueType(actual).Move(), expected,
2616  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2617  }
2618 
2619  void TooLong(const Ch* str, SizeType length, SizeType expected) {
2620  AddNumberError(kValidateErrorMaxLength,
2621  ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2622  }
2623  void TooShort(const Ch* str, SizeType length, SizeType expected) {
2624  AddNumberError(kValidateErrorMinLength,
2625  ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2626  }
2627  void DoesNotMatch(const Ch* str, SizeType length) {
2628  currentError_.SetObject();
2629  currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2630  AddCurrentError(kValidateErrorPattern);
2631  }
2632 
2633  void DisallowedItem(SizeType index) {
2634  currentError_.SetObject();
2635  currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2636  AddCurrentError(kValidateErrorAdditionalItems, true);
2637  }
2638  void TooFewItems(SizeType actualCount, SizeType expectedCount) {
2639  AddNumberError(kValidateErrorMinItems,
2640  ValueType(actualCount).Move(), SValue(expectedCount).Move());
2641  }
2642  void TooManyItems(SizeType actualCount, SizeType expectedCount) {
2643  AddNumberError(kValidateErrorMaxItems,
2644  ValueType(actualCount).Move(), SValue(expectedCount).Move());
2645  }
2646  void DuplicateItems(SizeType index1, SizeType index2) {
2647  ValueType duplicates(kArrayType);
2648  duplicates.PushBack(index1, GetStateAllocator());
2649  duplicates.PushBack(index2, GetStateAllocator());
2650  currentError_.SetObject();
2651  currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2652  AddCurrentError(kValidateErrorUniqueItems, true);
2653  }
2654 
2655  void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
2656  AddNumberError(kValidateErrorMaxProperties,
2657  ValueType(actualCount).Move(), SValue(expectedCount).Move());
2658  }
2659  void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
2660  AddNumberError(kValidateErrorMinProperties,
2661  ValueType(actualCount).Move(), SValue(expectedCount).Move());
2662  }
2664  currentError_.SetArray();
2665  }
2666  void AddMissingProperty(const SValue& name) {
2667  currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2668  }
2670  if (currentError_.Empty())
2671  return false;
2672  ValueType error(kObjectType);
2673  error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2674  currentError_ = error;
2675  AddCurrentError(kValidateErrorRequired);
2676  return true;
2677  }
2678  void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
2679  for (SizeType i = 0; i < count; ++i)
2680  MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2681  }
2682  void DisallowedProperty(const Ch* name, SizeType length) {
2683  currentError_.SetObject();
2684  currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2685  AddCurrentError(kValidateErrorAdditionalProperties, true);
2686  }
2687 
2689  currentError_.SetObject();
2690  }
2692  missingDependents_.SetArray();
2693  }
2694  void AddMissingDependentProperty(const SValue& targetName) {
2695  missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2696  }
2697  void EndMissingDependentProperties(const SValue& sourceName) {
2698  if (!missingDependents_.Empty()) {
2699  // Create equivalent 'required' error
2700  ValueType error(kObjectType);
2702  error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2703  AddErrorCode(error, code);
2704  AddErrorInstanceLocation(error, false);
2705  // When appending to a pointer ensure its allocator is used
2706  PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2707  AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2708  ValueType wrapper(kObjectType);
2709  wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2710  currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2711  }
2712  }
2713  void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2714  currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2715  static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2716  }
2718  if (currentError_.ObjectEmpty())
2719  return false;
2720  ValueType error(kObjectType);
2721  error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2722  currentError_ = error;
2723  AddCurrentError(kValidateErrorDependencies);
2724  return true;
2725  }
2726 
2728  currentError_.SetObject();
2729  AddCurrentError(code);
2730  }
2732  currentError_.SetArray();
2733  }
2734  void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
2735  currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2736  }
2737  void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
2738  ValueType error(kObjectType);
2739  error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2740  error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2741  currentError_ = error;
2742  AddCurrentError(kValidateErrorType);
2743  }
2744  void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2745  // Treat allOf like oneOf and anyOf to match https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
2746  AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2747  //for (SizeType i = 0; i < count; ++i) {
2748  // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2749  //}
2750  }
2751  void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2752  AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
2753  }
2754  void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2755  AddErrorArray(kValidateErrorOneOf, subvalidators, count);
2756  }
2757  void MultipleOneOf(SizeType index1, SizeType index2) {
2758  ValueType matches(kArrayType);
2759  matches.PushBack(index1, GetStateAllocator());
2760  matches.PushBack(index2, GetStateAllocator());
2761  currentError_.SetObject();
2762  currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
2763  AddCurrentError(kValidateErrorOneOfMatch);
2764  }
2765  void Disallowed() {
2766  currentError_.SetObject();
2767  AddCurrentError(kValidateErrorNot);
2768  }
2770  currentError_.SetObject();
2771  AddCurrentError(kValidateErrorReadOnly);
2772  }
2774  currentError_.SetObject();
2775  AddCurrentError(kValidateErrorWriteOnly);
2776  }
2777 
2778 #define RAPIDJSON_STRING_(name, ...) \
2779  static const StringRefType& Get##name##String() {\
2780  static const Ch s[] = { __VA_ARGS__, '\0' };\
2781  static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2782  return v;\
2783  }
2784 
2785  RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2786  RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2787  RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2788  RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2789  RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2790  RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2791  RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2792  RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2793  RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2794  RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2795  RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
2796 
2797 #undef RAPIDJSON_STRING_
2798 
2799 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2800  if (!valid_) return false; \
2801  if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2802  *documentStack_.template Push<Ch>() = '\0';\
2803  documentStack_.template Pop<Ch>(1);\
2804  RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
2805  valid_ = false;\
2806  return valid_;\
2807  }
2808 
2809 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2810  for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2811  if (context->hasher)\
2812  static_cast<HasherType*>(context->hasher)->method arg2;\
2813  if (context->validators)\
2814  for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2815  static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2816  if (context->patternPropertiesValidators)\
2817  for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2818  static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2819  }
2820 
2821 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2822  valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2823  return valid_;
2824 
2825 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2826  RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2827  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2828  RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2829 
2830  bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2831  bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2832  bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2833  bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2834  bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2835  bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2836  bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2837  bool RawNumber(const Ch* str, SizeType length, bool copy)
2838  { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2839  bool String(const Ch* str, SizeType length, bool copy)
2840  { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2841 
2842  bool StartObject() {
2843  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
2844  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2846  valid_ = !outputHandler_ || outputHandler_->StartObject();
2847  return valid_;
2848  }
2849 
2850  bool Key(const Ch* str, SizeType len, bool copy) {
2851  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
2852  if (!valid_) return false;
2853  AppendToken(str, len);
2854  if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
2855  valid_ = false;
2856  return valid_;
2857  }
2859  valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2860  return valid_;
2861  }
2862 
2863  bool EndObject(SizeType memberCount) {
2864  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
2865  if (!valid_) return false;
2867  if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
2868  valid_ = false;
2869  return valid_;
2870  }
2871  RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2872  }
2873 
2874  bool StartArray() {
2875  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
2876  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2878  valid_ = !outputHandler_ || outputHandler_->StartArray();
2879  return valid_;
2880  }
2881 
2882  bool EndArray(SizeType elementCount) {
2883  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
2884  if (!valid_) return false;
2886  if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
2887  valid_ = false;
2888  return valid_;
2889  }
2890  RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2891  }
2892 
2893 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2894 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2895 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2896 
2897  // Implementation of ISchemaStateFactory<SchemaType>
2898  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root, const bool inheritContinueOnErrors) {
2899  *documentStack_.template Push<Ch>() = '\0';
2900  documentStack_.template Pop<Ch>(1);
2901  ISchemaValidator* sv = new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2902  depth_ + 1,
2903  &GetStateAllocator());
2904  sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~static_cast<unsigned>(kValidateContinueOnErrorFlag));
2905  return sv;
2906  }
2907 
2908  virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2909  GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
2912  }
2913 
2914  virtual void* CreateHasher() {
2915  return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
2916  }
2917 
2918  virtual uint64_t GetHashCode(void* hasher) {
2919  return static_cast<HasherType*>(hasher)->GetHashCode();
2920  }
2921 
2922  virtual void DestroryHasher(void* hasher) {
2923  HasherType* h = static_cast<HasherType*>(hasher);
2924  h->~HasherType();
2926  }
2927 
2928  virtual void* MallocState(size_t size) {
2929  return GetStateAllocator().Malloc(size);
2930  }
2931 
2932  virtual void FreeState(void* p) {
2934  }
2935  // End of implementation of ISchemaStateFactory<SchemaType>
2936 
2937 private:
2938  typedef typename SchemaType::Context Context;
2939  typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2941 
2943  const SchemaDocumentType& schemaDocument,
2944  const SchemaType& root,
2945  const char* basePath, size_t basePathSize,
2946  unsigned depth,
2947  StateAllocator* allocator = 0,
2948  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2949  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2950  :
2951  schemaDocument_(&schemaDocument),
2952  root_(root),
2953  stateAllocator_(allocator),
2954  ownStateAllocator_(0),
2955  schemaStack_(allocator, schemaStackCapacity),
2956  documentStack_(allocator, documentStackCapacity),
2957  outputHandler_(0),
2958  error_(kObjectType),
2959  currentError_(),
2960  missingDependents_(),
2961  valid_(true),
2962  flags_(kValidateDefaultFlags),
2963  depth_(depth)
2964  {
2965  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath : "");
2966  if (basePath && basePathSize)
2967  memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2968  }
2969 
2970  StateAllocator& GetStateAllocator() {
2971  if (!stateAllocator_)
2972  stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
2973  return *stateAllocator_;
2974  }
2975 
2976  bool GetContinueOnErrors() const {
2977  return flags_ & kValidateContinueOnErrorFlag;
2978  }
2979 
2980  bool BeginValue() {
2981  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
2982  if (schemaStack_.Empty())
2983  PushSchema(root_);
2984  else {
2985  if (CurrentContext().inArray)
2986  internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2987 
2988  if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2989  return false;
2990 
2991  SizeType count = CurrentContext().patternPropertiesSchemaCount;
2992  const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2993  typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2994  bool valueUniqueness = CurrentContext().valueUniqueness;
2995  RAPIDJSON_ASSERT(CurrentContext().valueSchema);
2996  PushSchema(*CurrentContext().valueSchema);
2997 
2998  if (count > 0) {
2999  CurrentContext().objectPatternValidatorType = patternValidatorType;
3000  ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3001  SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3002  va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
3003  std::memset(va, 0, sizeof(ISchemaValidator*) * count);
3004  for (SizeType i = 0; i < count; i++)
3005  va[validatorCount++] = CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
3006  }
3007 
3008  CurrentContext().arrayUniqueness = valueUniqueness;
3009  }
3010  return true;
3011  }
3012 
3013  bool EndValue() {
3014  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
3015  if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3016  return false;
3017 
3019  schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3020  *documentStack_.template Push<Ch>() = '\0';
3021  documentStack_.template Pop<Ch>(1);
3022  RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3023  void* hasher = CurrentContext().hasher;
3024  uint64_t h = hasher && CurrentContext().arrayUniqueness ? static_cast<HasherType*>(hasher)->GetHashCode() : 0;
3025 
3026  PopSchema();
3027 
3028  if (!schemaStack_.Empty()) {
3029  Context& context = CurrentContext();
3030  // Only check uniqueness if there is a hasher
3031  if (hasher && context.valueUniqueness) {
3032  HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
3033  if (!a)
3034  CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
3035  for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
3036  if (itr->GetUint64() == h) {
3037  DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
3038  // Cleanup before returning if continuing
3039  if (GetContinueOnErrors()) {
3040  a->PushBack(h, GetStateAllocator());
3041  while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/');
3042  }
3044  }
3045  a->PushBack(h, GetStateAllocator());
3046  }
3047  }
3048 
3049  // Remove the last token of document pointer
3050  while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
3051  ;
3052 
3053  return true;
3054  }
3055 
3056  void AppendToken(const Ch* str, SizeType len) {
3057  documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
3058  *documentStack_.template PushUnsafe<Ch>() = '/';
3059  for (SizeType i = 0; i < len; i++) {
3060  if (str[i] == '~') {
3061  *documentStack_.template PushUnsafe<Ch>() = '~';
3062  *documentStack_.template PushUnsafe<Ch>() = '0';
3063  }
3064  else if (str[i] == '/') {
3065  *documentStack_.template PushUnsafe<Ch>() = '~';
3066  *documentStack_.template PushUnsafe<Ch>() = '1';
3067  }
3068  else
3069  *documentStack_.template PushUnsafe<Ch>() = str[i];
3070  }
3071  }
3072 
3073  RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_); }
3074 
3075  RAPIDJSON_FORCEINLINE void PopSchema() {
3076  Context* c = schemaStack_.template Pop<Context>(1);
3077  if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
3078  a->~HashCodeArray();
3080  }
3081  c->~Context();
3082  }
3083 
3084  void AddErrorInstanceLocation(ValueType& result, bool parent) {
3086  PointerType instancePointer = GetInvalidDocumentPointer();
3087  ((parent && instancePointer.GetTokenCount() > 0)
3088  ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3089  : instancePointer).StringifyUriFragment(sb);
3090  ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
3091  GetStateAllocator());
3092  result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3093  }
3094 
3095  void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
3097  SizeType len = CurrentSchema().GetURI().GetStringLength();
3098  if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
3099  if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
3100  else GetInvalidSchemaPointer().StringifyUriFragment(sb);
3101  ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
3102  GetStateAllocator());
3103  result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3104  }
3105 
3106  void AddErrorCode(ValueType& result, const ValidateErrorCode code) {
3107  result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3108  }
3109 
3110  void AddError(ValueType& keyword, ValueType& error) {
3111  typename ValueType::MemberIterator member = error_.FindMember(keyword);
3112  if (member == error_.MemberEnd())
3113  error_.AddMember(keyword, error, GetStateAllocator());
3114  else {
3115  if (member->value.IsObject()) {
3116  ValueType errors(kArrayType);
3117  errors.PushBack(member->value, GetStateAllocator());
3118  member->value = errors;
3119  }
3120  member->value.PushBack(error, GetStateAllocator());
3121  }
3122  }
3123 
3124  void AddCurrentError(const ValidateErrorCode code, bool parent = false) {
3125  AddErrorCode(currentError_, code);
3126  AddErrorInstanceLocation(currentError_, parent);
3127  AddErrorSchemaLocation(currentError_);
3128  AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(), currentError_);
3129  }
3130 
3131  void MergeError(ValueType& other) {
3132  for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
3133  AddError(it->name, it->value);
3134  }
3135  }
3136 
3137  void AddNumberError(const ValidateErrorCode code, ValueType& actual, const SValue& expected,
3138  const typename SchemaType::ValueType& (*exclusive)() = 0) {
3139  currentError_.SetObject();
3140  currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
3141  currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
3142  if (exclusive)
3143  currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
3144  AddCurrentError(code);
3145  }
3146 
3147  void AddErrorArray(const ValidateErrorCode code,
3148  ISchemaValidator** subvalidators, SizeType count) {
3149  ValueType errors(kArrayType);
3150  for (SizeType i = 0; i < count; ++i)
3151  errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
3152  currentError_.SetObject();
3153  currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
3154  AddCurrentError(code);
3155  }
3156 
3157  const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
3158  Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
3159  const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
3160 
3161  static const size_t kDefaultSchemaStackCapacity = 1024;
3162  static const size_t kDefaultDocumentStackCapacity = 256;
3163  const SchemaDocumentType* schemaDocument_;
3164  const SchemaType& root_;
3165  StateAllocator* stateAllocator_;
3166  StateAllocator* ownStateAllocator_;
3167  internal::Stack<StateAllocator> schemaStack_;
3168  internal::Stack<StateAllocator> documentStack_;
3169  OutputHandler* outputHandler_;
3170  ValueType error_;
3171  ValueType currentError_;
3172  ValueType missingDependents_;
3173  bool valid_;
3174  unsigned flags_;
3175  unsigned depth_;
3176 };
3177 
3179 
3181 // SchemaValidatingReader
3182 
3184 
3193 template <
3194  unsigned parseFlags,
3195  typename InputStream,
3196  typename SourceEncoding,
3197  typename SchemaDocumentType = SchemaDocument,
3198  typename StackAllocator = CrtAllocator>
3200 public:
3201  typedef typename SchemaDocumentType::PointerType PointerType;
3202  typedef typename InputStream::Ch Ch;
3204 
3206 
3210  SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), invalidSchemaCode_(kValidateErrorNone), error_(kObjectType), isValid_(true) {}
3211 
3212  template <typename Handler>
3213  bool operator()(Handler& handler) {
3216  parseResult_ = reader.template Parse<parseFlags>(is_, validator);
3217 
3218  isValid_ = validator.IsValid();
3219  if (isValid_) {
3220  invalidSchemaPointer_ = PointerType();
3221  invalidSchemaKeyword_ = 0;
3222  invalidDocumentPointer_ = PointerType();
3223  error_.SetObject();
3224  }
3225  else {
3226  invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
3227  invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
3228  invalidSchemaCode_ = validator.GetInvalidSchemaCode();
3229  invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
3230  error_.CopyFrom(validator.GetError(), allocator_);
3231  }
3232 
3233  return parseResult_;
3234  }
3235 
3236  const ParseResult& GetParseResult() const { return parseResult_; }
3237  bool IsValid() const { return isValid_; }
3238  const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
3239  const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
3240  const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
3241  const ValueType& GetError() const { return error_; }
3242  ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
3243 
3244 private:
3245  InputStream& is_;
3246  const SchemaDocumentType& sd_;
3247 
3248  ParseResult parseResult_;
3249  PointerType invalidSchemaPointer_;
3250  const Ch* invalidSchemaKeyword_;
3251  PointerType invalidDocumentPointer_;
3252  ValidateErrorCode invalidSchemaCode_;
3253  StackAllocator allocator_;
3254  ValueType error_;
3255  bool isValid_;
3256 };
3257 
3259 RAPIDJSON_DIAG_POP
3260 
3261 #endif // RAPIDJSON_SCHEMA_H_
void Free(A &a, T *p, size_t n=1)
Definition: allocators.h:448
C-runtime library allocator.
Definition: allocators.h:83
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: reader.h:539
JSON schema document.
Definition: schema.h:1815
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0, const PointerType &pointer=PointerType(), const Specification &spec=Specification(kDraft04))
Constructor.
Definition: schema.h:1843
const GValue & GetError() const
Definition: schema.h:1959
GValue & GetError()
Gets the error object.
Definition: schema.h:1958
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1955
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1918
GenericValue< EncodingType, AllocatorType > GValue
Definition: schema.h:1824
void SchemaError(const SchemaErrorCode code, const PointerType &location)
Default error method.
Definition: schema.h:1981
const Specification & GetSpecification() const
Definition: schema.h:1937
void SchemaErrorValue(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length)
Method for error with single string value insert.
Definition: schema.h:1987
static const Specification GetSpecification(const ValueType &document)
Static method to get the specification of any schema document.
Definition: schema.h:1942
const GValue & GetURI() const
Definition: schema.h:1935
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
Definition: schema.h:1818
EncodingType::Ch Ch
Definition: schema.h:1821
static const StringRefType & GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode)
Definition: schema.h:1961
Allocator AllocatorType
Definition: schema.h:1819
internal::Schema< GenericSchemaDocument > SchemaType
Definition: schema.h:1822
ValueType::EncodingType EncodingType
Definition: schema.h:1820
bool IsSupportedSpecification() const
Definition: schema.h:1938
GenericStringRef< Ch > StringRefType
Definition: schema.h:1826
ValueT ValueType
Definition: schema.h:1817
GenericPointer< ValueType, Allocator > PointerType
Definition: schema.h:1823
GenericUri< ValueType, Allocator > UriType
Definition: schema.h:1825
void SchemaErrorPointer(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length, const PointerType &pointer)
Method for error with invalid pointer.
Definition: schema.h:1994
JSON Schema Validator.
Definition: schema.h:2440
virtual void DestroryHasher(void *hasher)
Definition: schema.h:2922
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:2606
const ValueType & GetError() const
Definition: schema.h:2550
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:2457
void TooLong(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:2619
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
Definition: schema.h:2713
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2678
void DisallowedItem(SizeType index)
Definition: schema.h:2633
virtual unsigned GetValidateFlags() const
Definition: schema.h:2537
bool String(const Ch *str, SizeType length, bool copy)
Definition: schema.h:2839
SchemaType::SValue SValue
Definition: schema.h:2445
~GenericSchemaValidator()
Destructor.
Definition: schema.h:2512
void StartMissingProperties()
Definition: schema.h:2663
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2744
GenericValue< EncodingType, StateAllocator > ValueType
Definition: schema.h:2448
void DisallowedProperty(const Ch *name, SizeType length)
Definition: schema.h:2682
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root, const bool inheritContinueOnErrors)
Definition: schema.h:2898
void Reset()
Reset the internal states.
Definition: schema.h:2518
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:2594
virtual void FreeState(void *p)
Definition: schema.h:2932
void MultipleOneOf(SizeType index1, SizeType index2)
Definition: schema.h:2757
bool EndMissingProperties()
Definition: schema.h:2669
bool StartObject()
Definition: schema.h:2842
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:2554
void NotMultipleOf(uint64_t actual, const SValue &expected)
Definition: schema.h:2588
GenericStringRef< Ch > StringRefType
Definition: schema.h:2447
bool EndArray(SizeType elementCount)
Definition: schema.h:2882
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
Definition: schema.h:2734
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:2850
bool Null()
Definition: schema.h:2830
void StartDependencyErrors()
Definition: schema.h:2688
void TooShort(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:2623
void TooManyItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:2642
ValueType & GetError()
End of Implementation of ISchemaValidator.
Definition: schema.h:2549
virtual void * MallocState(size_t size)
Definition: schema.h:2928
void DuplicateItems(SizeType index1, SizeType index2)
Definition: schema.h:2646
void ResetError()
Reset the error state.
Definition: schema.h:2526
void AddMissingDependentProperty(const SValue &targetName)
Definition: schema.h:2694
EncodingType::Ch Ch
Definition: schema.h:2446
void AddMissingProperty(const SValue &name)
Definition: schema.h:2666
virtual bool IsValid() const
Definition: schema.h:2541
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:2598
void StartDisallowedType()
Definition: schema.h:2731
bool Bool(bool b)
Definition: schema.h:2831
void DisallowedWhenWriting()
Definition: schema.h:2769
bool Uint(unsigned u)
Definition: schema.h:2833
bool EndObject(SizeType memberCount)
Definition: schema.h:2863
void DisallowedWhenReading()
Definition: schema.h:2773
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2751
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:2659
void NotMultipleOf(int64_t actual, const SValue &expected)
Definition: schema.h:2585
bool EndDependencyErrors()
Definition: schema.h:2717
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:2560
bool StartArray()
Definition: schema.h:2874
virtual void * CreateHasher()
Definition: schema.h:2914
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:2602
bool Uint64(uint64_t u)
Definition: schema.h:2835
virtual uint64_t GetHashCode(void *hasher)
Definition: schema.h:2918
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:2576
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition: schema.h:2487
void StartMissingDependentProperties()
Definition: schema.h:2691
bool Int64(int64_t i)
Definition: schema.h:2834
SchemaDocumentType::SchemaType SchemaType
Definition: schema.h:2442
void Disallowed()
Definition: schema.h:2765
SchemaType::EncodingType EncodingType
Definition: schema.h:2444
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:2610
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2754
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:2655
bool Int(int i)
Definition: schema.h:2832
SchemaDocumentType::PointerType PointerType
Definition: schema.h:2443
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
Definition: schema.h:2737
virtual void DestroySchemaValidator(ISchemaValidator *validator)
Definition: schema.h:2908
bool RawNumber(const Ch *str, SizeType length, bool copy)
Definition: schema.h:2837
void NotMultipleOf(double actual, const SValue &expected)
Definition: schema.h:2591
ValidateErrorCode GetInvalidSchemaCode() const
Gets the error code of invalid schema.
Definition: schema.h:2568
bool Double(double d)
Definition: schema.h:2836
void DoesNotMatch(const Ch *str, SizeType length)
Definition: schema.h:2627
void TooFewItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:2638
void SetValidateFlags(unsigned flags)
Implementation of ISchemaValidator.
Definition: schema.h:2534
void DisallowedValue(const ValidateErrorCode code=kValidateErrorEnum)
Definition: schema.h:2727
void EndMissingDependentProperties(const SValue &sourceName)
Definition: schema.h:2697
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:2614
Represents an in-memory output stream.
Definition: stringbuffer.h:41
Ch * Push(size_t count)
Definition: stringbuffer.h:69
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition: stringbuffer.h:82
const Ch * GetString() const
Definition: stringbuffer.h:73
const Ch * GetString() const
Definition: uri.h:103
GenericUri Resolve(const GenericUri &baseuri, Allocator *allocator=0)
Resolve this URI against another (base) URI in accordance with URI resolution rules.
Definition: uri.h:156
SizeType GetBaseStringLength() const
Definition: uri.h:106
const Ch * GetBaseString() const
Definition: uri.h:105
GenericMemberIterator< false, EncodingType, AllocatorType >::Iterator MemberIterator
Member iterator for iterating in object.
Definition: document.h:676
const GenericValue * ConstValueIterator
Constant value iterator for iterating in array.
Definition: document.h:679
Definition: schema.h:1785
virtual const SchemaDocumentType * GetRemoteDocument(const GenericUri< ValueType, AllocatorType > uri, Specification &spec)
Definition: schema.h:1793
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:1789
virtual ~IGenericRemoteSchemaDocumentProvider()
Definition: schema.h:1791
virtual const SchemaDocumentType * GetRemoteDocument(const Ch *uri, SizeType length)=0
SchemaDocumentType::Ch Ch
Definition: schema.h:1787
SchemaDocumentType::ValueType ValueType
Definition: schema.h:1788
Default memory allocator used by the parser and DOM.
Definition: allocators.h:130
A helper class for parsing with validation.
Definition: schema.h:3199
SchemaDocumentType::PointerType PointerType
Definition: schema.h:3201
bool IsValid() const
Definition: schema.h:3237
const PointerType & GetInvalidDocumentPointer() const
Definition: schema.h:3240
ValidateErrorCode GetInvalidSchemaCode() const
Definition: schema.h:3242
InputStream::Ch Ch
Definition: schema.h:3202
bool operator()(Handler &handler)
Definition: schema.h:3213
const ValueType & GetError() const
Definition: schema.h:3241
const PointerType & GetInvalidSchemaPointer() const
Definition: schema.h:3238
const Ch * GetInvalidSchemaKeyword() const
Definition: schema.h:3239
const ParseResult & GetParseResult() const
Definition: schema.h:3236
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:3210
GenericValue< SourceEncoding, StackAllocator > ValueType
Definition: schema.h:3203
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:110
Definition: schema.h:330
bool Bool(bool b)
Definition: schema.h:337
bool Uint64(uint64_t u)
Definition: schema.h:341
bool StartObject()
Definition: schema.h:360
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:361
bool StartArray()
Definition: schema.h:373
Encoding::Ch Ch
Definition: schema.h:332
bool Uint(unsigned u)
Definition: schema.h:339
bool Null()
Definition: schema.h:336
bool EndObject(SizeType memberCount)
Definition: schema.h:362
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
Definition: schema.h:334
bool Double(double d)
Definition: schema.h:342
bool String(const Ch *str, SizeType len, bool)
Definition: schema.h:355
bool Int(int i)
Definition: schema.h:338
uint64_t GetHashCode() const
Definition: schema.h:385
bool EndArray(SizeType elementCount)
Definition: schema.h:374
bool Int64(int64_t i)
Definition: schema.h:340
bool IsValid() const
Definition: schema.h:383
bool RawNumber(const Ch *str, SizeType len, bool)
Definition: schema.h:350
Definition: schema.h:254
virtual void DestroySchemaValidator(ISchemaValidator *validator)=0
virtual void FreeState(void *p)=0
virtual void * CreateHasher()=0
virtual void DestroryHasher(void *hasher)=0
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &, const bool inheritContinueOnErrors)=0
virtual void * MallocState(size_t size)=0
virtual uint64_t GetHashCode(void *hasher)=0
virtual ~ISchemaStateFactory()
Definition: schema.h:256
Definition: schema.h:242
virtual void SetValidateFlags(unsigned flags)=0
virtual bool IsValid() const =0
virtual unsigned GetValidateFlags() const =0
virtual ~ISchemaValidator()
Definition: schema.h:244
Definition: schema.h:270
virtual void EndMissingDependentProperties(const SValue &sourceName)=0
virtual void DisallowedItem(SizeType index)=0
virtual void NotMultipleOf(int64_t actual, const SValue &expected)=0
virtual void DisallowedWhenWriting()=0
SchemaType::Ch Ch
Definition: schema.h:272
SchemaType::SValue SValue
Definition: schema.h:273
virtual void AddMissingDependentProperty(const SValue &targetName)=0
virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount)=0
virtual bool EndMissingProperties()=0
virtual void DuplicateItems(SizeType index1, SizeType index2)=0
virtual void AddMissingProperty(const SValue &name)=0
virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator)=0
virtual void TooShort(const Ch *str, SizeType length, SizeType expected)=0
virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual void AboveMaximum(double actual, const SValue &expected, bool exclusive)=0
virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType)=0
virtual void DisallowedValue(const ValidateErrorCode code)=0
virtual void DisallowedProperty(const Ch *name, SizeType length)=0
virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual ~IValidationErrorHandler()
Definition: schema.h:275
virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual bool EndDependencyErrors()=0
virtual void BelowMinimum(double actual, const SValue &expected, bool exclusive)=0
virtual void TooManyItems(SizeType actualCount, SizeType expectedCount)=0
virtual void DoesNotMatch(const Ch *str, SizeType length)=0
virtual void StartDisallowedType()=0
virtual void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual void StartDependencyErrors()=0
virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)=0
virtual void StartMissingProperties()=0
virtual void DisallowedWhenReading()=0
virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType)=0
virtual void NotMultipleOf(uint64_t actual, const SValue &expected)=0
virtual void NotMultipleOf(double actual, const SValue &expected)=0
virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount)=0
virtual void TooLong(const Ch *str, SizeType length, SizeType expected)=0
virtual void StartMissingDependentProperties()=0
virtual void MultipleOneOf(SizeType index1, SizeType index2)=0
virtual void TooFewItems(SizeType actualCount, SizeType expectedCount)=0
Definition: schema.h:518
bool Int64(Context &context, int64_t i) const
Definition: schema.h:1020
bool StartArray(Context &context) const
Definition: schema.h:1205
bool StartObject(Context &context) const
Definition: schema.h:1082
SchemaDocumentType::PointerType PointerType
Definition: schema.h:522
const UriType & GetId() const
Definition: schema.h:855
bool Int(Context &context, int i) const
Definition: schema.h:1006
bool Uint64(Context &context, uint64_t u) const
Definition: schema.h:1027
IValidationErrorHandler< Schema > ErrorHandler
Definition: schema.h:528
const PointerType & GetPointer() const
Definition: schema.h:863
GenericUri< ValueType, AllocatorType > UriType
Definition: schema.h:529
~Schema()
Definition: schema.h:830
const Specification & GetSpecification() const
Definition: schema.h:859
bool EndObject(Context &context, SizeType memberCount) const
Definition: schema.h:1157
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator, const UriType &id=UriType())
Definition: schema.h:532
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:521
bool EndArray(Context &context, SizeType elementCount) const
Definition: schema.h:1218
bool Double(Context &context, double d) const
Definition: schema.h:1034
SchemaDocumentType::ValueType ValueType
Definition: schema.h:520
const SValue & GetURI() const
Definition: schema.h:851
bool String(Context &context, const Ch *str, SizeType length, bool) const
Definition: schema.h:1053
EncodingType::Ch Ch
Definition: schema.h:524
ValueType::EncodingType EncodingType
Definition: schema.h:523
GenericValue< EncodingType, AllocatorType > SValue
Definition: schema.h:527
bool Uint(Context &context, unsigned u) const
Definition: schema.h:1013
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Definition: schema.h:1104
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:526
static const ValueType & GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)
Definition: schema.h:1235
SchemaValidationContext< SchemaDocumentType > Context
Definition: schema.h:525
bool Null(Context &context) const
Definition: schema.h:990
bool Bool(Context &context, bool b) const
Definition: schema.h:999
bool BeginValue(Context &context) const
Definition: schema.h:867
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Definition: schema.h:899
A type-unsafe stack for storing different types of data.
Definition: stack.h:37
Concept for allocating, resizing and freeing memory block.
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS
User-defined kValidateDefaultFlags definition.
Definition: schema.h:174
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:437
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
ValidateErrorCode
Error codes when validating.
Definition: error.h:162
SchemaErrorCode
Error codes when validating.
Definition: error.h:220
@ kValidateErrorMinProperties
Object has less members than 'minProperties' value.
Definition: error.h:182
@ kValidateErrorExclusiveMinimum
Number is less than or equal to the 'minimum' value.
Definition: error.h:170
@ kValidateErrorAdditionalItems
Array has additional items that are not allowed by the schema.
Definition: error.h:179
@ kValidateErrorMaxProperties
Object has more members than 'maxProperties' value.
Definition: error.h:181
@ kValidateErrorOneOfMatch
Property matched more than one of the sub-schemas specified by 'oneOf'.
Definition: error.h:192
@ kValidateErrorRequired
Object is missing one or more members required by the schema.
Definition: error.h:183
@ kValidateErrorDependencies
Object has missing property or schema dependencies.
Definition: error.h:186
@ kValidateErrorUniqueItems
Array has duplicate items but 'uniqueItems' is true.
Definition: error.h:178
@ kValidateErrorReadOnly
Property is read-only but has been provided when validation is for writing.
Definition: error.h:197
@ kValidateErrorEnum
Property has a value that is not one of its allowed enumerated values.
Definition: error.h:188
@ kValidateErrorExclusiveMaximum
Number is greater than or equal to the 'maximum' value.
Definition: error.h:168
@ kValidateErrorType
Property has a type that is not allowed by the schema.
Definition: error.h:189
@ kValidateErrorOneOf
Property did not match any of the sub-schemas specified by 'oneOf'.
Definition: error.h:191
@ kValidateErrorMinLength
String is longer than the 'maxLength' value.
Definition: error.h:173
@ kValidateErrors
Top level error code when kValidateContinueOnErrorsFlag set.
Definition: error.h:163
@ kValidateErrorMaxLength
String is longer than the 'maxLength' value.
Definition: error.h:172
@ kValidateErrorWriteOnly
Property is write-only but has been provided when validation is for reading.
Definition: error.h:198
@ kValidateErrorAnyOf
Property did not match any of the sub-schemas specified by 'anyOf'.
Definition: error.h:194
@ kValidateErrorPattern
String does not match the 'pattern' regular expression.
Definition: error.h:174
@ kValidateErrorMaximum
Number is greater than the 'maximum' value.
Definition: error.h:167
@ kValidateErrorMaxItems
Array is longer than the 'maxItems' value.
Definition: error.h:176
@ kValidateErrorMinimum
Number is less than the 'minimum' value.
Definition: error.h:169
@ kValidateErrorMultipleOf
Number is not a multiple of the 'multipleOf' value.
Definition: error.h:166
@ kValidateErrorNone
No error.
Definition: error.h:164
@ kValidateErrorMinItems
Array is shorter than the 'minItems' value.
Definition: error.h:177
@ kValidateErrorNot
Property matched the sub-schema specified by 'not'.
Definition: error.h:195
@ kValidateErrorAdditionalProperties
Object has additional members that are not allowed by the schema.
Definition: error.h:184
@ kValidateErrorPatternProperties
See other errors.
Definition: error.h:185
@ kValidateErrorAllOf
Property did not match all of the sub-schemas specified by 'allOf'.
Definition: error.h:193
@ kSchemaErrorStartUnknown
Pointer to start of schema does not resolve to a location in the document.
Definition: error.h:223
@ kSchemaErrorSpecIllegal
Both JSON schema draft and OpenAPI version found in document.
Definition: error.h:234
@ kSchemaErrorSpecUnsupported
JSON schema draft or OpenAPI version is not supported.
Definition: error.h:233
@ kSchemaErrorRefPlainName
$ref fragment must be a JSON pointer
Definition: error.h:224
@ kSchemaErrorRefNoRemoteProvider
$ref is remote but there is no remote provider
Definition: error.h:229
@ kSchemaErrorSpecUnknown
JSON schema draft or OpenAPI version is not recognized.
Definition: error.h:232
@ kSchemaErrorRefUnknown
$ref does not resolve to a location in the target document
Definition: error.h:227
@ kSchemaErrorRefPointerInvalid
$ref fragment is not a valid JSON pointer at offset
Definition: error.h:226
@ kSchemaErrorRefNoRemoteSchema
$ref is remote but the remote provider did not return a schema
Definition: error.h:230
@ kSchemaErrorRefCyclical
$ref is cyclical
Definition: error.h:228
@ kSchemaErrorRefInvalid
$ref must not be an empty string
Definition: error.h:225
@ kSchemaErrorRegexInvalid
Invalid regular expression in 'pattern' or 'patternProperties'.
Definition: error.h:231
@ kSchemaErrorReadOnlyAndWriteOnly
Property must not be both 'readOnly' and 'writeOnly'.
Definition: error.h:235
#define PRIu64
Definition: inttypes.h:142
#define PRId64
Definition: inttypes.h:88
__host__ constexpr __device__ auto depth(const Layout< Shape, UnrolledDescriptorType > &layout)
Get depth of the layout shape (return 0 if scalar).
Definition: layout_utils.hpp:371
__host__ T floor(T x)
Definition: math_v2.hpp:367
__host__ constexpr __device__ T min(T x)
Definition: math.hpp:116
auto copy(InputRange &&range, OutputIterator iter) -> decltype(std::copy(std::begin(std::forward< InputRange >(range)), std::end(std::forward< InputRange >(range)), iter))
Definition: algorithm.hpp:14
integral_constant< index_t, N > Number
Definition: number.hpp:12
Definition: allocators.h:423
char * u32toa(uint32_t value, char *buffer)
Definition: itoa.h:39
char * u64toa(uint64_t value, char *buffer)
Definition: itoa.h:126
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1350
#define RAPIDJSON_IF_CONSTEXPR
Definition: pointer.h:34
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1249
const CharType(& source)[N]
Definition: pointer.h:1272
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1249
Type
Type of JSON value.
Definition: rapidjson.h:729
@ kFalseType
false
Definition: rapidjson.h:731
@ kObjectType
object
Definition: rapidjson.h:733
@ kTrueType
true
Definition: rapidjson.h:732
@ kStringType
string
Definition: rapidjson.h:735
@ kNullType
null
Definition: rapidjson.h:730
@ kArrayType
array
Definition: rapidjson.h:734
@ kNumberType
number
Definition: rapidjson.h:736
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:716
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:415
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:320
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:712
GenericSchemaValidator< SchemaDocument > SchemaValidator
Definition: schema.h:3178
#define RAPIDJSON_SCHEMA_PRINT(name,...)
Definition: schema.h:149
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
Definition: schema.h:2799
ValidateFlag
Combination of validate flags.
Definition: schema.h:178
@ kValidateNoFlags
No flags are set.
Definition: schema.h:179
@ kValidateWriteFlag
Validation is for a write semantic.
Definition: schema.h:182
@ kValidateDefaultFlags
Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS.
Definition: schema.h:183
@ kValidateReadFlag
Validation is for a read semantic.
Definition: schema.h:181
@ kValidateContinueOnErrorFlag
Don't stop after first validation error.
Definition: schema.h:180
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
Definition: schema.h:2414
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
Definition: schema.h:2825
SchemaDraft
Definition: schema.h:188
@ kDraftUnknown
Definition: schema.h:189
@ kDraft03
Definition: schema.h:191
@ kDraftNone
Definition: schema.h:190
@ kDraft2020_12
Definition: schema.h:199
@ kDraft07
Definition: schema.h:197
@ kDraft06
Definition: schema.h:196
@ kDraft2019_09
Definition: schema.h:198
@ kDraft04
Definition: schema.h:193
@ kDraftMin
Current minimum supported draft.
Definition: schema.h:192
@ kDraft05
Definition: schema.h:194
@ kDraftMax
Current maximum supported draft.
Definition: schema.h:195
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
Definition: schema.h:2821
#define RAPIDJSON_STRING_(name,...)
Definition: schema.h:2778
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)
Definition: schema.h:156
OpenApiVersion
Definition: schema.h:202
@ kVersionMax
Current maximum supported version.
Definition: schema.h:208
@ kVersion20
Definition: schema.h:206
@ kVersionMin
Current minimum supported version.
Definition: schema.h:205
@ kVersionUnknown
Definition: schema.h:203
@ kVersion30
Definition: schema.h:207
@ kVersion31
Definition: schema.h:209
@ kVersionNone
Definition: schema.h:204
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
Definition: schema.h:2809
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition: schema.h:2416
signed __int64 int64_t
Definition: stdint.h:135
unsigned __int64 uint64_t
Definition: stdint.h:136
Reference to a constant string (not taking a copy)
Definition: document.h:346
Result of parsing (wraps ParseErrorCode)
Definition: error.h:106
Definition: schema.h:212
Specification(OpenApiVersion o)
Definition: schema.h:214
SchemaDraft draft
Definition: schema.h:224
bool IsSupported() const
Definition: schema.h:221
OpenApiVersion oapi
Definition: schema.h:225
~Specification()
Definition: schema.h:220
Specification(SchemaDraft d)
Definition: schema.h:213
Definition: schema.h:428
bool arrayUniqueness
Definition: schema.h:511
SizeType validatorCount
Definition: schema.h:500
const SchemaType ** patternPropertiesSchemas
Definition: schema.h:503
ISchemaValidator ** validators
Definition: schema.h:499
SizeType arrayElementIndex
Definition: schema.h:507
bool valueUniqueness
Definition: schema.h:510
SizeType patternPropertiesValidatorCount
Definition: schema.h:502
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
Definition: schema.h:430
const SchemaType * valueSchema
Definition: schema.h:494
bool * propertyExist
Definition: schema.h:508
void * hasher
Definition: schema.h:497
IValidationErrorHandler< SchemaType > ErrorHandlerType
Definition: schema.h:431
PatternValidatorType
Definition: schema.h:435
@ kPatternValidatorWithProperty
Definition: schema.h:437
@ kPatternValidatorWithAdditionalProperty
Definition: schema.h:438
@ kPatternValidatorOnly
Definition: schema.h:436
ValidateErrorCode invalidCode
Definition: schema.h:496
void * arrayElementHashCodes
Definition: schema.h:498
ISchemaValidator ** patternPropertiesValidators
Definition: schema.h:501
SizeType patternPropertiesSchemaCount
Definition: schema.h:504
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:429
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s, unsigned fl=0)
Definition: schema.h:441
const Ch * invalidKeyword
Definition: schema.h:495
~SchemaValidationContext()
Definition: schema.h:465
unsigned flags
Definition: schema.h:493
ValueType::Ch Ch
Definition: schema.h:433
SchemaType::ValueType ValueType
Definition: schema.h:432
PatternValidatorType valuePatternValidatorType
Definition: schema.h:505
ErrorHandlerType & error_handler
Definition: schema.h:491
PatternValidatorType objectPatternValidatorType
Definition: schema.h:506
SchemaValidatorFactoryType & factory
Definition: schema.h:490
bool inArray
Definition: schema.h:509
const SchemaType * schema
Definition: schema.h:492
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1763
Definition: schema.h:1750
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1751
Definition: schema.h:393
int64_t i
Definition: schema.h:395
uint64_t u
Definition: schema.h:394