/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) || \
30  !(__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
32 #endif
33 
34 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
35 #include "internal/regex.h"
36 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
37 #include <regex>
38 #endif
39 
40 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
41 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
42 #else
43 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
44 #endif
45 
46 #ifndef RAPIDJSON_SCHEMA_VERBOSE
47 #define RAPIDJSON_SCHEMA_VERBOSE 0
48 #endif
49 
50 RAPIDJSON_DIAG_PUSH
51 
52 #if defined(__GNUC__)
53 RAPIDJSON_DIAG_OFF(effc++)
54 #endif
55 
56 #ifdef __clang__
57 RAPIDJSON_DIAG_OFF(weak - vtables)
58 RAPIDJSON_DIAG_OFF(exit - time - destructors)
59 RAPIDJSON_DIAG_OFF(c++ 98 - compat - pedantic)
60 RAPIDJSON_DIAG_OFF(variadic - macros)
61 #elif defined(_MSC_VER)
62 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
63 #endif
64 
66 
68 // Verbose Utilities
69 
70 #if RAPIDJSON_SCHEMA_VERBOSE
71 
72 namespace internal {
73 
74 inline void PrintInvalidKeywordData(const char* keyword)
75 {
76  printf(" Fail keyword: '%s'\n", keyword);
77 }
78 
79 inline void PrintInvalidKeywordData(const wchar_t* keyword)
80 {
81  wprintf(L" Fail keyword: '%ls'\n", keyword);
82 }
83 
84 inline void PrintInvalidDocumentData(const char* document)
85 {
86  printf(" Fail document: '%s'\n", document);
87 }
88 
89 inline void PrintInvalidDocumentData(const wchar_t* document)
90 {
91  wprintf(L" Fail document: '%ls'\n", document);
92 }
93 
94 inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth)
95 {
96  printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
97 }
98 
99 inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth)
100 {
101  wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
102 }
103 
104 inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved)
105 {
106  printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
107 }
108 
109 inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved)
110 {
111  wprintf(
112  L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
113 }
114 
115 inline void PrintMethodData(const char* method) { printf("%s\n", method); }
116 
117 inline void PrintMethodData(const char* method, bool b)
118 {
119  printf("%s, Data: '%s'\n", method, b ? "true" : "false");
120 }
121 
122 inline void PrintMethodData(const char* method, int64_t i)
123 {
124  printf("%s, Data: '%" PRId64 "'\n", method, i);
125 }
126 
127 inline void PrintMethodData(const char* method, uint64_t u)
128 {
129  printf("%s, Data: '%" PRIu64 "'\n", method, u);
130 }
131 
132 inline void PrintMethodData(const char* method, double d)
133 {
134  printf("%s, Data: '%lf'\n", method, d);
135 }
136 
137 inline void PrintMethodData(const char* method, const char* s)
138 {
139  printf("%s, Data: '%s'\n", method, s);
140 }
141 
142 inline void PrintMethodData(const char* method, const wchar_t* s)
143 {
144  wprintf(L"%hs, Data: '%ls'\n", method, s);
145 }
146 
147 inline void PrintMethodData(const char* method, const char* s1, const char* s2)
148 {
149  printf("%s, Data: '%s', '%s'\n", method, s1, s2);
150 }
151 
152 inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2)
153 {
154  wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
155 }
156 
157 } // namespace internal
158 
159 #endif // RAPIDJSON_SCHEMA_VERBOSE
160 
161 #ifndef RAPIDJSON_SCHEMA_PRINT
162 #if RAPIDJSON_SCHEMA_VERBOSE
163 #define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
164 #else
165 #define RAPIDJSON_SCHEMA_PRINT(name, ...)
166 #endif
167 #endif
168 
170 // RAPIDJSON_INVALID_KEYWORD_RETURN
171 
172 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code) \
173  RAPIDJSON_MULTILINEMACRO_BEGIN \
174  context.invalidCode = code; \
175  context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString(); \
176  RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword); \
177  return false; \
178  RAPIDJSON_MULTILINEMACRO_END
179 
181 // ValidateFlag
182 
189 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
190 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
191 #endif
192 
195 {
203 };
204 
206 // Specification
208 {
211  kDraft03 = 3,
212  kDraftMin = 4,
213  kDraft04 = 4,
214  kDraft05 = 5,
215  kDraftMax = 5,
216  kDraft06 = 6,
217  kDraft07 = 7,
219  kDraft2020_12 = 9
220 };
221 
223 {
231 };
232 
234 {
237  {
238  if(oapi == kVersion20)
239  draft = kDraft04;
240  else if(oapi == kVersion30)
241  draft = kDraft05;
242  else if(oapi == kVersion31)
244  else
245  draft = kDraft04;
246  }
248  bool IsSupported() const
249  {
250  return ((draft >= kDraftMin && draft <= kDraftMax) &&
251  ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
252  }
255 };
256 
258 // Forward declarations
259 
260 template <typename ValueType, typename Allocator>
262 
263 namespace internal {
264 
265 template <typename SchemaDocumentType>
266 class Schema;
267 
269 // ISchemaValidator
270 
272 {
273  public:
274  virtual ~ISchemaValidator() {}
275  virtual bool IsValid() const = 0;
276  virtual void SetValidateFlags(unsigned flags) = 0;
277  virtual unsigned GetValidateFlags() const = 0;
278 };
279 
281 // ISchemaStateFactory
282 
283 template <typename SchemaType>
285 {
286  public:
287  virtual ~ISchemaStateFactory() {}
288  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&,
289  const bool inheritContinueOnErrors) = 0;
290  virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
291  virtual void* CreateHasher() = 0;
292  virtual uint64_t GetHashCode(void* hasher) = 0;
293  virtual void DestroryHasher(void* hasher) = 0;
294  virtual void* MallocState(size_t size) = 0;
295  virtual void FreeState(void* p) = 0;
296 };
297 
299 // IValidationErrorHandler
300 
301 template <typename SchemaType>
303 {
304  public:
305  typedef typename SchemaType::Ch Ch;
306  typedef typename SchemaType::SValue SValue;
307 
309 
310  virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
311  virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
312  virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
313  virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
314  virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
315  virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
316  virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
317  virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
318  virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
319 
320  virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
321  virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
322  virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
323 
324  virtual void DisallowedItem(SizeType index) = 0;
325  virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
326  virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
327  virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
328 
329  virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
330  virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
331  virtual void StartMissingProperties() = 0;
332  virtual void AddMissingProperty(const SValue& name) = 0;
333  virtual bool EndMissingProperties() = 0;
334  virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
335  virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
336 
337  virtual void StartDependencyErrors() = 0;
339  virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
340  virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
341  virtual void AddDependencySchemaError(const SValue& souceName,
342  ISchemaValidator* subvalidator) = 0;
343  virtual bool EndDependencyErrors() = 0;
344 
345  virtual void DisallowedValue(const ValidateErrorCode code) = 0;
346  virtual void StartDisallowedType() = 0;
347  virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
348  virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
349  virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
350  virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
351  virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
352  virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
353  virtual void Disallowed() = 0;
354  virtual void DisallowedWhenWriting() = 0;
355  virtual void DisallowedWhenReading() = 0;
356 };
357 
359 // Hasher
360 
361 // For comparison of compound value
362 template <typename Encoding, typename Allocator>
363 class Hasher
364 {
365  public:
366  typedef typename Encoding::Ch Ch;
367 
368  Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize)
369  : stack_(allocator, stackCapacity)
370  {
371  }
372 
373  bool Null() { return WriteType(kNullType); }
374  bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
375  bool Int(int i)
376  {
377  Number n;
378  n.u.i = i;
379  n.d = static_cast<double>(i);
380  return WriteNumber(n);
381  }
382  bool Uint(unsigned u)
383  {
384  Number n;
385  n.u.u = u;
386  n.d = static_cast<double>(u);
387  return WriteNumber(n);
388  }
389  bool Int64(int64_t i)
390  {
391  Number n;
392  n.u.i = i;
393  n.d = static_cast<double>(i);
394  return WriteNumber(n);
395  }
396  bool Uint64(uint64_t u)
397  {
398  Number n;
399  n.u.u = u;
400  n.d = static_cast<double>(u);
401  return WriteNumber(n);
402  }
403  bool Double(double d)
404  {
405  Number n;
406  if(d < 0)
407  n.u.i = static_cast<int64_t>(d);
408  else
409  n.u.u = static_cast<uint64_t>(d);
410  n.d = d;
411  return WriteNumber(n);
412  }
413 
414  bool RawNumber(const Ch* str, SizeType len, bool)
415  {
416  WriteBuffer(kNumberType, str, len * sizeof(Ch));
417  return true;
418  }
419 
420  bool String(const Ch* str, SizeType len, bool)
421  {
422  WriteBuffer(kStringType, str, len * sizeof(Ch));
423  return true;
424  }
425 
426  bool StartObject() { return true; }
427  bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
428  bool EndObject(SizeType memberCount)
429  {
430  uint64_t h = Hash(0, kObjectType);
431  uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
432  for(SizeType i = 0; i < memberCount; i++)
433  // Issue #2205
434  // Hasing the key to avoid key=value cases with bug-prone zero-value hash
435  h ^= Hash(Hash(0, kv[i * 2]),
436  kv[i * 2 + 1]); // Use xor to achieve member order insensitive
437  *stack_.template Push<uint64_t>() = h;
438  return true;
439  }
440 
441  bool StartArray() { return true; }
442  bool EndArray(SizeType elementCount)
443  {
444  uint64_t h = Hash(0, kArrayType);
445  uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
446  for(SizeType i = 0; i < elementCount; i++)
447  h = Hash(h, e[i]); // Use hash to achieve element order sensitive
448  *stack_.template Push<uint64_t>() = h;
449  return true;
450  }
451 
452  bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
453 
455  {
457  return *stack_.template Top<uint64_t>();
458  }
459 
460  private:
461  static const size_t kDefaultSize = 256;
462  struct Number
463  {
464  union U
465  {
468  } u;
469  double d;
470  };
471 
472  bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
473 
474  bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
475 
476  bool WriteBuffer(Type type, const void* data, size_t len)
477  {
478  // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
479  uint64_t h = Hash(RAPIDJSON_UINT64_C2(0xcbf29ce4, 0x84222325), type);
480  const unsigned char* d = static_cast<const unsigned char*>(data);
481  for(size_t i = 0; i < len; i++)
482  h = Hash(h, d[i]);
483  *stack_.template Push<uint64_t>() = h;
484  return true;
485  }
486 
487  static uint64_t Hash(uint64_t h, uint64_t d)
488  {
489  static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
490  h ^= d;
491  h *= kPrime;
492  return h;
493  }
494 
495  Stack<Allocator> stack_;
496 };
497 
499 // SchemaValidationContext
500 
501 template <typename SchemaDocumentType>
503 {
508  typedef typename ValueType::Ch Ch;
509 
511  {
515  };
516 
518  ErrorHandlerType& eh,
519  const SchemaType* s,
520  unsigned fl = 0)
521  : factory(f),
522  error_handler(eh),
523  schema(s),
524  flags(fl),
525  valueSchema(),
526  invalidKeyword(),
527  invalidCode(),
528  hasher(),
530  validators(),
531  validatorCount(),
537  propertyExist(),
538  inArray(false),
539  valueUniqueness(false),
540  arrayUniqueness(false)
541  {
542  }
543 
545  {
546  if(hasher)
548  if(validators)
549  {
550  for(SizeType i = 0; i < validatorCount; i++)
551  {
552  if(validators[i])
553  {
555  }
556  }
558  }
560  {
561  for(SizeType i = 0; i < patternPropertiesValidatorCount; i++)
562  {
564  {
566  }
567  }
569  }
572  if(propertyExist)
574  }
575 
579  unsigned flags;
583  void* hasher; // Only validator access
584  void* arrayElementHashCodes; // Only validator access this
595  bool inArray;
598 };
599 
601 // Schema
602 
603 template <typename SchemaDocumentType>
604 class Schema
605 {
606  public:
607  typedef typename SchemaDocumentType::ValueType ValueType;
608  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
609  typedef typename SchemaDocumentType::PointerType PointerType;
610  typedef typename ValueType::EncodingType EncodingType;
611  typedef typename EncodingType::Ch Ch;
618 
619  Schema(SchemaDocumentType* schemaDocument,
620  const PointerType& p,
621  const ValueType& value,
622  const ValueType& document,
623  AllocatorType* allocator,
624  const UriType& id = UriType())
625  : allocator_(allocator),
626  uri_(schemaDocument->GetURI(), *allocator),
627  id_(id, allocator),
628  spec_(schemaDocument->GetSpecification()),
629  pointer_(p, allocator),
630  typeless_(schemaDocument->GetTypeless()),
631  enum_(),
632  enumCount_(),
633  not_(),
634  type_((1 << kTotalSchemaType) - 1), // typeless
635  validatorCount_(),
637  properties_(),
641  propertyCount_(),
642  minProperties_(),
644  additionalProperties_(true),
646  hasRequired_(),
649  itemsList_(),
650  itemsTuple_(),
652  minItems_(),
653  maxItems_(SizeType(~0)),
654  additionalItems_(true),
655  uniqueItems_(false),
656  pattern_(),
657  minLength_(0),
658  maxLength_(~SizeType(0)),
659  exclusiveMinimum_(false),
660  exclusiveMaximum_(false),
662  readOnly_(false),
663  writeOnly_(false),
664  nullable_(false)
665  {
667  p.StringifyUriFragment(sb);
668  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
669 
670  typedef typename ValueType::ConstValueIterator ConstValueIterator;
671  typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
672 
673  // PR #1393
674  // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
675  // recursion (with recursive schemas), since schemaDocument->getSchema() is always
676  // checked before creating a new one. Don't cache typeless_, though.
677  if(this != typeless_)
678  {
679  typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
680  SchemaEntry* entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
681  new(entry) SchemaEntry(pointer_, this, true, allocator_);
682  schemaDocument->AddSchemaRefs(this);
683  }
684 
685  if(!value.IsObject())
686  return;
687 
688  // If we have an id property, resolve it with the in-scope id
689  // Not supported for open api 2.0 or 3.0
691  if(const ValueType* v = GetMember(value, GetIdString()))
692  {
693  if(v->IsString())
694  {
695  UriType local(*v, allocator);
696  id_ = local.Resolve(id_, allocator);
698  SchemaIds, id.GetString(), v->GetString(), id_.GetString());
699  }
700  }
701 
702  if(const ValueType* v = GetMember(value, GetTypeString()))
703  {
704  type_ = 0;
705  if(v->IsString())
706  AddType(*v);
707  else if(v->IsArray())
708  for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
709  AddType(*itr);
710  }
711 
712  if(const ValueType* v = GetMember(value, GetEnumString()))
713  {
714  if(v->IsArray() && v->Size() > 0)
715  {
716  enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
717  for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
718  {
720  char buffer[256u + 24];
721  MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer, sizeof(buffer));
722  EnumHasherType h(&hasherAllocator, 256);
723  itr->Accept(h);
724  enum_[enumCount_++] = h.GetHashCode();
725  }
726  }
727  }
728 
729  if(schemaDocument)
730  AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
731 
732  // AnyOf, OneOf, Not not supported for open api 2.0
733  if(schemaDocument && spec_.oapi != kVersion20)
734  {
735  AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
736  AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
737 
738  if(const ValueType* v = GetMember(value, GetNotString()))
739  {
740  schemaDocument->CreateSchema(
741  &not_, p.Append(GetNotString(), allocator_), *v, document, id_);
743  validatorCount_++;
744  }
745  }
746 
747  // Object
748 
749  const ValueType* properties = GetMember(value, GetPropertiesString());
750  const ValueType* required = GetMember(value, GetRequiredString());
751  const ValueType* dependencies = GetMember(value, GetDependenciesString());
752  {
753  // Gather properties from properties/required/dependencies
754  SValue allProperties(kArrayType);
755 
756  if(properties && properties->IsObject())
757  for(ConstMemberIterator itr = properties->MemberBegin();
758  itr != properties->MemberEnd();
759  ++itr)
760  AddUniqueElement(allProperties, itr->name);
761 
762  if(required && required->IsArray())
763  for(ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
764  if(itr->IsString())
765  AddUniqueElement(allProperties, *itr);
766 
767  // Dependencies not supported for open api 2.0 and 3.0
769  if(dependencies && dependencies->IsObject())
770  for(ConstMemberIterator itr = dependencies->MemberBegin();
771  itr != dependencies->MemberEnd();
772  ++itr)
773  {
774  AddUniqueElement(allProperties, itr->name);
775  if(itr->value.IsArray())
776  for(ConstValueIterator i = itr->value.Begin(); i != itr->value.End();
777  ++i)
778  if(i->IsString())
779  AddUniqueElement(allProperties, *i);
780  }
781 
782  if(allProperties.Size() > 0)
783  {
784  propertyCount_ = allProperties.Size();
785  properties_ =
786  static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
787  for(SizeType i = 0; i < propertyCount_; i++)
788  {
789  new(&properties_[i]) Property();
790  properties_[i].name = allProperties[i];
792  }
793  }
794  }
795 
796  if(properties && properties->IsObject())
797  {
798  PointerType q = p.Append(GetPropertiesString(), allocator_);
799  for(ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd();
800  ++itr)
801  {
802  SizeType index;
803  if(FindPropertyIndex(itr->name, &index))
804  schemaDocument->CreateSchema(&properties_[index].schema,
805  q.Append(itr->name, allocator_),
806  itr->value,
807  document,
808  id_);
809  }
810  }
811 
812  // PatternProperties not supported for open api 2.0 and 3.0
814  if(const ValueType* v = GetMember(value, GetPatternPropertiesString()))
815  {
816  PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
817  patternProperties_ = static_cast<PatternProperty*>(
818  allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
820 
821  for(ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr)
822  {
824  PointerType r = q.Append(itr->name, allocator_);
826  CreatePattern(itr->name, schemaDocument, r);
827  schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema,
828  r,
829  itr->value,
830  document,
831  id_);
833  }
834  }
835 
836  if(required && required->IsArray())
837  for(ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
838  if(itr->IsString())
839  {
840  SizeType index;
841  if(FindPropertyIndex(*itr, &index))
842  {
843  properties_[index].required = true;
844  hasRequired_ = true;
845  }
846  }
847 
848  // Dependencies not supported for open api 2.0 and 3.0
850  if(dependencies && dependencies->IsObject())
851  {
852  PointerType q = p.Append(GetDependenciesString(), allocator_);
853  hasDependencies_ = true;
854  for(ConstMemberIterator itr = dependencies->MemberBegin();
855  itr != dependencies->MemberEnd();
856  ++itr)
857  {
858  SizeType sourceIndex;
859  if(FindPropertyIndex(itr->name, &sourceIndex))
860  {
861  if(itr->value.IsArray())
862  {
863  properties_[sourceIndex].dependencies = static_cast<bool*>(
864  allocator_->Malloc(sizeof(bool) * propertyCount_));
865  std::memset(properties_[sourceIndex].dependencies,
866  0,
867  sizeof(bool) * propertyCount_);
868  for(ConstValueIterator targetItr = itr->value.Begin();
869  targetItr != itr->value.End();
870  ++targetItr)
871  {
872  SizeType targetIndex;
873  if(FindPropertyIndex(*targetItr, &targetIndex))
874  properties_[sourceIndex].dependencies[targetIndex] = true;
875  }
876  }
877  else if(itr->value.IsObject())
878  {
879  hasSchemaDependencies_ = true;
880  schemaDocument->CreateSchema(
881  &properties_[sourceIndex].dependenciesSchema,
882  q.Append(itr->name, allocator_),
883  itr->value,
884  document,
885  id_);
887  validatorCount_++;
888  }
889  }
890  }
891  }
892 
893  if(const ValueType* v = GetMember(value, GetAdditionalPropertiesString()))
894  {
895  if(v->IsBool())
896  additionalProperties_ = v->GetBool();
897  else if(v->IsObject())
898  schemaDocument->CreateSchema(&additionalPropertiesSchema_,
899  p.Append(GetAdditionalPropertiesString(), allocator_),
900  *v,
901  document,
902  id_);
903  }
904 
905  AssignIfExist(minProperties_, value, GetMinPropertiesString());
906  AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
907 
908  // Array
909  if(const ValueType* v = GetMember(value, GetItemsString()))
910  {
911  PointerType q = p.Append(GetItemsString(), allocator_);
912  if(v->IsObject()) // List validation
913  schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
914  else if(v->IsArray())
915  { // Tuple validation
916  itemsTuple_ = static_cast<const Schema**>(
917  allocator_->Malloc(sizeof(const Schema*) * v->Size()));
918  SizeType index = 0;
919  for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
920  schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++],
921  q.Append(index, allocator_),
922  *itr,
923  document,
924  id_);
925  }
926  }
927 
928  AssignIfExist(minItems_, value, GetMinItemsString());
929  AssignIfExist(maxItems_, value, GetMaxItemsString());
930 
931  // AdditionalItems not supported for openapi 2.0 and 3.0
933  if(const ValueType* v = GetMember(value, GetAdditionalItemsString()))
934  {
935  if(v->IsBool())
936  additionalItems_ = v->GetBool();
937  else if(v->IsObject())
938  schemaDocument->CreateSchema(&additionalItemsSchema_,
939  p.Append(GetAdditionalItemsString(), allocator_),
940  *v,
941  document,
942  id_);
943  }
944 
945  AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
946 
947  // String
948  AssignIfExist(minLength_, value, GetMinLengthString());
949  AssignIfExist(maxLength_, value, GetMaxLengthString());
950 
951  if(const ValueType* v = GetMember(value, GetPatternString()))
952  pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
953 
954  // Number
955  if(const ValueType* v = GetMember(value, GetMinimumString()))
956  if(v->IsNumber())
957  minimum_.CopyFrom(*v, *allocator_);
958 
959  if(const ValueType* v = GetMember(value, GetMaximumString()))
960  if(v->IsNumber())
961  maximum_.CopyFrom(*v, *allocator_);
962 
963  AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
964  AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
965 
966  if(const ValueType* v = GetMember(value, GetMultipleOfString()))
967  if(v->IsNumber() && v->GetDouble() > 0.0)
968  multipleOf_.CopyFrom(*v, *allocator_);
969 
970  // Default
971  if(const ValueType* v = GetMember(value, GetDefaultValueString()))
972  if(v->IsString())
973  defaultValueLength_ = v->GetStringLength();
974 
975  // ReadOnly - open api only (until draft 7 supported)
976  // WriteOnly - open api 3 only (until draft 7 supported)
977  // Both can't be true
978  if(spec_.oapi != kVersionNone)
979  AssignIfExist(readOnly_, value, GetReadOnlyString());
980  if(spec_.oapi >= kVersion30)
981  AssignIfExist(writeOnly_, value, GetWriteOnlyString());
982  if(readOnly_ && writeOnly_)
983  schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
984 
985  // Nullable - open api 3 only
986  // If true add 'null' as allowable type
987  if(spec_.oapi >= kVersion30)
988  {
989  AssignIfExist(nullable_, value, GetNullableString());
990  if(nullable_)
991  AddType(GetNullString());
992  }
993  }
994 
996  {
998  if(properties_)
999  {
1000  for(SizeType i = 0; i < propertyCount_; i++)
1001  properties_[i].~Property();
1003  }
1004  if(patternProperties_)
1005  {
1006  for(SizeType i = 0; i < patternPropertyCount_; i++)
1009  }
1011 #if RAPIDJSON_SCHEMA_HAS_REGEX
1012  if(pattern_)
1013  {
1014  pattern_->~RegexType();
1016  }
1017 #endif
1018  }
1019 
1020  const SValue& GetURI() const { return uri_; }
1021 
1022  const UriType& GetId() const { return id_; }
1023 
1024  const Specification& GetSpecification() const { return spec_; }
1025 
1026  const PointerType& GetPointer() const { return pointer_; }
1027 
1028  bool BeginValue(Context& context) const
1029  {
1030  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
1031  if(context.inArray)
1032  {
1033  if(uniqueItems_)
1034  context.valueUniqueness = true;
1035 
1036  if(itemsList_)
1037  context.valueSchema = itemsList_;
1038  else if(itemsTuple_)
1039  {
1040  if(context.arrayElementIndex < itemsTupleCount_)
1041  context.valueSchema = itemsTuple_[context.arrayElementIndex];
1042  else if(additionalItemsSchema_)
1044  else if(additionalItems_)
1045  context.valueSchema = typeless_;
1046  else
1047  {
1049  // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else
1050  // reports spurious type error
1051  context.valueSchema = typeless_;
1052  // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
1053  context.arrayElementIndex++;
1055  }
1056  }
1057  else
1058  context.valueSchema = typeless_;
1059 
1060  context.arrayElementIndex++;
1061  }
1062  return true;
1063  }
1064 
1065  RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const
1066  {
1067  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
1068  // Only check pattern properties if we have validators
1069  if(context.patternPropertiesValidatorCount > 0)
1070  {
1071  bool otherValid = false;
1072  SizeType count = context.patternPropertiesValidatorCount;
1074  otherValid = context.patternPropertiesValidators[--count]->IsValid();
1075 
1076  bool patternValid = true;
1077  for(SizeType i = 0; i < count; i++)
1078  if(!context.patternPropertiesValidators[i]->IsValid())
1079  {
1080  patternValid = false;
1081  break;
1082  }
1083 
1085  {
1086  if(!patternValid)
1087  {
1089  count);
1091  }
1092  }
1094  {
1095  if(!patternValid || !otherValid)
1096  {
1098  count + 1);
1100  }
1101  }
1102  else if(!patternValid && !otherValid)
1103  { // kPatternValidatorWithAdditionalProperty)
1105  count + 1);
1107  }
1108  }
1109 
1110  // For enums only check if we have a hasher
1111  if(enum_ && context.hasher)
1112  {
1113  const uint64_t h = context.factory.GetHashCode(context.hasher);
1114  for(SizeType i = 0; i < enumCount_; i++)
1115  if(enum_[i] == h)
1116  goto foundEnum;
1119  foundEnum:;
1120  }
1121 
1122  // Only check allOf etc if we have validators
1123  if(context.validatorCount > 0)
1124  {
1125  if(allOf_.schemas)
1126  for(SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
1127  if(!context.validators[i]->IsValid())
1128  {
1129  context.error_handler.NotAllOf(&context.validators[allOf_.begin],
1130  allOf_.count);
1132  }
1133 
1134  if(anyOf_.schemas)
1135  {
1136  for(SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
1137  if(context.validators[i]->IsValid())
1138  goto foundAny;
1139  context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
1141  foundAny:;
1142  }
1143 
1144  if(oneOf_.schemas)
1145  {
1146  bool oneValid = false;
1147  SizeType firstMatch = 0;
1148  for(SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
1149  if(context.validators[i]->IsValid())
1150  {
1151  if(oneValid)
1152  {
1153  context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
1155  }
1156  else
1157  {
1158  oneValid = true;
1159  firstMatch = i - oneOf_.begin;
1160  }
1161  }
1162  if(!oneValid)
1163  {
1166  }
1167  }
1168 
1169  if(not_ && context.validators[notValidatorIndex_]->IsValid())
1170  {
1171  context.error_handler.Disallowed();
1173  }
1174  }
1175 
1176  return true;
1177  }
1178 
1179  bool Null(Context& context) const
1180  {
1181  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
1182  if(!(type_ & (1 << kNullSchemaType)))
1183  {
1184  DisallowedType(context, GetNullString());
1186  }
1187  return CreateParallelValidator(context);
1188  }
1189 
1190  bool Bool(Context& context, bool b) const
1191  {
1192  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b);
1193  if(!CheckBool(context, b))
1194  return false;
1195  return CreateParallelValidator(context);
1196  }
1197 
1198  bool Int(Context& context, int i) const
1199  {
1200  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i);
1201  if(!CheckInt(context, i))
1202  return false;
1203  return CreateParallelValidator(context);
1204  }
1205 
1206  bool Uint(Context& context, unsigned u) const
1207  {
1208  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u);
1209  if(!CheckUint(context, u))
1210  return false;
1211  return CreateParallelValidator(context);
1212  }
1213 
1214  bool Int64(Context& context, int64_t i) const
1215  {
1216  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i);
1217  if(!CheckInt(context, i))
1218  return false;
1219  return CreateParallelValidator(context);
1220  }
1221 
1222  bool Uint64(Context& context, uint64_t u) const
1223  {
1224  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u);
1225  if(!CheckUint(context, u))
1226  return false;
1227  return CreateParallelValidator(context);
1228  }
1229 
1230  bool Double(Context& context, double d) const
1231  {
1232  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d);
1233  if(!(type_ & (1 << kNumberSchemaType)))
1234  {
1235  DisallowedType(context, GetNumberString());
1237  }
1238 
1239  if(!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1240  return false;
1241 
1242  if(!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1243  return false;
1244 
1245  if(!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1246  return false;
1247 
1248  return CreateParallelValidator(context);
1249  }
1250 
1251  bool String(Context& context, const Ch* str, SizeType length, bool) const
1252  {
1253  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str);
1254  if(!(type_ & (1 << kStringSchemaType)))
1255  {
1256  DisallowedType(context, GetStringString());
1258  }
1259 
1260  if(minLength_ != 0 || maxLength_ != SizeType(~0))
1261  {
1262  SizeType count;
1263  if(internal::CountStringCodePoint<EncodingType>(str, length, &count))
1264  {
1265  if(count < minLength_)
1266  {
1267  context.error_handler.TooShort(str, length, minLength_);
1269  }
1270  if(count > maxLength_)
1271  {
1272  context.error_handler.TooLong(str, length, maxLength_);
1274  }
1275  }
1276  }
1277 
1278  if(pattern_ && !IsPatternMatch(pattern_, str, length))
1279  {
1280  context.error_handler.DoesNotMatch(str, length);
1282  }
1283 
1284  return CreateParallelValidator(context);
1285  }
1286 
1287  bool StartObject(Context& context) const
1288  {
1289  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject");
1290  if(!(type_ & (1 << kObjectSchemaType)))
1291  {
1292  DisallowedType(context, GetObjectString());
1294  }
1295 
1297  {
1298  context.propertyExist =
1299  static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
1300  std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
1301  }
1302 
1303  if(patternProperties_)
1304  { // pre-allocate schema array
1305  SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
1306  context.patternPropertiesSchemas = static_cast<const SchemaType**>(
1307  context.factory.MallocState(sizeof(const SchemaType*) * count));
1308  context.patternPropertiesSchemaCount = 0;
1309  std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
1310  }
1311 
1312  return CreateParallelValidator(context);
1313  }
1314 
1315  bool Key(Context& context, const Ch* str, SizeType len, bool) const
1316  {
1317  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
1318 
1319  if(patternProperties_)
1320  {
1321  context.patternPropertiesSchemaCount = 0;
1322  for(SizeType i = 0; i < patternPropertyCount_; i++)
1323  if(patternProperties_[i].pattern &&
1324  IsPatternMatch(patternProperties_[i].pattern, str, len))
1325  {
1328  context.valueSchema = typeless_;
1329  }
1330  }
1331 
1332  SizeType index = 0;
1333  if(FindPropertyIndex(ValueType(str, len).Move(), &index))
1334  {
1335  if(context.patternPropertiesSchemaCount > 0)
1336  {
1338  properties_[index].schema;
1339  context.valueSchema = typeless_;
1341  }
1342  else
1343  context.valueSchema = properties_[index].schema;
1344 
1345  if(context.propertyExist)
1346  context.propertyExist[index] = true;
1347 
1348  return true;
1349  }
1350 
1352  {
1353  if(context.patternPropertiesSchemaCount > 0)
1354  {
1357  context.valueSchema = typeless_;
1358  context.valuePatternValidatorType =
1360  }
1361  else
1363  return true;
1364  }
1365  else if(additionalProperties_)
1366  {
1367  context.valueSchema = typeless_;
1368  return true;
1369  }
1370 
1371  if(context.patternPropertiesSchemaCount == 0)
1372  { // patternProperties are not additional properties
1373  // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports
1374  // spurious type error
1375  context.valueSchema = typeless_;
1376  context.error_handler.DisallowedProperty(str, len);
1378  }
1379 
1380  return true;
1381  }
1382 
1383  bool EndObject(Context& context, SizeType memberCount) const
1384  {
1385  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
1386  if(hasRequired_)
1387  {
1389  for(SizeType index = 0; index < propertyCount_; index++)
1390  if(properties_[index].required && !context.propertyExist[index])
1391  if(properties_[index].schema->defaultValueLength_ == 0)
1392  context.error_handler.AddMissingProperty(properties_[index].name);
1393  if(context.error_handler.EndMissingProperties())
1395  }
1396 
1397  if(memberCount < minProperties_)
1398  {
1399  context.error_handler.TooFewProperties(memberCount, minProperties_);
1401  }
1402 
1403  if(memberCount > maxProperties_)
1404  {
1405  context.error_handler.TooManyProperties(memberCount, maxProperties_);
1407  }
1408 
1409  if(hasDependencies_)
1410  {
1412  for(SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
1413  {
1414  const Property& source = properties_[sourceIndex];
1415  if(context.propertyExist[sourceIndex])
1416  {
1417  if(source.dependencies)
1418  {
1420  for(SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1421  if(source.dependencies[targetIndex] &&
1422  !context.propertyExist[targetIndex])
1424  properties_[targetIndex].name);
1426  }
1427  else if(source.dependenciesSchema)
1428  {
1429  ISchemaValidator* dependenciesValidator =
1430  context.validators[source.dependenciesValidatorIndex];
1431  if(!dependenciesValidator->IsValid())
1433  dependenciesValidator);
1434  }
1435  }
1436  }
1437  if(context.error_handler.EndDependencyErrors())
1439  }
1440 
1441  return true;
1442  }
1443 
1444  bool StartArray(Context& context) const
1445  {
1446  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
1447  context.arrayElementIndex = 0;
1448  context.inArray = true; // Ensure we note that we are in an array
1449 
1450  if(!(type_ & (1 << kArraySchemaType)))
1451  {
1452  DisallowedType(context, GetArrayString());
1454  }
1455 
1456  return CreateParallelValidator(context);
1457  }
1458 
1459  bool EndArray(Context& context, SizeType elementCount) const
1460  {
1461  RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray");
1462  context.inArray = false;
1463 
1464  if(elementCount < minItems_)
1465  {
1466  context.error_handler.TooFewItems(elementCount, minItems_);
1468  }
1469 
1470  if(elementCount > maxItems_)
1471  {
1472  context.error_handler.TooManyItems(elementCount, maxItems_);
1474  }
1475 
1476  return true;
1477  }
1478 
1479  static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)
1480  {
1481  switch(validateErrorCode)
1482  {
1483  case kValidateErrorMultipleOf: return GetMultipleOfString();
1484  case kValidateErrorMaximum: return GetMaximumString();
1485  case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
1486  case kValidateErrorMinimum: return GetMinimumString();
1487  case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
1488 
1489  case kValidateErrorMaxLength: return GetMaxLengthString();
1490  case kValidateErrorMinLength: return GetMinLengthString();
1491  case kValidateErrorPattern: return GetPatternString();
1492 
1493  case kValidateErrorMaxItems: return GetMaxItemsString();
1494  case kValidateErrorMinItems: return GetMinItemsString();
1495  case kValidateErrorUniqueItems: return GetUniqueItemsString();
1496  case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
1497 
1498  case kValidateErrorMaxProperties: return GetMaxPropertiesString();
1499  case kValidateErrorMinProperties: return GetMinPropertiesString();
1500  case kValidateErrorRequired: return GetRequiredString();
1501  case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
1502  case kValidateErrorPatternProperties: return GetPatternPropertiesString();
1503  case kValidateErrorDependencies: return GetDependenciesString();
1504 
1505  case kValidateErrorEnum: return GetEnumString();
1506  case kValidateErrorType: return GetTypeString();
1507 
1508  case kValidateErrorOneOf: return GetOneOfString();
1509  case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
1510  case kValidateErrorAllOf: return GetAllOfString();
1511  case kValidateErrorAnyOf: return GetAnyOfString();
1512  case kValidateErrorNot: return GetNotString();
1513 
1514  case kValidateErrorReadOnly: return GetReadOnlyString();
1515  case kValidateErrorWriteOnly: return GetWriteOnlyString();
1516 
1517  default: return GetNullString();
1518  }
1519  }
1520 
1521  // Generate functions for string literal according to Ch
1522 #define RAPIDJSON_STRING_(name, ...) \
1523  static const ValueType& Get##name##String() \
1524  { \
1525  static const Ch s[] = {__VA_ARGS__, '\0'}; \
1526  static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
1527  return v; \
1528  }
1529 
1530  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1531  RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1532  RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1533  RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1534  RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1535  RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1536  RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1537  RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1538  RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1539  RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1540  RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1541  RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1542  RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1543  RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1544  RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1545  RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1546  RAPIDJSON_STRING_(PatternProperties,
1547  'p',
1548  'a',
1549  't',
1550  't',
1551  'e',
1552  'r',
1553  'n',
1554  'P',
1555  'r',
1556  'o',
1557  'p',
1558  'e',
1559  'r',
1560  't',
1561  'i',
1562  'e',
1563  's')
1564  RAPIDJSON_STRING_(AdditionalProperties,
1565  'a',
1566  'd',
1567  'd',
1568  'i',
1569  't',
1570  'i',
1571  'o',
1572  'n',
1573  'a',
1574  'l',
1575  'P',
1576  'r',
1577  'o',
1578  'p',
1579  'e',
1580  'r',
1581  't',
1582  'i',
1583  'e',
1584  's')
1586  MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1588  MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1589  RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1590  RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1591  RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1593  AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1594  RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1595  RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1596  RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1597  RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1598  RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1599  RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1600  RAPIDJSON_STRING_(ExclusiveMinimum,
1601  'e',
1602  'x',
1603  'c',
1604  'l',
1605  'u',
1606  's',
1607  'i',
1608  'v',
1609  'e',
1610  'M',
1611  'i',
1612  'n',
1613  'i',
1614  'm',
1615  'u',
1616  'm')
1617  RAPIDJSON_STRING_(ExclusiveMaximum,
1618  'e',
1619  'x',
1620  'c',
1621  'l',
1622  'u',
1623  's',
1624  'i',
1625  'v',
1626  'e',
1627  'M',
1628  'a',
1629  'x',
1630  'i',
1631  'm',
1632  'u',
1633  'm')
1634  RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1635  RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1636  RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
1637  RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
1638  RAPIDJSON_STRING_(Id, 'i', 'd')
1639  RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
1640  RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
1641  RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
1642  RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
1643  RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
1644 
1645 #undef RAPIDJSON_STRING_
1646 
1647  private:
1648  enum SchemaValueType
1649  {
1650  kNullSchemaType,
1651  kBooleanSchemaType,
1652  kObjectSchemaType,
1653  kArraySchemaType,
1654  kStringSchemaType,
1655  kNumberSchemaType,
1656  kIntegerSchemaType,
1657  kTotalSchemaType
1658  };
1659 
1660 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1662 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1663  typedef std::basic_regex<Ch> RegexType;
1664 #else
1665  typedef char RegexType;
1666 #endif
1667 
1669  {
1673  SizeType begin; // begin index of context.validators
1675  };
1676 
1677  template <typename V1, typename V2>
1678  void AddUniqueElement(V1& a, const V2& v)
1679  {
1680  for(typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1681  if(*itr == v)
1682  return;
1683  V1 c(v, *allocator_);
1684  a.PushBack(c, *allocator_);
1685  }
1686 
1687  static const ValueType* GetMember(const ValueType& value, const ValueType& name)
1688  {
1689  typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1690  return itr != value.MemberEnd() ? &(itr->value) : 0;
1691  }
1692 
1693  static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name)
1694  {
1695  if(const ValueType* v = GetMember(value, name))
1696  if(v->IsBool())
1697  out = v->GetBool();
1698  }
1699 
1700  static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name)
1701  {
1702  if(const ValueType* v = GetMember(value, name))
1703  if(v->IsUint64() && v->GetUint64() <= SizeType(~0))
1704  out = static_cast<SizeType>(v->GetUint64());
1705  }
1706 
1708  SchemaDocumentType& schemaDocument,
1709  const PointerType& p,
1710  const ValueType& value,
1711  const ValueType& name,
1712  const ValueType& document)
1713  {
1714  if(const ValueType* v = GetMember(value, name))
1715  {
1716  if(v->IsArray() && v->Size() > 0)
1717  {
1718  PointerType q = p.Append(name, allocator_);
1719  out.count = v->Size();
1720  out.schemas = static_cast<const Schema**>(
1721  allocator_->Malloc(out.count * sizeof(const Schema*)));
1722  memset(out.schemas, 0, sizeof(Schema*) * out.count);
1723  for(SizeType i = 0; i < out.count; i++)
1724  schemaDocument.CreateSchema(
1725  &out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1726  out.begin = validatorCount_;
1727  validatorCount_ += out.count;
1728  }
1729  }
1730  }
1731 
1732 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1733  template <typename ValueType>
1734  RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p)
1735  {
1736  if(value.IsString())
1737  {
1738  RegexType* r =
1739  new(allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1740  if(!r->IsValid())
1741  {
1742  sd->SchemaErrorValue(
1743  kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1744  r->~RegexType();
1746  r = 0;
1747  }
1748  return r;
1749  }
1750  return 0;
1751  }
1752 
1753  static bool IsPatternMatch(const RegexType* pattern, const Ch* str, SizeType)
1754  {
1755  GenericRegexSearch<RegexType> rs(*pattern);
1756  return rs.Search(str);
1757  }
1758 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1759  template <typename ValueType>
1760  RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p)
1761  {
1762  if(value.IsString())
1763  {
1764  RegexType* r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1765  try
1766  {
1767  return new(r) RegexType(value.GetString(),
1768  std::size_t(value.GetStringLength()),
1769  std::regex_constants::ECMAScript);
1770  }
1771  catch(const std::regex_error& e)
1772  {
1773  sd->SchemaErrorValue(
1774  kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1776  }
1777  }
1778  return 0;
1779  }
1780 
1781  static bool IsPatternMatch(const RegexType* pattern, const Ch* str, SizeType length)
1782  {
1783  std::match_results<const Ch*> r;
1784  return std::regex_search(str, str + length, r, *pattern);
1785  }
1786 #else
1787  template <typename ValueType>
1789  {
1790  return 0;
1791  }
1792 
1793  static bool IsPatternMatch(const RegexType*, const Ch*, SizeType) { return true; }
1794 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1795 
1796  void AddType(const ValueType& type)
1797  {
1798  if(type == GetNullString())
1799  type_ |= 1 << kNullSchemaType;
1800  else if(type == GetBooleanString())
1801  type_ |= 1 << kBooleanSchemaType;
1802  else if(type == GetObjectString())
1803  type_ |= 1 << kObjectSchemaType;
1804  else if(type == GetArrayString())
1805  type_ |= 1 << kArraySchemaType;
1806  else if(type == GetStringString())
1807  type_ |= 1 << kStringSchemaType;
1808  else if(type == GetIntegerString())
1809  type_ |= 1 << kIntegerSchemaType;
1810  else if(type == GetNumberString())
1811  type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1812  }
1813 
1814  // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if
1815  // required. Also creates a hasher for enums and array uniqueness, if required. Also a useful
1816  // place to add type-independent error checks.
1817  bool CreateParallelValidator(Context& context) const
1818  {
1819  if(enum_ || context.arrayUniqueness)
1820  context.hasher = context.factory.CreateHasher();
1821 
1822  if(validatorCount_)
1823  {
1824  RAPIDJSON_ASSERT(context.validators == 0);
1825  context.validators = static_cast<ISchemaValidator**>(
1826  context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1827  std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_);
1828  context.validatorCount = validatorCount_;
1829 
1830  // Always return after first failure for these sub-validators
1831  if(allOf_.schemas)
1832  CreateSchemaValidators(context, allOf_, false);
1833 
1834  if(anyOf_.schemas)
1835  CreateSchemaValidators(context, anyOf_, false);
1836 
1837  if(oneOf_.schemas)
1838  CreateSchemaValidators(context, oneOf_, false);
1839 
1840  if(not_)
1841  context.validators[notValidatorIndex_] =
1842  context.factory.CreateSchemaValidator(*not_, false);
1843 
1845  {
1846  for(SizeType i = 0; i < propertyCount_; i++)
1847  if(properties_[i].dependenciesSchema)
1850  *properties_[i].dependenciesSchema, false);
1851  }
1852  }
1853 
1854  // Add any other type-independent checks here
1855  if(readOnly_ && (context.flags & kValidateWriteFlag))
1856  {
1859  }
1860  if(writeOnly_ && (context.flags & kValidateReadFlag))
1861  {
1864  }
1865 
1866  return true;
1867  }
1868 
1870  const SchemaArray& schemas,
1871  const bool inheritContinueOnErrors) const
1872  {
1873  for(SizeType i = 0; i < schemas.count; i++)
1874  context.validators[schemas.begin + i] =
1875  context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1876  }
1877 
1878  // O(n)
1879  bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const
1880  {
1881  SizeType len = name.GetStringLength();
1882  const Ch* str = name.GetString();
1883  for(SizeType index = 0; index < propertyCount_; index++)
1884  if(properties_[index].name.GetStringLength() == len &&
1885  (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1886  {
1887  *outIndex = index;
1888  return true;
1889  }
1890  return false;
1891  }
1892 
1893  bool CheckBool(Context& context, bool) const
1894  {
1895  if(!(type_ & (1 << kBooleanSchemaType)))
1896  {
1897  DisallowedType(context, GetBooleanString());
1899  }
1900  return true;
1901  }
1902 
1903  bool CheckInt(Context& context, int64_t i) const
1904  {
1905  if(!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1906  {
1907  DisallowedType(context, GetIntegerString());
1909  }
1910 
1911  if(!minimum_.IsNull())
1912  {
1913  if(minimum_.IsInt64())
1914  {
1915  if(exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1916  {
1920  }
1921  }
1922  else if(minimum_.IsUint64())
1923  {
1928  : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1929  }
1930  else if(!CheckDoubleMinimum(context, static_cast<double>(i)))
1931  return false;
1932  }
1933 
1934  if(!maximum_.IsNull())
1935  {
1936  if(maximum_.IsInt64())
1937  {
1938  if(exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1939  {
1943  }
1944  }
1945  else if(maximum_.IsUint64()) {}
1946  /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1947  else if(!CheckDoubleMaximum(context, static_cast<double>(i)))
1948  return false;
1949  }
1950 
1951  if(!multipleOf_.IsNull())
1952  {
1953  if(multipleOf_.IsUint64())
1954  {
1955  if(static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1956  {
1959  }
1960  }
1961  else if(!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1962  return false;
1963  }
1964 
1965  return true;
1966  }
1967 
1968  bool CheckUint(Context& context, uint64_t i) const
1969  {
1970  if(!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1971  {
1972  DisallowedType(context, GetIntegerString());
1974  }
1975 
1976  if(!minimum_.IsNull())
1977  {
1978  if(minimum_.IsUint64())
1979  {
1980  if(exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1981  {
1985  }
1986  }
1987  else if(minimum_.IsInt64())
1988  /* do nothing */; // i >= 0 > minimum.Getint64()
1989  else if(!CheckDoubleMinimum(context, static_cast<double>(i)))
1990  return false;
1991  }
1992 
1993  if(!maximum_.IsNull())
1994  {
1995  if(maximum_.IsUint64())
1996  {
1997  if(exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1998  {
2002  }
2003  }
2004  else if(maximum_.IsInt64())
2005  {
2009  : kValidateErrorMaximum); // i >= 0 > maximum_
2010  }
2011  else if(!CheckDoubleMaximum(context, static_cast<double>(i)))
2012  return false;
2013  }
2014 
2015  if(!multipleOf_.IsNull())
2016  {
2017  if(multipleOf_.IsUint64())
2018  {
2019  if(i % multipleOf_.GetUint64() != 0)
2020  {
2023  }
2024  }
2025  else if(!CheckDoubleMultipleOf(context, static_cast<double>(i)))
2026  return false;
2027  }
2028 
2029  return true;
2030  }
2031 
2032  bool CheckDoubleMinimum(Context& context, double d) const
2033  {
2034  if(exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
2035  {
2039  }
2040  return true;
2041  }
2042 
2043  bool CheckDoubleMaximum(Context& context, double d) const
2044  {
2045  if(exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
2046  {
2050  }
2051  return true;
2052  }
2053 
2054  bool CheckDoubleMultipleOf(Context& context, double d) const
2055  {
2056  double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
2057  double q = a / b;
2058  double qRounded = std::floor(q + 0.5);
2059  double scaledEpsilon = (q + qRounded) * std::numeric_limits<double>::epsilon();
2060  double difference = std::abs(qRounded - q);
2061  bool isMultiple =
2062  difference <= scaledEpsilon || difference < (std::numeric_limits<double>::min)();
2063  if(!isMultiple)
2064  {
2067  }
2068  return true;
2069  }
2070 
2071  void DisallowedType(Context& context, const ValueType& actualType) const
2072  {
2073  ErrorHandler& eh = context.error_handler;
2074  eh.StartDisallowedType();
2075 
2076  if(type_ & (1 << kNullSchemaType))
2077  eh.AddExpectedType(GetNullString());
2078  if(type_ & (1 << kBooleanSchemaType))
2079  eh.AddExpectedType(GetBooleanString());
2080  if(type_ & (1 << kObjectSchemaType))
2081  eh.AddExpectedType(GetObjectString());
2082  if(type_ & (1 << kArraySchemaType))
2083  eh.AddExpectedType(GetArrayString());
2084  if(type_ & (1 << kStringSchemaType))
2085  eh.AddExpectedType(GetStringString());
2086 
2087  if(type_ & (1 << kNumberSchemaType))
2088  eh.AddExpectedType(GetNumberString());
2089  else if(type_ & (1 << kIntegerSchemaType))
2090  eh.AddExpectedType(GetIntegerString());
2091 
2092  eh.EndDisallowedType(actualType);
2093  }
2094 
2095  struct Property
2096  {
2098  : schema(),
2101  dependencies(),
2102  required(false)
2103  {
2104  }
2111  bool required;
2112  };
2113 
2115  {
2118  {
2119  if(pattern)
2120  {
2121  pattern->~RegexType();
2123  }
2124  }
2127  };
2128 
2141  unsigned type_; // bitmask of kSchemaType
2144 
2156 
2165 
2169 
2175 
2177 
2181 };
2182 
2183 template <typename Stack, typename Ch>
2185 {
2186  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index)
2187  {
2188  *documentStack.template Push<Ch>() = '/';
2189  char buffer[21];
2190  size_t length = static_cast<size_t>(
2191  (sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
2192  for(size_t i = 0; i < length; i++)
2193  *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
2194  }
2195 };
2196 
2197 // Partial specialized version for char to prevent buffer copying.
2198 template <typename Stack>
2199 struct TokenHelper<Stack, char>
2200 {
2201  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index)
2202  {
2203  RAPIDJSON_IF_CONSTEXPR(sizeof(SizeType) == 4)
2204  {
2205  char* buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
2206  *buffer++ = '/';
2207  const char* end = internal::u32toa(index, buffer);
2208  documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
2209  }
2210  else
2211  {
2212  char* buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
2213  *buffer++ = '/';
2214  const char* end = internal::u64toa(index, buffer);
2215  documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
2216  }
2217  }
2218 };
2219 
2220 } // namespace internal
2221 
2223 // IGenericRemoteSchemaDocumentProvider
2224 
2225 template <typename SchemaDocumentType>
2227 {
2228  public:
2229  typedef typename SchemaDocumentType::Ch Ch;
2230  typedef typename SchemaDocumentType::ValueType ValueType;
2231  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
2232 
2234  virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
2235  virtual const SchemaDocumentType*
2237  {
2238  // Default implementation just calls through for compatibility
2239  // Following line suppresses unused parameter warning
2240  (void)spec;
2241  // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
2243  }
2244 };
2245 
2247 // GenericSchemaDocument
2248 
2250 
2258 template <typename ValueT, typename Allocator = CrtAllocator>
2260 {
2261  public:
2262  typedef ValueT ValueType;
2266  typedef typename ValueType::EncodingType EncodingType;
2267  typedef typename EncodingType::Ch Ch;
2274  template <typename, typename, typename>
2276 
2278 
2290  explicit GenericSchemaDocument(const ValueType& document,
2291  const Ch* uri = 0,
2292  SizeType uriLength = 0,
2293  IRemoteSchemaDocumentProviderType* remoteProvider = 0,
2294  Allocator* allocator = 0,
2295  const PointerType& pointer = PointerType(), // PR #1393
2296  const Specification& spec = Specification(kDraft04))
2297  : remoteProvider_(remoteProvider),
2298  allocator_(allocator),
2299  ownAllocator_(),
2300  root_(),
2301  typeless_(),
2302  schemaMap_(allocator, kInitialSchemaMapSize),
2303  schemaRef_(allocator, kInitialSchemaRefSize),
2304  spec_(spec),
2305  error_(kObjectType),
2306  currentError_()
2307  {
2308  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
2309  if(!allocator_)
2310  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
2311 
2312  Ch noUri[1] = {0};
2313  uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
2314  docId_ = UriType(uri_, allocator_);
2315 
2316  typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
2317  new(typeless_) SchemaType(this,
2318  PointerType(),
2319  ValueType(kObjectType).Move(),
2320  ValueType(kObjectType).Move(),
2321  allocator_,
2322  docId_);
2323 
2324  // Establish the schema draft or open api version.
2325  // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
2326  SetSchemaSpecification(document);
2327 
2328  // Generate root schema, it will call CreateSchema() to create sub-schemas,
2329  // And call HandleRefSchema() if there are $ref.
2330  // PR #1393 use input pointer if supplied
2331  root_ = typeless_;
2332  if(pointer.GetTokenCount() == 0)
2333  {
2334  CreateSchemaRecursive(&root_, pointer, document, document, docId_);
2335  }
2336  else if(const ValueType* v = pointer.Get(document))
2337  {
2338  CreateSchema(&root_, pointer, *v, document, docId_);
2339  }
2340  else
2341  {
2343  pointer.StringifyUriFragment(sb);
2345  PointerType(),
2346  sb.GetString(),
2347  static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
2348  }
2349 
2350  RAPIDJSON_ASSERT(root_ != 0);
2351 
2352  schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
2353  }
2354 
2355 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
2357  GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT
2358  : remoteProvider_(rhs.remoteProvider_),
2359  allocator_(rhs.allocator_),
2360  ownAllocator_(rhs.ownAllocator_),
2361  root_(rhs.root_),
2362  typeless_(rhs.typeless_),
2363  schemaMap_(std::move(rhs.schemaMap_)),
2364  schemaRef_(std::move(rhs.schemaRef_)),
2365  uri_(std::move(rhs.uri_)),
2366  docId_(std::move(rhs.docId_)),
2367  spec_(rhs.spec_),
2368  error_(std::move(rhs.error_)),
2369  currentError_(std::move(rhs.currentError_))
2370  {
2371  rhs.remoteProvider_ = 0;
2372  rhs.allocator_ = 0;
2373  rhs.ownAllocator_ = 0;
2374  rhs.typeless_ = 0;
2375  }
2376 #endif
2377 
2380  {
2381  while(!schemaMap_.Empty())
2382  schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
2383 
2384  if(typeless_)
2385  {
2386  typeless_->~SchemaType();
2387  Allocator::Free(typeless_);
2388  }
2389 
2390  // these may contain some allocator data so clear before deleting ownAllocator_
2391  uri_.SetNull();
2392  error_.SetNull();
2393  currentError_.SetNull();
2394 
2395  RAPIDJSON_DELETE(ownAllocator_);
2396  }
2397 
2398  const GValue& GetURI() const { return uri_; }
2399 
2400  const Specification& GetSpecification() const { return spec_; }
2401  bool IsSupportedSpecification() const { return spec_.IsSupported(); }
2402 
2404  // Returns kDraftNone if document is silent
2405  static const Specification GetSpecification(const ValueType& document)
2406  {
2407  SchemaDraft draft = GetSchemaDraft(document);
2408  if(draft != kDraftNone)
2409  return Specification(draft);
2410  else
2411  {
2412  OpenApiVersion oapi = GetOpenApiVersion(document);
2413  if(oapi != kVersionNone)
2414  return Specification(oapi);
2415  }
2416  return Specification(kDraftNone);
2417  }
2418 
2420  const SchemaType& GetRoot() const { return *root_; }
2421 
2423  GValue& GetError() { return error_; }
2424  const GValue& GetError() const { return error_; }
2425 
2426  static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode)
2427  {
2428  switch(schemaErrorCode)
2429  {
2430  case kSchemaErrorStartUnknown: return GetStartUnknownString();
2431  case kSchemaErrorRefPlainName: return GetRefPlainNameString();
2432  case kSchemaErrorRefInvalid: return GetRefInvalidString();
2433  case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString();
2434  case kSchemaErrorRefUnknown: return GetRefUnknownString();
2435  case kSchemaErrorRefCyclical: return GetRefCyclicalString();
2436  case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
2437  case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
2438  case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
2439  case kSchemaErrorSpecUnknown: return GetSpecUnknownString();
2440  case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString();
2441  case kSchemaErrorSpecIllegal: return GetSpecIllegalString();
2442  case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString();
2443  default: return GetNullString();
2444  }
2445  }
2446 
2448  void SchemaError(const SchemaErrorCode code, const PointerType& location)
2449  {
2450  currentError_ = GValue(kObjectType);
2451  AddCurrentError(code, location);
2452  }
2453 
2456  const PointerType& location,
2457  const Ch* value,
2458  SizeType length)
2459  {
2460  currentError_ = GValue(kObjectType);
2461  currentError_.AddMember(
2462  GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
2463  AddCurrentError(code, location);
2464  }
2465 
2468  const PointerType& location,
2469  const Ch* value,
2470  SizeType length,
2471  const PointerType& pointer)
2472  {
2473  currentError_ = GValue(kObjectType);
2474  currentError_.AddMember(
2475  GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
2476  currentError_.AddMember(GetOffsetString(),
2477  static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)),
2478  *allocator_);
2479  AddCurrentError(code, location);
2480  }
2481 
2482  private:
2486  GenericSchemaDocument& operator=(const GenericSchemaDocument&);
2487 
2488  typedef const PointerType* SchemaRefPtr; // PR #1393
2489 
2490  struct SchemaEntry
2491  {
2492  SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator)
2493  : pointer(p, allocator), schema(s), owned(o)
2494  {
2495  }
2496  ~SchemaEntry()
2497  {
2498  if(owned)
2499  {
2500  schema->~SchemaType();
2501  Allocator::Free(schema);
2502  }
2503  }
2505  SchemaType* schema;
2506  bool owned;
2507  };
2508 
2509  void AddErrorInstanceLocation(GValue& result, const PointerType& location)
2510  {
2512  location.StringifyUriFragment(sb);
2513  GValue instanceRef(
2514  sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
2515  result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2516  }
2517 
2518  void AddError(GValue& keyword, GValue& error)
2519  {
2520  typename GValue::MemberIterator member = error_.FindMember(keyword);
2521  if(member == error_.MemberEnd())
2522  error_.AddMember(keyword, error, *allocator_);
2523  else
2524  {
2525  if(member->value.IsObject())
2526  {
2527  GValue errors(kArrayType);
2528  errors.PushBack(member->value, *allocator_);
2529  member->value = errors;
2530  }
2531  member->value.PushBack(error, *allocator_);
2532  }
2533  }
2534 
2535  void AddCurrentError(const SchemaErrorCode code, const PointerType& location)
2536  {
2537  RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2538  currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2539  AddErrorInstanceLocation(currentError_, location);
2540  AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2541  }
2542 
2543 #define RAPIDJSON_STRING_(name, ...) \
2544  static const StringRefType& Get##name##String() \
2545  { \
2546  static const Ch s[] = {__VA_ARGS__, '\0'}; \
2547  static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2548  return v; \
2549  }
2550 
2551  RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2552  RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2553  RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
2554  RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
2555 
2556  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
2557  RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2558  RAPIDJSON_STRING_(
2559  SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
2560  RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
2561  RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2562  RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
2563  RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2564  RAPIDJSON_STRING_(RefPointerInvalid,
2565  'R',
2566  'e',
2567  'f',
2568  'P',
2569  'o',
2570  'i',
2571  'n',
2572  't',
2573  'e',
2574  'r',
2575  'I',
2576  'n',
2577  'v',
2578  'a',
2579  'l',
2580  'i',
2581  'd')
2582  RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2583  RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
2584  RAPIDJSON_STRING_(RefNoRemoteProvider,
2585  'R',
2586  'e',
2587  'f',
2588  'N',
2589  'o',
2590  'R',
2591  'e',
2592  'm',
2593  'o',
2594  't',
2595  'e',
2596  'P',
2597  'r',
2598  'o',
2599  'v',
2600  'i',
2601  'd',
2602  'e',
2603  'r')
2604  RAPIDJSON_STRING_(RefNoRemoteSchema,
2605  'R',
2606  'e',
2607  'f',
2608  'N',
2609  'o',
2610  'R',
2611  'e',
2612  'm',
2613  'o',
2614  't',
2615  'e',
2616  'S',
2617  'c',
2618  'h',
2619  'e',
2620  'm',
2621  'a')
2622  RAPIDJSON_STRING_(ReadOnlyAndWriteOnly,
2623  'R',
2624  'e',
2625  'a',
2626  'd',
2627  'O',
2628  'n',
2629  'l',
2630  'y',
2631  'A',
2632  'n',
2633  'd',
2634  'W',
2635  'r',
2636  'i',
2637  't',
2638  'e',
2639  'O',
2640  'n',
2641  'l',
2642  'y')
2643  RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2644 
2645 #undef RAPIDJSON_STRING_
2646 
2647  // Static method to get schema draft of any schema document
2648  static SchemaDraft GetSchemaDraft(const ValueType& document)
2649  {
2650  static const Ch kDraft03String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2651  'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2652  'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2653  '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2654  static const Ch kDraft04String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2655  'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2656  'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2657  '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2658  static const Ch kDraft05String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2659  'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2660  'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2661  '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2662  static const Ch kDraft06String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2663  'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2664  'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2665  '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2666  static const Ch kDraft07String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2667  'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2668  'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2669  '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2670  static const Ch kDraft2019_09String[] = {
2671  'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c',
2672  'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/',
2673  '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0'};
2674  static const Ch kDraft2020_12String[] = {
2675  'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c',
2676  'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/',
2677  '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0'};
2678 
2679  if(!document.IsObject())
2680  {
2681  return kDraftNone;
2682  }
2683 
2684  // Get the schema draft from the $schema keyword at the supplied location
2685  typename ValueType::ConstMemberIterator itr =
2686  document.FindMember(SchemaType::GetSchemaString());
2687  if(itr != document.MemberEnd())
2688  {
2689  if(!itr->value.IsString())
2690  return kDraftUnknown;
2691  const UriType draftUri(itr->value);
2692  // Check base uri for match
2693  if(draftUri.Match(UriType(kDraft04String), false))
2694  return kDraft04;
2695  if(draftUri.Match(UriType(kDraft05String), false))
2696  return kDraft05;
2697  if(draftUri.Match(UriType(kDraft06String), false))
2698  return kDraft06;
2699  if(draftUri.Match(UriType(kDraft07String), false))
2700  return kDraft07;
2701  if(draftUri.Match(UriType(kDraft03String), false))
2702  return kDraft03;
2703  if(draftUri.Match(UriType(kDraft2019_09String), false))
2704  return kDraft2019_09;
2705  if(draftUri.Match(UriType(kDraft2020_12String), false))
2706  return kDraft2020_12;
2707  return kDraftUnknown;
2708  }
2709  // $schema not found
2710  return kDraftNone;
2711  }
2712 
2713  // Get open api version of any schema document
2714  static OpenApiVersion GetOpenApiVersion(const ValueType& document)
2715  {
2716  static const Ch kVersion20String[] = {'2', '.', '0', '\0'};
2717  static const Ch kVersion30String[] = {'3', '.', '0', '.', '\0'}; // ignore patch level
2718  static const Ch kVersion31String[] = {'3', '.', '1', '.', '\0'}; // ignore patch level
2719  static SizeType len = internal::StrLen<Ch>(kVersion30String);
2720 
2721  if(!document.IsObject())
2722  {
2723  return kVersionNone;
2724  }
2725 
2726  // Get the open api version from the swagger / openapi keyword at the supplied location
2727  typename ValueType::ConstMemberIterator itr =
2728  document.FindMember(SchemaType::GetSwaggerString());
2729  if(itr == document.MemberEnd())
2730  itr = document.FindMember(SchemaType::GetOpenApiString());
2731  if(itr != document.MemberEnd())
2732  {
2733  if(!itr->value.IsString())
2734  return kVersionUnknown;
2735  const ValueType kVersion20Value(kVersion20String);
2736  if(kVersion20Value == itr->value)
2737  return kVersion20; // must match 2.0 exactly
2738  const ValueType kVersion30Value(kVersion30String);
2739  if(itr->value.GetStringLength() > len &&
2740  kVersion30Value == ValueType(itr->value.GetString(), len))
2741  return kVersion30; // must match 3.0.x
2742  const ValueType kVersion31Value(kVersion31String);
2743  if(itr->value.GetStringLength() > len &&
2744  kVersion31Value == ValueType(itr->value.GetString(), len))
2745  return kVersion31; // must match 3.1.x
2746  return kVersionUnknown;
2747  }
2748  // swagger or openapi not found
2749  return kVersionNone;
2750  }
2751 
2752  // Get the draft of the schema or the open api version (which implies the draft).
2753  // Report an error if schema draft or open api version not supported or not recognized, or both
2754  // in document, and carry on.
2755  void SetSchemaSpecification(const ValueType& document)
2756  {
2757  // Look for '$schema', 'swagger' or 'openapi' keyword at document root
2758  SchemaDraft docDraft = GetSchemaDraft(document);
2759  OpenApiVersion docOapi = GetOpenApiVersion(document);
2760  // Error if both in document
2761  if(docDraft != kDraftNone && docOapi != kVersionNone)
2763  // Use document draft or open api version if present or use spec from constructor
2764  if(docDraft != kDraftNone)
2765  spec_ = Specification(docDraft);
2766  else if(docOapi != kVersionNone)
2767  spec_ = Specification(docOapi);
2768  // Error if draft or version unknown
2769  if(spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2771  else if(!spec_.IsSupported())
2773  }
2774 
2775  // Changed by PR #1393
2776  void CreateSchemaRecursive(const SchemaType** schema,
2777  const PointerType& pointer,
2778  const ValueType& v,
2779  const ValueType& document,
2780  const UriType& id)
2781  {
2782  if(v.GetType() == kObjectType)
2783  {
2784  UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
2785 
2786  for(typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();
2787  ++itr)
2788  CreateSchemaRecursive(
2789  0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2790  }
2791  else if(v.GetType() == kArrayType)
2792  for(SizeType i = 0; i < v.Size(); i++)
2793  CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
2794  }
2795 
2796  // Changed by PR #1393
2797  const UriType& CreateSchema(const SchemaType** schema,
2798  const PointerType& pointer,
2799  const ValueType& v,
2800  const ValueType& document,
2801  const UriType& id)
2802  {
2803  RAPIDJSON_ASSERT(pointer.IsValid());
2805  pointer.StringifyUriFragment(sb);
2807  Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
2808  if(v.IsObject())
2809  {
2810  if(const SchemaType* sc = GetSchema(pointer))
2811  {
2812  if(schema)
2813  *schema = sc;
2814  AddSchemaRefs(const_cast<SchemaType*>(sc));
2815  }
2816  else if(!HandleRefSchema(pointer, schema, v, document, id))
2817  {
2818  // The new schema constructor adds itself and its $ref(s) to schemaMap_
2819  SchemaType* s = new(allocator_->Malloc(sizeof(SchemaType)))
2820  SchemaType(this, pointer, v, document, allocator_, id);
2821  if(schema)
2822  *schema = s;
2823  return s->GetId();
2824  }
2825  }
2826  else
2827  {
2828  if(schema)
2829  *schema = typeless_;
2830  AddSchemaRefs(typeless_);
2831  }
2832  return id;
2833  }
2834 
2835  // Changed by PR #1393
2836  // TODO should this return a UriType& ?
2837  bool HandleRefSchema(const PointerType& source,
2838  const SchemaType** schema,
2839  const ValueType& v,
2840  const ValueType& document,
2841  const UriType& id)
2842  {
2843  typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2844  if(itr == v.MemberEnd())
2845  return false;
2846 
2848  source.StringifyUriFragment(sb);
2850  Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
2851  // Resolve the source pointer to the $ref'ed schema (finally)
2852  new(schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2853 
2854  if(itr->value.IsString())
2855  {
2856  SizeType len = itr->value.GetStringLength();
2857  if(len == 0)
2859  else
2860  {
2861  // First resolve $ref against the in-scope id
2862  UriType scopeId = UriType(id, allocator_);
2863  UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2865  SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
2866  // See if the resolved $ref minus the fragment matches a resolved id in this
2867  // document Search from the root. Returns the subschema in the document and its
2868  // absolute JSON pointer.
2869  PointerType basePointer = PointerType();
2870  const ValueType* base = FindId(document, ref, basePointer, docId_, false);
2871  if(!base)
2872  {
2873  // Remote reference - call the remote document provider
2874  if(!remoteProvider_)
2876  else
2877  {
2878  if(const GenericSchemaDocument* remoteDocument =
2879  remoteProvider_->GetRemoteDocument(ref, spec_))
2880  {
2881  const Ch* s = ref.GetFragString();
2882  len = ref.GetFragStringLength();
2883  if(len <= 1 || s[1] == '/')
2884  {
2885  // JSON pointer fragment, absolute in the remote schema
2886  const PointerType pointer(s, len, allocator_);
2887  if(!pointer.IsValid())
2890  else
2891  {
2892  // Get the subschema
2893  if(const SchemaType* sc = remoteDocument->GetSchema(pointer))
2894  {
2895  if(schema)
2896  *schema = sc;
2897  AddSchemaRefs(const_cast<SchemaType*>(sc));
2898  return true;
2899  }
2900  else
2902  source,
2903  ref.GetString(),
2904  ref.GetStringLength());
2905  }
2906  }
2907  else
2908  // Plain name fragment, not allowed in remote schema
2910  }
2911  else
2913  source,
2914  ref.GetString(),
2915  ref.GetStringLength());
2916  }
2917  }
2918  else
2919  { // Local reference
2920  const Ch* s = ref.GetFragString();
2921  len = ref.GetFragStringLength();
2922  if(len <= 1 || s[1] == '/')
2923  {
2924  // JSON pointer fragment, relative to the resolved URI
2925  const PointerType relPointer(s, len, allocator_);
2926  if(!relPointer.IsValid())
2928  kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
2929  else
2930  {
2931  // Get the subschema
2932  if(const ValueType* pv = relPointer.Get(*base))
2933  {
2934  // Now get the absolute JSON pointer by adding relative to base
2935  PointerType pointer(basePointer, allocator_);
2936  for(SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2937  pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2938  if(IsCyclicRef(pointer))
2940  source,
2941  ref.GetString(),
2942  ref.GetStringLength());
2943  else
2944  {
2945  // Call CreateSchema recursively, but first compute the in-scope
2946  // id for the $ref target as we have jumped there
2947  // TODO: cache pointer <-> id mapping
2948  size_t unresolvedTokenIndex;
2949  scopeId = pointer.GetUri(
2950  document, docId_, &unresolvedTokenIndex, allocator_);
2951  CreateSchema(schema, pointer, *pv, document, scopeId);
2952  return true;
2953  }
2954  }
2955  else
2957  source,
2958  ref.GetString(),
2959  ref.GetStringLength());
2960  }
2961  }
2962  else
2963  {
2964  // Plain name fragment, relative to the resolved URI
2965  // Not supported in open api 2.0 and 3.0
2966  PointerType pointer(allocator_);
2967  if(spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2969  // See if the fragment matches an id in this document.
2970  // Search from the base we just established. Returns the subschema in the
2971  // document and its absolute JSON pointer.
2972  else if(const ValueType* pv = FindId(*base,
2973  ref,
2974  pointer,
2975  UriType(ref.GetBaseString(),
2976  ref.GetBaseStringLength(),
2977  allocator_),
2978  true,
2979  basePointer))
2980  {
2981  if(IsCyclicRef(pointer))
2983  source,
2984  ref.GetString(),
2985  ref.GetStringLength());
2986  else
2987  {
2988  // Call CreateSchema recursively, but first compute the in-scope id
2989  // for the $ref target as we have jumped there
2990  // TODO: cache pointer <-> id mapping
2991  size_t unresolvedTokenIndex;
2992  scopeId = pointer.GetUri(
2993  document, docId_, &unresolvedTokenIndex, allocator_);
2994  CreateSchema(schema, pointer, *pv, document, scopeId);
2995  return true;
2996  }
2997  }
2998  else
3000  source,
3001  ref.GetString(),
3002  ref.GetStringLength());
3003  }
3004  }
3005  }
3006  }
3007 
3008  // Invalid/Unknown $ref
3009  if(schema)
3010  *schema = typeless_;
3011  AddSchemaRefs(typeless_);
3012  return true;
3013  }
3014 
3016  // If full specified use all URI else ignore fragment.
3017  // If found, return a pointer to the subschema and its JSON pointer.
3018  // TODO cache pointer <-> id mapping
3019  ValueType* FindId(const ValueType& doc,
3020  const UriType& finduri,
3021  PointerType& resptr,
3022  const UriType& baseuri,
3023  bool full,
3024  const PointerType& here = PointerType()) const
3025  {
3026  SizeType i = 0;
3027  ValueType* resval = 0;
3028  UriType tempuri = UriType(finduri, allocator_);
3029  UriType localuri = UriType(baseuri, allocator_);
3030  if(doc.GetType() == kObjectType)
3031  {
3032  // Establish the base URI of this object
3033  typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
3034  if(m != doc.MemberEnd() && m->value.GetType() == kStringType)
3035  {
3036  localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
3037  }
3038  // See if it matches
3039  if(localuri.Match(finduri, full))
3040  {
3041  RAPIDJSON_SCHEMA_PRINT(Method,
3042  "GenericSchemaDocument::FindId (match)",
3043  full ? localuri.GetString() : localuri.GetBaseString());
3044  resval = const_cast<ValueType*>(&doc);
3045  resptr = here;
3046  return resval;
3047  }
3048  // No match, continue looking
3049  for(m = doc.MemberBegin(); m != doc.MemberEnd(); ++m)
3050  {
3051  if(m->value.GetType() == kObjectType || m->value.GetType() == kArrayType)
3052  {
3053  resval = FindId(
3054  m->value,
3055  finduri,
3056  resptr,
3057  localuri,
3058  full,
3059  here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
3060  }
3061  if(resval)
3062  break;
3063  }
3064  }
3065  else if(doc.GetType() == kArrayType)
3066  {
3067  // Continue looking
3068  for(typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v)
3069  {
3070  if(v->GetType() == kObjectType || v->GetType() == kArrayType)
3071  {
3072  resval =
3073  FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
3074  }
3075  if(resval)
3076  break;
3077  i++;
3078  }
3079  }
3080  return resval;
3081  }
3082 
3083  // Added by PR #1393
3084  void AddSchemaRefs(SchemaType* schema)
3085  {
3086  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
3087  while(!schemaRef_.Empty())
3088  {
3089  SchemaRefPtr* ref = schemaRef_.template Pop<SchemaRefPtr>(1);
3090  SchemaEntry* entry = schemaMap_.template Push<SchemaEntry>();
3091  new(entry) SchemaEntry(**ref, schema, false, allocator_);
3092  }
3093  }
3094 
3095  // Added by PR #1393
3096  bool IsCyclicRef(const PointerType& pointer) const
3097  {
3098  for(const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>();
3099  ref != schemaRef_.template End<SchemaRefPtr>();
3100  ++ref)
3101  if(pointer == **ref)
3102  return true;
3103  return false;
3104  }
3105 
3106  const SchemaType* GetSchema(const PointerType& pointer) const
3107  {
3108  for(const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
3109  target != schemaMap_.template End<SchemaEntry>();
3110  ++target)
3111  if(pointer == target->pointer)
3112  return target->schema;
3113  return 0;
3114  }
3115 
3116  PointerType GetPointer(const SchemaType* schema) const
3117  {
3118  for(const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
3119  target != schemaMap_.template End<SchemaEntry>();
3120  ++target)
3121  if(schema == target->schema)
3122  return target->pointer;
3123  return PointerType();
3124  }
3125 
3126  const SchemaType* GetTypeless() const { return typeless_; }
3127 
3128  static const size_t kInitialSchemaMapSize = 64;
3129  static const size_t kInitialSchemaRefSize = 64;
3130 
3131  IRemoteSchemaDocumentProviderType* remoteProvider_;
3132  Allocator* allocator_;
3133  Allocator* ownAllocator_;
3134  const SchemaType* root_;
3135  SchemaType* typeless_;
3136  internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
3137  internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
3138  GValue uri_; // Schema document URI
3139  UriType docId_;
3140  Specification spec_;
3141  GValue error_;
3142  GValue currentError_;
3143 };
3144 
3149 
3151 // GenericSchemaValidator
3152 
3154 
3165 template <typename SchemaDocumentType,
3166  typename OutputHandler =
3168  typename StateAllocator = CrtAllocator>
3170  : public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
3172  public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
3173 {
3174  public:
3175  typedef typename SchemaDocumentType::SchemaType SchemaType;
3176  typedef typename SchemaDocumentType::PointerType PointerType;
3177  typedef typename SchemaType::EncodingType EncodingType;
3178  typedef typename SchemaType::SValue SValue;
3179  typedef typename EncodingType::Ch Ch;
3182 
3184 
3190  GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3191  StateAllocator* allocator = 0,
3192  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3193  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3194  : schemaDocument_(&schemaDocument),
3195  root_(schemaDocument.GetRoot()),
3196  stateAllocator_(allocator),
3197  ownStateAllocator_(0),
3198  schemaStack_(allocator, schemaStackCapacity),
3199  documentStack_(allocator, documentStackCapacity),
3200  outputHandler_(0),
3201  error_(kObjectType),
3202  currentError_(),
3203  missingDependents_(),
3204  valid_(true),
3205  flags_(kValidateDefaultFlags),
3206  depth_(0)
3207  {
3208  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
3209  }
3210 
3212 
3218  GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3219  OutputHandler& outputHandler,
3220  StateAllocator* allocator = 0,
3221  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3222  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3223  : schemaDocument_(&schemaDocument),
3224  root_(schemaDocument.GetRoot()),
3225  stateAllocator_(allocator),
3226  ownStateAllocator_(0),
3227  schemaStack_(allocator, schemaStackCapacity),
3228  documentStack_(allocator, documentStackCapacity),
3229  outputHandler_(&outputHandler),
3230  error_(kObjectType),
3231  currentError_(),
3232  missingDependents_(),
3233  valid_(true),
3234  flags_(kValidateDefaultFlags),
3235  depth_(0)
3236  {
3237  RAPIDJSON_SCHEMA_PRINT(Method,
3238  "GenericSchemaValidator::GenericSchemaValidator (output handler)");
3239  }
3240 
3243  {
3244  Reset();
3245  RAPIDJSON_DELETE(ownStateAllocator_);
3246  }
3247 
3249  void Reset()
3250  {
3251  while(!schemaStack_.Empty())
3252  PopSchema();
3253  documentStack_.Clear();
3254  ResetError();
3255  }
3256 
3258  void ResetError()
3259  {
3260  error_.SetObject();
3261  currentError_.SetNull();
3262  missingDependents_.SetNull();
3263  valid_ = true;
3264  }
3265 
3267  void SetValidateFlags(unsigned flags) { flags_ = flags; }
3268  virtual unsigned GetValidateFlags() const { return flags_; }
3269 
3270  virtual bool IsValid() const
3271  {
3272  if(!valid_)
3273  return false;
3274  if(GetContinueOnErrors() && !error_.ObjectEmpty())
3275  return false;
3276  return true;
3277  }
3279 
3281  ValueType& GetError() { return error_; }
3282  const ValueType& GetError() const { return error_; }
3283 
3285  // If reporting all errors, the stack will be empty.
3287  {
3288  return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
3289  }
3290 
3292  // If reporting all errors, the stack will be empty, so return "errors".
3294  {
3295  if(!schemaStack_.Empty())
3296  return CurrentContext().invalidKeyword;
3297  if(GetContinueOnErrors() && !error_.ObjectEmpty())
3298  return static_cast<const Ch*>(GetErrorsString());
3299  return 0;
3300  }
3301 
3303  // If reporting all errors, the stack will be empty, so return kValidateErrors.
3305  {
3306  if(!schemaStack_.Empty())
3307  return CurrentContext().invalidCode;
3308  if(GetContinueOnErrors() && !error_.ObjectEmpty())
3309  return kValidateErrors;
3310  return kValidateErrorNone;
3311  }
3312 
3314  // If reporting all errors, the stack will be empty.
3316  {
3317  if(documentStack_.Empty())
3318  {
3319  return PointerType();
3320  }
3321  else
3322  {
3323  return PointerType(documentStack_.template Bottom<Ch>(),
3324  documentStack_.GetSize() / sizeof(Ch));
3325  }
3326  }
3327 
3328  void NotMultipleOf(int64_t actual, const SValue& expected)
3329  {
3330  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3331  }
3332  void NotMultipleOf(uint64_t actual, const SValue& expected)
3333  {
3334  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3335  }
3336  void NotMultipleOf(double actual, const SValue& expected)
3337  {
3338  AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3339  }
3340  void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive)
3341  {
3342  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3343  ValueType(actual).Move(),
3344  expected,
3345  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3346  }
3347  void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive)
3348  {
3349  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3350  ValueType(actual).Move(),
3351  expected,
3352  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3353  }
3354  void AboveMaximum(double actual, const SValue& expected, bool exclusive)
3355  {
3356  AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3357  ValueType(actual).Move(),
3358  expected,
3359  exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3360  }
3361  void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive)
3362  {
3363  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3364  ValueType(actual).Move(),
3365  expected,
3366  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3367  }
3368  void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive)
3369  {
3370  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3371  ValueType(actual).Move(),
3372  expected,
3373  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3374  }
3375  void BelowMinimum(double actual, const SValue& expected, bool exclusive)
3376  {
3377  AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3378  ValueType(actual).Move(),
3379  expected,
3380  exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3381  }
3382 
3383  void TooLong(const Ch* str, SizeType length, SizeType expected)
3384  {
3385  AddNumberError(kValidateErrorMaxLength,
3386  ValueType(str, length, GetStateAllocator()).Move(),
3387  SValue(expected).Move());
3388  }
3389  void TooShort(const Ch* str, SizeType length, SizeType expected)
3390  {
3391  AddNumberError(kValidateErrorMinLength,
3392  ValueType(str, length, GetStateAllocator()).Move(),
3393  SValue(expected).Move());
3394  }
3395  void DoesNotMatch(const Ch* str, SizeType length)
3396  {
3397  currentError_.SetObject();
3398  currentError_.AddMember(GetActualString(),
3399  ValueType(str, length, GetStateAllocator()).Move(),
3400  GetStateAllocator());
3401  AddCurrentError(kValidateErrorPattern);
3402  }
3403 
3405  {
3406  currentError_.SetObject();
3407  currentError_.AddMember(
3408  GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
3409  AddCurrentError(kValidateErrorAdditionalItems, true);
3410  }
3411  void TooFewItems(SizeType actualCount, SizeType expectedCount)
3412  {
3413  AddNumberError(
3414  kValidateErrorMinItems, ValueType(actualCount).Move(), SValue(expectedCount).Move());
3415  }
3416  void TooManyItems(SizeType actualCount, SizeType expectedCount)
3417  {
3418  AddNumberError(
3419  kValidateErrorMaxItems, ValueType(actualCount).Move(), SValue(expectedCount).Move());
3420  }
3421  void DuplicateItems(SizeType index1, SizeType index2)
3422  {
3423  ValueType duplicates(kArrayType);
3424  duplicates.PushBack(index1, GetStateAllocator());
3425  duplicates.PushBack(index2, GetStateAllocator());
3426  currentError_.SetObject();
3427  currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
3428  AddCurrentError(kValidateErrorUniqueItems, true);
3429  }
3430 
3431  void TooManyProperties(SizeType actualCount, SizeType expectedCount)
3432  {
3433  AddNumberError(kValidateErrorMaxProperties,
3434  ValueType(actualCount).Move(),
3435  SValue(expectedCount).Move());
3436  }
3437  void TooFewProperties(SizeType actualCount, SizeType expectedCount)
3438  {
3439  AddNumberError(kValidateErrorMinProperties,
3440  ValueType(actualCount).Move(),
3441  SValue(expectedCount).Move());
3442  }
3443  void StartMissingProperties() { currentError_.SetArray(); }
3444  void AddMissingProperty(const SValue& name)
3445  {
3446  currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
3447  }
3449  {
3450  if(currentError_.Empty())
3451  return false;
3452  ValueType error(kObjectType);
3453  error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
3454  currentError_ = error;
3455  AddCurrentError(kValidateErrorRequired);
3456  return true;
3457  }
3458  void PropertyViolations(ISchemaValidator** subvalidators, SizeType count)
3459  {
3460  for(SizeType i = 0; i < count; ++i)
3461  MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
3462  }
3463  void DisallowedProperty(const Ch* name, SizeType length)
3464  {
3465  currentError_.SetObject();
3466  currentError_.AddMember(GetDisallowedString(),
3467  ValueType(name, length, GetStateAllocator()).Move(),
3468  GetStateAllocator());
3469  AddCurrentError(kValidateErrorAdditionalProperties, true);
3470  }
3471 
3472  void StartDependencyErrors() { currentError_.SetObject(); }
3473  void StartMissingDependentProperties() { missingDependents_.SetArray(); }
3474  void AddMissingDependentProperty(const SValue& targetName)
3475  {
3476  missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(),
3477  GetStateAllocator());
3478  }
3479  void EndMissingDependentProperties(const SValue& sourceName)
3480  {
3481  if(!missingDependents_.Empty())
3482  {
3483  // Create equivalent 'required' error
3484  ValueType error(kObjectType);
3486  error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
3487  AddErrorCode(error, code);
3488  AddErrorInstanceLocation(error, false);
3489  // When appending to a pointer ensure its allocator is used
3490  PointerType schemaRef = GetInvalidSchemaPointer().Append(
3491  SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies),
3492  &GetInvalidSchemaPointer().GetAllocator());
3493  AddErrorSchemaLocation(error,
3494  schemaRef.Append(sourceName.GetString(),
3495  sourceName.GetStringLength(),
3496  &GetInvalidSchemaPointer().GetAllocator()));
3497  ValueType wrapper(kObjectType);
3498  wrapper.AddMember(
3499  ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(),
3500  error,
3501  GetStateAllocator());
3502  currentError_.AddMember(
3503  ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
3504  }
3505  }
3506  void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator)
3507  {
3508  currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
3509  static_cast<GenericSchemaValidator*>(subvalidator)->GetError(),
3510  GetStateAllocator());
3511  }
3513  {
3514  if(currentError_.ObjectEmpty())
3515  return false;
3516  ValueType error(kObjectType);
3517  error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
3518  currentError_ = error;
3519  AddCurrentError(kValidateErrorDependencies);
3520  return true;
3521  }
3522 
3524  {
3525  currentError_.SetObject();
3526  AddCurrentError(code);
3527  }
3528  void StartDisallowedType() { currentError_.SetArray(); }
3529  void AddExpectedType(const typename SchemaType::ValueType& expectedType)
3530  {
3531  currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(),
3532  GetStateAllocator());
3533  }
3534  void EndDisallowedType(const typename SchemaType::ValueType& actualType)
3535  {
3536  ValueType error(kObjectType);
3537  error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
3538  error.AddMember(GetActualString(),
3539  ValueType(actualType, GetStateAllocator()).Move(),
3540  GetStateAllocator());
3541  currentError_ = error;
3542  AddCurrentError(kValidateErrorType);
3543  }
3544  void NotAllOf(ISchemaValidator** subvalidators, SizeType count)
3545  {
3546  // Treat allOf like oneOf and anyOf to match
3547  // https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
3548  AddErrorArray(kValidateErrorAllOf, subvalidators, count);
3549  // for (SizeType i = 0; i < count; ++i) {
3550  // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
3551  // }
3552  }
3553  void NoneOf(ISchemaValidator** subvalidators, SizeType count)
3554  {
3555  AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
3556  }
3557  void NotOneOf(ISchemaValidator** subvalidators, SizeType count)
3558  {
3559  AddErrorArray(kValidateErrorOneOf, subvalidators, count);
3560  }
3561  void MultipleOneOf(SizeType index1, SizeType index2)
3562  {
3563  ValueType matches(kArrayType);
3564  matches.PushBack(index1, GetStateAllocator());
3565  matches.PushBack(index2, GetStateAllocator());
3566  currentError_.SetObject();
3567  currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
3568  AddCurrentError(kValidateErrorOneOfMatch);
3569  }
3570  void Disallowed()
3571  {
3572  currentError_.SetObject();
3573  AddCurrentError(kValidateErrorNot);
3574  }
3576  {
3577  currentError_.SetObject();
3578  AddCurrentError(kValidateErrorReadOnly);
3579  }
3581  {
3582  currentError_.SetObject();
3583  AddCurrentError(kValidateErrorWriteOnly);
3584  }
3585 
3586 #define RAPIDJSON_STRING_(name, ...) \
3587  static const StringRefType& Get##name##String() \
3588  { \
3589  static const Ch s[] = {__VA_ARGS__, '\0'}; \
3590  static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
3591  return v; \
3592  }
3593 
3594  RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
3595  RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
3596  RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
3597  RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
3598  RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
3599  RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
3600  RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
3601  RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
3602  RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
3603  RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
3604  RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
3605 
3606 #undef RAPIDJSON_STRING_
3607 
3608 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1) \
3609  if(!valid_) \
3610  return false; \
3611  if((!BeginValue() && !GetContinueOnErrors()) || \
3612  (!CurrentSchema().method arg1 && !GetContinueOnErrors())) \
3613  { \
3614  *documentStack_.template Push<Ch>() = '\0'; \
3615  documentStack_.template Pop<Ch>(1); \
3616  RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>()); \
3617  valid_ = false; \
3618  return valid_; \
3619  }
3620 
3621 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2) \
3622  for(Context* context = schemaStack_.template Bottom<Context>(); \
3623  context != schemaStack_.template End<Context>(); \
3624  context++) \
3625  { \
3626  if(context->hasher) \
3627  static_cast<HasherType*>(context->hasher)->method arg2; \
3628  if(context->validators) \
3629  for(SizeType i_ = 0; i_ < context->validatorCount; i_++) \
3630  static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2; \
3631  if(context->patternPropertiesValidators) \
3632  for(SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++) \
3633  static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_]) \
3634  ->method arg2; \
3635  }
3636 
3637 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2) \
3638  valid_ = \
3639  (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2); \
3640  return valid_;
3641 
3642 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
3643  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1); \
3644  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2); \
3645  RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
3646 
3647  bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ()); }
3648  bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
3649  bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
3650  bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
3651  bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
3652  bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
3653  bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
3654  bool RawNumber(const Ch* str, SizeType length, bool copy)
3655  {
3657  String, (CurrentContext(), str, length, copy), (str, length, copy));
3658  }
3659  bool String(const Ch* str, SizeType length, bool copy)
3660  {
3662  String, (CurrentContext(), str, length, copy), (str, length, copy));
3663  }
3664 
3666  {
3667  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
3668  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
3670  valid_ = !outputHandler_ || outputHandler_->StartObject();
3671  return valid_;
3672  }
3673 
3674  bool Key(const Ch* str, SizeType len, bool copy)
3675  {
3676  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
3677  if(!valid_)
3678  return false;
3679  AppendToken(str, len);
3680  if(!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors())
3681  {
3682  valid_ = false;
3683  return valid_;
3684  }
3686  valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
3687  return valid_;
3688  }
3689 
3690  bool EndObject(SizeType memberCount)
3691  {
3692  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
3693  if(!valid_)
3694  return false;
3696  if(!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors())
3697  {
3698  valid_ = false;
3699  return valid_;
3700  }
3701  RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
3702  }
3703 
3704  bool StartArray()
3705  {
3706  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
3707  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
3709  valid_ = !outputHandler_ || outputHandler_->StartArray();
3710  return valid_;
3711  }
3712 
3713  bool EndArray(SizeType elementCount)
3714  {
3715  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
3716  if(!valid_)
3717  return false;
3719  if(!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors())
3720  {
3721  valid_ = false;
3722  return valid_;
3723  }
3724  RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
3725  }
3726 
3727 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
3728 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
3729 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
3730 
3731  // Implementation of ISchemaStateFactory<SchemaType>
3732  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root,
3733  const bool inheritContinueOnErrors)
3734  {
3735  *documentStack_.template Push<Ch>() = '\0';
3736  documentStack_.template Pop<Ch>(1);
3737  ISchemaValidator* sv = new(GetStateAllocator().Malloc(sizeof(GenericSchemaValidator)))
3738  GenericSchemaValidator(*schemaDocument_,
3739  root,
3740  documentStack_.template Bottom<char>(),
3741  documentStack_.GetSize(),
3742  depth_ + 1,
3743  &GetStateAllocator());
3744  sv->SetValidateFlags(inheritContinueOnErrors
3745  ? GetValidateFlags()
3746  : GetValidateFlags() &
3747  ~static_cast<unsigned>(kValidateContinueOnErrorFlag));
3748  return sv;
3749  }
3750 
3751  virtual void DestroySchemaValidator(ISchemaValidator* validator)
3752  {
3753  GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
3756  }
3757 
3758  virtual void* CreateHasher()
3759  {
3760  return new(GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
3761  }
3762 
3763  virtual uint64_t GetHashCode(void* hasher)
3764  {
3765  return static_cast<HasherType*>(hasher)->GetHashCode();
3766  }
3767 
3768  virtual void DestroryHasher(void* hasher)
3769  {
3770  HasherType* h = static_cast<HasherType*>(hasher);
3771  h->~HasherType();
3773  }
3774 
3775  virtual void* MallocState(size_t size) { return GetStateAllocator().Malloc(size); }
3776 
3777  virtual void FreeState(void* p) { StateAllocator::Free(p); }
3778  // End of implementation of ISchemaStateFactory<SchemaType>
3779 
3780  private:
3781  typedef typename SchemaType::Context Context;
3782  typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
3784 
3785  GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3786  const SchemaType& root,
3787  const char* basePath,
3788  size_t basePathSize,
3789  unsigned depth,
3790  StateAllocator* allocator = 0,
3791  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3792  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3793  : schemaDocument_(&schemaDocument),
3794  root_(root),
3795  stateAllocator_(allocator),
3796  ownStateAllocator_(0),
3797  schemaStack_(allocator, schemaStackCapacity),
3798  documentStack_(allocator, documentStackCapacity),
3799  outputHandler_(0),
3800  error_(kObjectType),
3801  currentError_(),
3802  missingDependents_(),
3803  valid_(true),
3804  flags_(kValidateDefaultFlags),
3805  depth_(depth)
3806  {
3807  RAPIDJSON_SCHEMA_PRINT(Method,
3808  "GenericSchemaValidator::GenericSchemaValidator (internal)",
3809  basePath && basePathSize ? basePath : "");
3810  if(basePath && basePathSize)
3811  memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
3812  }
3813 
3814  StateAllocator& GetStateAllocator()
3815  {
3816  if(!stateAllocator_)
3817  stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
3818  return *stateAllocator_;
3819  }
3820 
3821  bool GetContinueOnErrors() const { return flags_ & kValidateContinueOnErrorFlag; }
3822 
3823  bool BeginValue()
3824  {
3825  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
3826  if(schemaStack_.Empty())
3827  PushSchema(root_);
3828  else
3829  {
3830  if(CurrentContext().inArray)
3832  documentStack_, CurrentContext().arrayElementIndex);
3833 
3834  if(!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
3835  return false;
3836 
3837  SizeType count = CurrentContext().patternPropertiesSchemaCount;
3838  const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
3839  typename Context::PatternValidatorType patternValidatorType =
3840  CurrentContext().valuePatternValidatorType;
3841  bool valueUniqueness = CurrentContext().valueUniqueness;
3842  RAPIDJSON_ASSERT(CurrentContext().valueSchema);
3843  PushSchema(*CurrentContext().valueSchema);
3844 
3845  if(count > 0)
3846  {
3847  CurrentContext().objectPatternValidatorType = patternValidatorType;
3848  ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3849  SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3850  va =
3851  static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
3852  std::memset(va, 0, sizeof(ISchemaValidator*) * count);
3853  for(SizeType i = 0; i < count; i++)
3854  va[validatorCount++] =
3855  CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
3856  }
3857 
3858  CurrentContext().arrayUniqueness = valueUniqueness;
3859  }
3860  return true;
3861  }
3862 
3863  bool EndValue()
3864  {
3865  RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
3866  if(!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3867  return false;
3868 
3870  schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3871  *documentStack_.template Push<Ch>() = '\0';
3872  documentStack_.template Pop<Ch>(1);
3874  ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3875  void* hasher = CurrentContext().hasher;
3876  uint64_t h = hasher && CurrentContext().arrayUniqueness
3877  ? static_cast<HasherType*>(hasher)->GetHashCode()
3878  : 0;
3879 
3880  PopSchema();
3881 
3882  if(!schemaStack_.Empty())
3883  {
3884  Context& context = CurrentContext();
3885  // Only check uniqueness if there is a hasher
3886  if(hasher && context.valueUniqueness)
3887  {
3888  HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
3889  if(!a)
3890  CurrentContext().arrayElementHashCodes = a =
3891  new(GetStateAllocator().Malloc(sizeof(HashCodeArray)))
3892  HashCodeArray(kArrayType);
3893  for(typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End();
3894  ++itr)
3895  if(itr->GetUint64() == h)
3896  {
3897  DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
3898  // Cleanup before returning if continuing
3899  if(GetContinueOnErrors())
3900  {
3901  a->PushBack(h, GetStateAllocator());
3902  while(!documentStack_.Empty() &&
3903  *documentStack_.template Pop<Ch>(1) != '/')
3904  ;
3905  }
3907  }
3908  a->PushBack(h, GetStateAllocator());
3909  }
3910  }
3911 
3912  // Remove the last token of document pointer
3913  while(!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
3914  ;
3915 
3916  return true;
3917  }
3918 
3919  void AppendToken(const Ch* str, SizeType len)
3920  {
3921  documentStack_.template Reserve<Ch>(
3922  1 + len * 2); // worst case all characters are escaped as two characters
3923  *documentStack_.template PushUnsafe<Ch>() = '/';
3924  for(SizeType i = 0; i < len; i++)
3925  {
3926  if(str[i] == '~')
3927  {
3928  *documentStack_.template PushUnsafe<Ch>() = '~';
3929  *documentStack_.template PushUnsafe<Ch>() = '0';
3930  }
3931  else if(str[i] == '/')
3932  {
3933  *documentStack_.template PushUnsafe<Ch>() = '~';
3934  *documentStack_.template PushUnsafe<Ch>() = '1';
3935  }
3936  else
3937  *documentStack_.template PushUnsafe<Ch>() = str[i];
3938  }
3939  }
3940 
3941  RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema)
3942  {
3943  new(schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_);
3944  }
3945 
3946  RAPIDJSON_FORCEINLINE void PopSchema()
3947  {
3948  Context* c = schemaStack_.template Pop<Context>(1);
3949  if(HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes))
3950  {
3951  a->~HashCodeArray();
3953  }
3954  c->~Context();
3955  }
3956 
3957  void AddErrorInstanceLocation(ValueType& result, bool parent)
3958  {
3960  PointerType instancePointer = GetInvalidDocumentPointer();
3961  ((parent && instancePointer.GetTokenCount() > 0)
3962  ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3963  : instancePointer)
3964  .StringifyUriFragment(sb);
3965  ValueType instanceRef(
3966  sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator());
3967  result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3968  }
3969 
3970  void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType())
3971  {
3973  SizeType len = CurrentSchema().GetURI().GetStringLength();
3974  if(len)
3975  memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
3976  if(schema.GetTokenCount())
3977  schema.StringifyUriFragment(sb);
3978  else
3979  GetInvalidSchemaPointer().StringifyUriFragment(sb);
3980  ValueType schemaRef(
3981  sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator());
3982  result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3983  }
3984 
3985  void AddErrorCode(ValueType& result, const ValidateErrorCode code)
3986  {
3987  result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3988  }
3989 
3990  void AddError(ValueType& keyword, ValueType& error)
3991  {
3992  typename ValueType::MemberIterator member = error_.FindMember(keyword);
3993  if(member == error_.MemberEnd())
3994  error_.AddMember(keyword, error, GetStateAllocator());
3995  else
3996  {
3997  if(member->value.IsObject())
3998  {
3999  ValueType errors(kArrayType);
4000  errors.PushBack(member->value, GetStateAllocator());
4001  member->value = errors;
4002  }
4003  member->value.PushBack(error, GetStateAllocator());
4004  }
4005  }
4006 
4007  void AddCurrentError(const ValidateErrorCode code, bool parent = false)
4008  {
4009  AddErrorCode(currentError_, code);
4010  AddErrorInstanceLocation(currentError_, parent);
4011  AddErrorSchemaLocation(currentError_);
4012  AddError(
4013  ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(),
4014  currentError_);
4015  }
4016 
4017  void MergeError(ValueType& other)
4018  {
4019  for(typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd();
4020  it != end;
4021  ++it)
4022  {
4023  AddError(it->name, it->value);
4024  }
4025  }
4026 
4027  void AddNumberError(const ValidateErrorCode code,
4028  ValueType& actual,
4029  const SValue& expected,
4030  const typename SchemaType::ValueType& (*exclusive)() = 0)
4031  {
4032  currentError_.SetObject();
4033  currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
4034  currentError_.AddMember(GetExpectedString(),
4035  ValueType(expected, GetStateAllocator()).Move(),
4036  GetStateAllocator());
4037  if(exclusive)
4038  currentError_.AddMember(
4039  ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
4040  AddCurrentError(code);
4041  }
4042 
4043  void
4044  AddErrorArray(const ValidateErrorCode code, ISchemaValidator** subvalidators, SizeType count)
4045  {
4046  ValueType errors(kArrayType);
4047  for(SizeType i = 0; i < count; ++i)
4048  errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(),
4049  GetStateAllocator());
4050  currentError_.SetObject();
4051  currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
4052  AddCurrentError(code);
4053  }
4054 
4055  const SchemaType& CurrentSchema() const
4056  {
4057  return *schemaStack_.template Top<Context>()->schema;
4058  }
4059  Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
4060  const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
4061 
4062  static const size_t kDefaultSchemaStackCapacity = 1024;
4063  static const size_t kDefaultDocumentStackCapacity = 256;
4064  const SchemaDocumentType* schemaDocument_;
4065  const SchemaType& root_;
4066  StateAllocator* stateAllocator_;
4067  StateAllocator* ownStateAllocator_;
4069  schemaStack_;
4071  documentStack_;
4072  OutputHandler* outputHandler_;
4073  ValueType error_;
4074  ValueType currentError_;
4075  ValueType missingDependents_;
4076  bool valid_;
4077  unsigned flags_;
4078  unsigned depth_;
4079 };
4080 
4082 
4084 // SchemaValidatingReader
4085 
4087 
4096 template <unsigned parseFlags,
4097  typename InputStream,
4098  typename SourceEncoding,
4099  typename SchemaDocumentType = SchemaDocument,
4100  typename StackAllocator = CrtAllocator>
4102 {
4103  public:
4104  typedef typename SchemaDocumentType::PointerType PointerType;
4105  typedef typename InputStream::Ch Ch;
4107 
4109 
4113  SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd)
4114  : is_(is),
4115  sd_(sd),
4116  invalidSchemaKeyword_(),
4117  invalidSchemaCode_(kValidateErrorNone),
4118  error_(kObjectType),
4119  isValid_(true)
4120  {
4121  }
4122 
4123  template <typename Handler>
4124  bool operator()(Handler& handler)
4125  {
4127  reader;
4129  parseResult_ = reader.template Parse<parseFlags>(is_, validator);
4130 
4131  isValid_ = validator.IsValid();
4132  if(isValid_)
4133  {
4134  invalidSchemaPointer_ = PointerType();
4135  invalidSchemaKeyword_ = 0;
4136  invalidDocumentPointer_ = PointerType();
4137  error_.SetObject();
4138  }
4139  else
4140  {
4141  invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
4142  invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
4143  invalidSchemaCode_ = validator.GetInvalidSchemaCode();
4144  invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
4145  error_.CopyFrom(validator.GetError(), allocator_);
4146  }
4147 
4148  return parseResult_;
4149  }
4150 
4151  const ParseResult& GetParseResult() const { return parseResult_; }
4152  bool IsValid() const { return isValid_; }
4153  const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
4154  const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
4155  const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
4156  const ValueType& GetError() const { return error_; }
4157  ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
4158 
4159  private:
4160  InputStream& is_;
4161  const SchemaDocumentType& sd_;
4162 
4163  ParseResult parseResult_;
4164  PointerType invalidSchemaPointer_;
4165  const Ch* invalidSchemaKeyword_;
4166  PointerType invalidDocumentPointer_;
4167  ValidateErrorCode invalidSchemaCode_;
4168  StackAllocator allocator_;
4169  ValueType error_;
4170  bool isValid_;
4171 };
4172 
4174 RAPIDJSON_DIAG_POP
4175 
4176 #endif // RAPIDJSON_SCHEMA_H_
void Free(A &a, T *p, size_t n=1)
Definition: allocators.h:485
C-runtime library allocator.
Definition: allocators.h:83
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: reader.h:604
JSON schema document.
Definition: schema.h:2260
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:2290
const GValue & GetError() const
Definition: schema.h:2424
GValue & GetError()
Gets the error object.
Definition: schema.h:2423
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:2420
~GenericSchemaDocument()
Destructor.
Definition: schema.h:2379
GenericValue< EncodingType, AllocatorType > GValue
Definition: schema.h:2270
void SchemaError(const SchemaErrorCode code, const PointerType &location)
Default error method.
Definition: schema.h:2448
const Specification & GetSpecification() const
Definition: schema.h:2400
void SchemaErrorValue(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length)
Method for error with single string value insert.
Definition: schema.h:2455
static const Specification GetSpecification(const ValueType &document)
Static method to get the specification of any schema document.
Definition: schema.h:2405
const GValue & GetURI() const
Definition: schema.h:2398
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
Definition: schema.h:2264
EncodingType::Ch Ch
Definition: schema.h:2267
static const StringRefType & GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode)
Definition: schema.h:2426
Allocator AllocatorType
Definition: schema.h:2265
internal::Schema< GenericSchemaDocument > SchemaType
Definition: schema.h:2268
ValueType::EncodingType EncodingType
Definition: schema.h:2266
bool IsSupportedSpecification() const
Definition: schema.h:2401
GenericStringRef< Ch > StringRefType
Definition: schema.h:2272
ValueT ValueType
Definition: schema.h:2262
GenericPointer< ValueType, Allocator > PointerType
Definition: schema.h:2269
GenericUri< ValueType, Allocator > UriType
Definition: schema.h:2271
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:2467
JSON Schema Validator.
Definition: schema.h:3173
virtual void DestroryHasher(void *hasher)
Definition: schema.h:3768
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:3361
const ValueType & GetError() const
Definition: schema.h:3282
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:3190
void TooLong(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:3383
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
Definition: schema.h:3506
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:3458
void DisallowedItem(SizeType index)
Definition: schema.h:3404
virtual unsigned GetValidateFlags() const
Definition: schema.h:3268
bool String(const Ch *str, SizeType length, bool copy)
Definition: schema.h:3659
SchemaType::SValue SValue
Definition: schema.h:3178
~GenericSchemaValidator()
Destructor.
Definition: schema.h:3242
void StartMissingProperties()
Definition: schema.h:3443
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:3544
GenericValue< EncodingType, StateAllocator > ValueType
Definition: schema.h:3181
void DisallowedProperty(const Ch *name, SizeType length)
Definition: schema.h:3463
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root, const bool inheritContinueOnErrors)
Definition: schema.h:3732
void Reset()
Reset the internal states.
Definition: schema.h:3249
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:3340
virtual void FreeState(void *p)
Definition: schema.h:3777
void MultipleOneOf(SizeType index1, SizeType index2)
Definition: schema.h:3561
bool EndMissingProperties()
Definition: schema.h:3448
bool StartObject()
Definition: schema.h:3665
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:3286
void NotMultipleOf(uint64_t actual, const SValue &expected)
Definition: schema.h:3332
GenericStringRef< Ch > StringRefType
Definition: schema.h:3180
bool EndArray(SizeType elementCount)
Definition: schema.h:3713
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
Definition: schema.h:3529
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:3674
bool Null()
Definition: schema.h:3647
void StartDependencyErrors()
Definition: schema.h:3472
void TooShort(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:3389
void TooManyItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:3416
ValueType & GetError()
End of Implementation of ISchemaValidator.
Definition: schema.h:3281
virtual void * MallocState(size_t size)
Definition: schema.h:3775
void DuplicateItems(SizeType index1, SizeType index2)
Definition: schema.h:3421
void ResetError()
Reset the error state.
Definition: schema.h:3258
void AddMissingDependentProperty(const SValue &targetName)
Definition: schema.h:3474
EncodingType::Ch Ch
Definition: schema.h:3179
void AddMissingProperty(const SValue &name)
Definition: schema.h:3444
virtual bool IsValid() const
Definition: schema.h:3270
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:3347
void StartDisallowedType()
Definition: schema.h:3528
bool Bool(bool b)
Definition: schema.h:3648
void DisallowedWhenWriting()
Definition: schema.h:3575
bool Uint(unsigned u)
Definition: schema.h:3650
bool EndObject(SizeType memberCount)
Definition: schema.h:3690
void DisallowedWhenReading()
Definition: schema.h:3580
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:3553
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:3437
void NotMultipleOf(int64_t actual, const SValue &expected)
Definition: schema.h:3328
bool EndDependencyErrors()
Definition: schema.h:3512
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:3293
bool StartArray()
Definition: schema.h:3704
virtual void * CreateHasher()
Definition: schema.h:3758
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:3354
bool Uint64(uint64_t u)
Definition: schema.h:3652
virtual uint64_t GetHashCode(void *hasher)
Definition: schema.h:3763
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:3315
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition: schema.h:3218
void StartMissingDependentProperties()
Definition: schema.h:3473
bool Int64(int64_t i)
Definition: schema.h:3651
SchemaDocumentType::SchemaType SchemaType
Definition: schema.h:3175
void Disallowed()
Definition: schema.h:3570
SchemaType::EncodingType EncodingType
Definition: schema.h:3177
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:3368
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:3557
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:3431
bool Int(int i)
Definition: schema.h:3649
SchemaDocumentType::PointerType PointerType
Definition: schema.h:3176
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
Definition: schema.h:3534
virtual void DestroySchemaValidator(ISchemaValidator *validator)
Definition: schema.h:3751
bool RawNumber(const Ch *str, SizeType length, bool copy)
Definition: schema.h:3654
void NotMultipleOf(double actual, const SValue &expected)
Definition: schema.h:3336
ValidateErrorCode GetInvalidSchemaCode() const
Gets the error code of invalid schema.
Definition: schema.h:3304
bool Double(double d)
Definition: schema.h:3653
void DoesNotMatch(const Ch *str, SizeType length)
Definition: schema.h:3395
void TooFewItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:3411
void SetValidateFlags(unsigned flags)
Implementation of ISchemaValidator.
Definition: schema.h:3267
void DisallowedValue(const ValidateErrorCode code=kValidateErrorEnum)
Definition: schema.h:3523
void EndMissingDependentProperties(const SValue &sourceName)
Definition: schema.h:3479
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:3375
Represents an in-memory output stream.
Definition: stringbuffer.h:42
Ch * Push(size_t count)
Definition: stringbuffer.h:75
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition: stringbuffer.h:89
const Ch * GetString() const
Definition: stringbuffer.h:79
const Ch * GetString() const
Definition: uri.h:180
GenericUri Resolve(const GenericUri &baseuri, Allocator *allocator=0)
Resolve this URI against another (base) URI in accordance with URI resolution rules.
Definition: uri.h:259
SizeType GetBaseStringLength() const
Definition: uri.h:183
const Ch * GetBaseString() const
Definition: uri.h:182
GenericMemberIterator< false, EncodingType, AllocatorType >::Iterator MemberIterator
Member iterator for iterating in object.
Definition: document.h:831
const GenericValue * ConstValueIterator
Constant value iterator for iterating in array.
Definition: document.h:836
Definition: schema.h:2227
virtual const SchemaDocumentType * GetRemoteDocument(const GenericUri< ValueType, AllocatorType > uri, Specification &spec)
Definition: schema.h:2236
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:2231
virtual ~IGenericRemoteSchemaDocumentProvider()
Definition: schema.h:2233
virtual const SchemaDocumentType * GetRemoteDocument(const Ch *uri, SizeType length)=0
SchemaDocumentType::Ch Ch
Definition: schema.h:2229
SchemaDocumentType::ValueType ValueType
Definition: schema.h:2230
Default memory allocator used by the parser and DOM.
Definition: allocators.h:130
A helper class for parsing with validation.
Definition: schema.h:4102
SchemaDocumentType::PointerType PointerType
Definition: schema.h:4104
bool IsValid() const
Definition: schema.h:4152
const PointerType & GetInvalidDocumentPointer() const
Definition: schema.h:4155
ValidateErrorCode GetInvalidSchemaCode() const
Definition: schema.h:4157
InputStream::Ch Ch
Definition: schema.h:4105
bool operator()(Handler &handler)
Definition: schema.h:4124
const ValueType & GetError() const
Definition: schema.h:4156
const PointerType & GetInvalidSchemaPointer() const
Definition: schema.h:4153
const Ch * GetInvalidSchemaKeyword() const
Definition: schema.h:4154
const ParseResult & GetParseResult() const
Definition: schema.h:4151
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:4113
GenericValue< SourceEncoding, StackAllocator > ValueType
Definition: schema.h:4106
Definition: regex.h:659
bool Search(InputStream &is)
Definition: regex.h:699
Definition: schema.h:364
bool Bool(bool b)
Definition: schema.h:374
bool Uint64(uint64_t u)
Definition: schema.h:396
bool StartObject()
Definition: schema.h:426
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:427
bool StartArray()
Definition: schema.h:441
Encoding::Ch Ch
Definition: schema.h:366
bool Uint(unsigned u)
Definition: schema.h:382
bool Null()
Definition: schema.h:373
bool EndObject(SizeType memberCount)
Definition: schema.h:428
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
Definition: schema.h:368
bool Double(double d)
Definition: schema.h:403
bool String(const Ch *str, SizeType len, bool)
Definition: schema.h:420
bool Int(int i)
Definition: schema.h:375
uint64_t GetHashCode() const
Definition: schema.h:454
bool EndArray(SizeType elementCount)
Definition: schema.h:442
bool Int64(int64_t i)
Definition: schema.h:389
bool IsValid() const
Definition: schema.h:452
bool RawNumber(const Ch *str, SizeType len, bool)
Definition: schema.h:414
Definition: schema.h:285
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:287
Definition: schema.h:272
virtual void SetValidateFlags(unsigned flags)=0
virtual bool IsValid() const =0
virtual unsigned GetValidateFlags() const =0
virtual ~ISchemaValidator()
Definition: schema.h:274
Definition: schema.h:303
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:305
SchemaType::SValue SValue
Definition: schema.h:306
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:308
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:605
bool Int64(Context &context, int64_t i) const
Definition: schema.h:1214
bool exclusiveMaximum_
Definition: schema.h:2174
SizeType notValidatorIndex_
Definition: schema.h:2143
bool StartArray(Context &context) const
Definition: schema.h:1444
bool CheckUint(Context &context, uint64_t i) const
Definition: schema.h:1968
bool nullable_
Definition: schema.h:2180
bool StartObject(Context &context) const
Definition: schema.h:1287
SchemaDocumentType::PointerType PointerType
Definition: schema.h:609
const UriType & GetId() const
Definition: schema.h:1022
bool additionalProperties_
Definition: schema.h:2152
bool exclusiveMinimum_
Definition: schema.h:2173
p
Definition: schema.h:1578
t
Definition: schema.h:1569
bool Int(Context &context, int i) const
Definition: schema.h:1198
bool Uint64(Context &context, uint64_t u) const
Definition: schema.h:1222
bool uniqueItems_
Definition: schema.h:2164
s x
Definition: schema.h:1588
SizeType maxLength_
Definition: schema.h:2168
bool FindPropertyIndex(const ValueType &name, SizeType *outIndex) const
Definition: schema.h:1879
d
Definition: schema.h:1566
AllocatorType * allocator_
Definition: schema.h:2129
static void AssignIfExist(SizeType &out, const ValueType &value, const ValueType &name)
Definition: schema.h:1700
IValidationErrorHandler< Schema > ErrorHandler
Definition: schema.h:615
RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(AdditionalProperties
SizeType validatorCount_
Definition: schema.h:2142
bool readOnly_
Definition: schema.h:2178
SValue maximum_
Definition: schema.h:2171
bool CheckDoubleMultipleOf(Context &context, double d) const
Definition: schema.h:2054
i
Definition: schema.h:1568
n
Definition: schema.h:1572
const PointerType & GetPointer() const
Definition: schema.h:1026
SchemaArray oneOf_
Definition: schema.h:2139
GenericUri< ValueType, AllocatorType > UriType
Definition: schema.h:616
SizeType minItems_
Definition: schema.h:2161
s s m RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') private typedef internal::GenericRegex< EncodingType, AllocatorType > RegexType
Definition: schema.h:1617
~Schema()
Definition: schema.h:995
static void AssignIfExist(bool &out, const ValueType &value, const ValueType &name)
Definition: schema.h:1693
void AddType(const ValueType &type)
Definition: schema.h:1796
const Specification & GetSpecification() const
Definition: schema.h:1024
s s v
Definition: schema.h:1608
bool additionalItems_
Definition: schema.h:2163
bool CheckDoubleMinimum(Context &context, double d) const
Definition: schema.h:2032
bool EndObject(Context &context, SizeType memberCount) const
Definition: schema.h:1383
static bool IsPatternMatch(const RegexType *pattern, const Ch *str, SizeType)
Definition: schema.h:1753
Specification spec_
Definition: schema.h:2132
SizeType maxProperties_
Definition: schema.h:2151
Property * properties_
Definition: schema.h:2145
void DisallowedType(Context &context, const ValueType &actualType) const
Definition: schema.h:2071
bool CheckInt(Context &context, int64_t i) const
Definition: schema.h:1903
s m
Definition: schema.h:1588
bool CheckBool(Context &context, bool) const
Definition: schema.h:1893
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator, const UriType &id=UriType())
Definition: schema.h:619
const SchemaType * typeless_
Definition: schema.h:2134
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:608
bool EndArray(Context &context, SizeType elementCount) const
Definition: schema.h:1459
o
Definition: schema.h:1571
const SchemaType * additionalPropertiesSchema_
Definition: schema.h:2146
SizeType defaultValueLength_
Definition: schema.h:2176
bool Double(Context &context, double d) const
Definition: schema.h:1230
bool CreateParallelValidator(Context &context) const
Definition: schema.h:1817
l
Definition: schema.h:1574
SchemaDocumentType::ValueType ValueType
Definition: schema.h:607
const SchemaType * additionalItemsSchema_
Definition: schema.h:2157
const SValue & GetURI() const
Definition: schema.h:1020
e
Definition: schema.h:1579
unsigned type_
Definition: schema.h:2141
bool String(Context &context, const Ch *str, SizeType length, bool) const
Definition: schema.h:1251
bool CheckDoubleMaximum(Context &context, double d) const
Definition: schema.h:2043
void AddUniqueElement(V1 &a, const V2 &v)
Definition: schema.h:1678
SizeType enumCount_
Definition: schema.h:2136
EncodingType::Ch Ch
Definition: schema.h:611
SValue minimum_
Definition: schema.h:2170
PatternProperty * patternProperties_
Definition: schema.h:2147
ValueType::EncodingType EncodingType
Definition: schema.h:610
SchemaArray allOf_
Definition: schema.h:2137
UriType id_
Definition: schema.h:2131
a
Definition: schema.h:1565
s s s
Definition: schema.h:1606
SizeType minProperties_
Definition: schema.h:2150
RegexType * CreatePattern(const ValueType &value, SchemaDocumentType *sd, const PointerType &p)
Definition: schema.h:1734
bool hasSchemaDependencies_
Definition: schema.h:2155
GenericValue< EncodingType, AllocatorType > SValue
Definition: schema.h:614
const SchemaType ** itemsTuple_
Definition: schema.h:2159
const SchemaType * not_
Definition: schema.h:2140
void CreateSchemaValidators(Context &context, const SchemaArray &schemas, const bool inheritContinueOnErrors) const
Definition: schema.h:1869
SizeType minLength_
Definition: schema.h:2167
s s M
Definition: schema.h:1610
s s u
Definition: schema.h:1605
bool Uint(Context &context, unsigned u) const
Definition: schema.h:1206
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Definition: schema.h:1315
PointerType pointer_
Definition: schema.h:2133
SizeType maxItems_
Definition: schema.h:2162
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:613
static const ValueType & GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)
Definition: schema.h:1479
SchemaValidationContext< SchemaDocumentType > Context
Definition: schema.h:612
s s c
Definition: schema.h:1603
SValue uri_
Definition: schema.h:2130
bool Null(Context &context) const
Definition: schema.h:1179
SizeType itemsTupleCount_
Definition: schema.h:2160
SizeType patternPropertyCount_
Definition: schema.h:2148
bool hasRequired_
Definition: schema.h:2154
SizeType propertyCount_
Definition: schema.h:2149
RegexType * pattern_
Definition: schema.h:2166
bool Bool(Context &context, bool b) const
Definition: schema.h:1190
bool hasDependencies_
Definition: schema.h:2153
bool BeginValue(Context &context) const
Definition: schema.h:1028
uint64_t * enum_
Definition: schema.h:2135
r
Definition: schema.h:1576
P
Definition: schema.h:1575
static const ValueType * GetMember(const ValueType &value, const ValueType &name)
Definition: schema.h:1687
void AssignIfExist(SchemaArray &out, SchemaDocumentType &schemaDocument, const PointerType &p, const ValueType &value, const ValueType &name, const ValueType &document)
Definition: schema.h:1707
SValue multipleOf_
Definition: schema.h:2172
const SchemaType * itemsList_
Definition: schema.h:2158
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Definition: schema.h:1065
bool writeOnly_
Definition: schema.h:2179
SchemaArray anyOf_
Definition: schema.h:2138
A type-unsafe stack for storing different types of data.
Definition: stack.h:38
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:190
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:451
#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:173
SchemaErrorCode
Error codes when validating.
Definition: error.h:237
@ kValidateErrorMinProperties
Object has less members than 'minProperties' value.
Definition: error.h:194
@ kValidateErrorExclusiveMinimum
Number is less than or equal to the 'minimum' value.
Definition: error.h:181
@ kValidateErrorAdditionalItems
Definition: error.h:190
@ kValidateErrorMaxProperties
Object has more members than 'maxProperties' value.
Definition: error.h:193
@ kValidateErrorOneOfMatch
Definition: error.h:205
@ kValidateErrorRequired
Object is missing one or more members required by the schema.
Definition: error.h:195
@ kValidateErrorDependencies
Object has missing property or schema dependencies.
Definition: error.h:199
@ kValidateErrorUniqueItems
Array has duplicate items but 'uniqueItems' is true.
Definition: error.h:189
@ kValidateErrorReadOnly
Definition: error.h:211
@ kValidateErrorEnum
Property has a value that is not one of its allowed enumerated values.
Definition: error.h:201
@ kValidateErrorExclusiveMaximum
Number is greater than or equal to the 'maximum' value.
Definition: error.h:179
@ kValidateErrorType
Property has a type that is not allowed by the schema.
Definition: error.h:202
@ kValidateErrorOneOf
Property did not match any of the sub-schemas specified by 'oneOf'.
Definition: error.h:204
@ kValidateErrorMinLength
String is longer than the 'maxLength' value.
Definition: error.h:184
@ kValidateErrors
Top level error code when kValidateContinueOnErrorsFlag set.
Definition: error.h:174
@ kValidateErrorMaxLength
String is longer than the 'maxLength' value.
Definition: error.h:183
@ kValidateErrorWriteOnly
Definition: error.h:213
@ kValidateErrorAnyOf
Property did not match any of the sub-schemas specified by 'anyOf'.
Definition: error.h:208
@ kValidateErrorPattern
String does not match the 'pattern' regular expression.
Definition: error.h:185
@ kValidateErrorMaximum
Number is greater than the 'maximum' value.
Definition: error.h:178
@ kValidateErrorMaxItems
Array is longer than the 'maxItems' value.
Definition: error.h:187
@ kValidateErrorMinimum
Number is less than the 'minimum' value.
Definition: error.h:180
@ kValidateErrorMultipleOf
Number is not a multiple of the 'multipleOf' value.
Definition: error.h:177
@ kValidateErrorNone
No error.
Definition: error.h:175
@ kValidateErrorMinItems
Array is shorter than the 'minItems' value.
Definition: error.h:188
@ kValidateErrorNot
Property matched the sub-schema specified by 'not'.
Definition: error.h:209
@ kValidateErrorAdditionalProperties
Definition: error.h:196
@ kValidateErrorPatternProperties
See other errors.
Definition: error.h:198
@ kValidateErrorAllOf
Property did not match all of the sub-schemas specified by 'allOf'.
Definition: error.h:207
@ kSchemaErrorStartUnknown
Definition: error.h:240
@ kSchemaErrorSpecIllegal
Both JSON schema draft and OpenAPI version found in document.
Definition: error.h:253
@ kSchemaErrorSpecUnsupported
JSON schema draft or OpenAPI version is not supported.
Definition: error.h:252
@ kSchemaErrorRefPlainName
$ref fragment must be a JSON pointer
Definition: error.h:242
@ kSchemaErrorRefNoRemoteProvider
$ref is remote but there is no remote provider
Definition: error.h:247
@ kSchemaErrorSpecUnknown
JSON schema draft or OpenAPI version is not recognized.
Definition: error.h:251
@ kSchemaErrorRefUnknown
$ref does not resolve to a location in the target document
Definition: error.h:245
@ kSchemaErrorRefPointerInvalid
$ref fragment is not a valid JSON pointer at offset
Definition: error.h:244
@ kSchemaErrorRefNoRemoteSchema
Definition: error.h:248
@ kSchemaErrorRefCyclical
$ref is cyclical
Definition: error.h:246
@ kSchemaErrorRefInvalid
$ref must not be an empty string
Definition: error.h:243
@ kSchemaErrorRegexInvalid
Invalid regular expression in 'pattern' or 'patternProperties'.
Definition: error.h:250
@ kSchemaErrorReadOnlyAndWriteOnly
Property must not be both 'readOnly' and 'writeOnly'.
Definition: error.h:254
#define PRIu64
Definition: inttypes.h:143
#define PRId64
Definition: inttypes.h:89
__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:459
char * u32toa(uint32_t value, char *buffer)
Definition: itoa.h:41
char * u64toa(uint64_t value, char *buffer)
Definition: itoa.h:135
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1697
#define RAPIDJSON_IF_CONSTEXPR
Definition: pointer.h:34
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1514
const CharType(& source)[N]
Definition: pointer.h:1559
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1517
Type
Type of JSON value.
Definition: rapidjson.h:760
@ kFalseType
false
Definition: rapidjson.h:762
@ kObjectType
object
Definition: rapidjson.h:764
@ kTrueType
true
Definition: rapidjson.h:763
@ kStringType
string
Definition: rapidjson.h:766
@ kNullType
null
Definition: rapidjson.h:761
@ kArrayType
array
Definition: rapidjson.h:765
@ kNumberType
number
Definition: rapidjson.h:767
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:746
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:429
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:326
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:742
GenericSchemaValidator< SchemaDocument > SchemaValidator
Definition: schema.h:4081
#define RAPIDJSON_SCHEMA_PRINT(name,...)
Definition: schema.h:165
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
Definition: schema.h:3608
ValidateFlag
Combination of validate flags.
Definition: schema.h:195
@ kValidateNoFlags
No flags are set.
Definition: schema.h:196
@ kValidateWriteFlag
Validation is for a write semantic.
Definition: schema.h:199
@ kValidateDefaultFlags
Definition: schema.h:200
@ kValidateReadFlag
Validation is for a read semantic.
Definition: schema.h:198
@ kValidateContinueOnErrorFlag
Don't stop after first validation error.
Definition: schema.h:197
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
Definition: schema.h:3146
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
Definition: schema.h:3642
SchemaDraft
Definition: schema.h:208
@ kDraftUnknown
Definition: schema.h:209
@ kDraft03
Definition: schema.h:211
@ kDraftNone
Definition: schema.h:210
@ kDraft2020_12
Definition: schema.h:219
@ kDraft07
Definition: schema.h:217
@ kDraft06
Definition: schema.h:216
@ kDraft2019_09
Definition: schema.h:218
@ kDraft04
Definition: schema.h:213
@ kDraftMin
Current minimum supported draft.
Definition: schema.h:212
@ kDraft05
Definition: schema.h:214
@ kDraftMax
Current maximum supported draft.
Definition: schema.h:215
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
Definition: schema.h:3637
#define RAPIDJSON_STRING_(name,...)
Definition: schema.h:3586
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)
Definition: schema.h:172
OpenApiVersion
Definition: schema.h:223
@ kVersionMax
Current maximum supported version.
Definition: schema.h:229
@ kVersion20
Definition: schema.h:227
@ kVersionMin
Current minimum supported version.
Definition: schema.h:226
@ kVersionUnknown
Definition: schema.h:224
@ kVersion30
Definition: schema.h:228
@ kVersion31
Definition: schema.h:230
@ kVersionNone
Definition: schema.h:225
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
Definition: schema.h:3621
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition: schema.h:3148
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:417
Result of parsing (wraps ParseErrorCode)
Definition: error.h:108
Definition: schema.h:234
Specification(OpenApiVersion o)
Definition: schema.h:236
SchemaDraft draft
Definition: schema.h:253
bool IsSupported() const
Definition: schema.h:248
OpenApiVersion oapi
Definition: schema.h:254
~Specification()
Definition: schema.h:247
Specification(SchemaDraft d)
Definition: schema.h:235
Definition: schema.h:2115
~PatternProperty()
Definition: schema.h:2117
RegexType * pattern
Definition: schema.h:2126
const SchemaType * schema
Definition: schema.h:2125
PatternProperty()
Definition: schema.h:2116
Definition: schema.h:2096
const SchemaType * dependenciesSchema
Definition: schema.h:2108
bool required
Definition: schema.h:2111
~Property()
Definition: schema.h:2105
const SchemaType * schema
Definition: schema.h:2107
SizeType dependenciesValidatorIndex
Definition: schema.h:2109
bool * dependencies
Definition: schema.h:2110
SValue name
Definition: schema.h:2106
Property()
Definition: schema.h:2097
Definition: schema.h:1669
SchemaArray()
Definition: schema.h:1670
const SchemaType ** schemas
Definition: schema.h:1672
~SchemaArray()
Definition: schema.h:1671
SizeType count
Definition: schema.h:1674
SizeType begin
Definition: schema.h:1673
Definition: schema.h:503
bool arrayUniqueness
Definition: schema.h:597
SizeType validatorCount
Definition: schema.h:586
const SchemaType ** patternPropertiesSchemas
Definition: schema.h:589
ISchemaValidator ** validators
Definition: schema.h:585
SizeType arrayElementIndex
Definition: schema.h:593
bool valueUniqueness
Definition: schema.h:596
SizeType patternPropertiesValidatorCount
Definition: schema.h:588
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
Definition: schema.h:505
const SchemaType * valueSchema
Definition: schema.h:580
bool * propertyExist
Definition: schema.h:594
void * hasher
Definition: schema.h:583
IValidationErrorHandler< SchemaType > ErrorHandlerType
Definition: schema.h:506
PatternValidatorType
Definition: schema.h:511
@ kPatternValidatorWithProperty
Definition: schema.h:513
@ kPatternValidatorWithAdditionalProperty
Definition: schema.h:514
@ kPatternValidatorOnly
Definition: schema.h:512
ValidateErrorCode invalidCode
Definition: schema.h:582
void * arrayElementHashCodes
Definition: schema.h:584
ISchemaValidator ** patternPropertiesValidators
Definition: schema.h:587
SizeType patternPropertiesSchemaCount
Definition: schema.h:590
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:504
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s, unsigned fl=0)
Definition: schema.h:517
const Ch * invalidKeyword
Definition: schema.h:581
~SchemaValidationContext()
Definition: schema.h:544
unsigned flags
Definition: schema.h:579
ValueType::Ch Ch
Definition: schema.h:508
SchemaType::ValueType ValueType
Definition: schema.h:507
PatternValidatorType valuePatternValidatorType
Definition: schema.h:591
ErrorHandlerType & error_handler
Definition: schema.h:577
PatternValidatorType objectPatternValidatorType
Definition: schema.h:592
SchemaValidatorFactoryType & factory
Definition: schema.h:576
bool inArray
Definition: schema.h:595
const SchemaType * schema
Definition: schema.h:578
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:2201
Definition: schema.h:2185
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:2186
Definition: schema.h:465
int64_t i
Definition: schema.h:467
uint64_t u
Definition: schema.h:466