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


livox_ros_driver
Author(s): Livox Dev Team
autogenerated on Mon Mar 15 2021 02:40:46