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