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 
72 ///////////////////////////////////////////////////////////////////////////////
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 
107 ///////////////////////////////////////////////////////////////////////////////
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 
123 ///////////////////////////////////////////////////////////////////////////////
124 // Forward declarations
125 
126 template <typename ValueType, typename Allocator>
128 
129 namespace internal {
130 
131 template <typename SchemaDocumentType>
132 class Schema;
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 // ISchemaValidator
136 
138 public:
139  virtual ~ISchemaValidator() {}
140  virtual bool IsValid() const = 0;
141 };
142 
143 ///////////////////////////////////////////////////////////////////////////////
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 
159 ///////////////////////////////////////////////////////////////////////////////
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 
215 ///////////////////////////////////////////////////////////////////////////////
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 
303  static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
304  h ^= d;
305  h *= kPrime;
306  return h;
307  }
308 
310 };
311 
312 ///////////////////////////////////////////////////////////////////////////////
313 // SchemaValidationContext
314 
315 template <typename SchemaDocumentType>
321  typedef typename ValueType::Ch Ch;
322 
326  kPatternValidatorWithAdditionalProperty
327  };
328 
329  SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :
330  factory(f),
331  error_handler(eh),
332  schema(s),
333  valueSchema(),
334  invalidKeyword(),
335  hasher(),
336  arrayElementHashCodes(),
337  validators(),
338  validatorCount(),
339  patternPropertiesValidators(),
340  patternPropertiesValidatorCount(),
341  patternPropertiesSchemas(),
342  patternPropertiesSchemaCount(),
343  valuePatternValidatorType(kPatternValidatorOnly),
344  propertyExist(),
345  inArray(false),
346  valueUniqueness(false),
347  arrayUniqueness(false)
348  {
349  }
350 
352  if (hasher)
353  factory.DestroryHasher(hasher);
354  if (validators) {
355  for (SizeType i = 0; i < validatorCount; i++)
356  factory.DestroySchemaValidator(validators[i]);
357  factory.FreeState(validators);
358  }
359  if (patternPropertiesValidators) {
360  for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
361  factory.DestroySchemaValidator(patternPropertiesValidators[i]);
362  factory.FreeState(patternPropertiesValidators);
363  }
364  if (patternPropertiesSchemas)
365  factory.FreeState(patternPropertiesSchemas);
366  if (propertyExist)
367  factory.FreeState(propertyExist);
368  }
369 
370  SchemaValidatorFactoryType& factory;
371  ErrorHandlerType& error_handler;
372  const SchemaType* schema;
373  const SchemaType* valueSchema;
374  const Ch* invalidKeyword;
375  void* hasher; // Only validator access
376  void* arrayElementHashCodes; // Only validator access this
381  const SchemaType** patternPropertiesSchemas;
387  bool inArray;
390 };
391 
392 ///////////////////////////////////////////////////////////////////////////////
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;
407  friend class GenericSchemaDocument<ValueType, AllocatorType>;
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[256u + 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 {
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;
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) {
720  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
721  }
722  }
723  else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
724  if (!patternValid || !otherValid) {
726  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
727  }
728  }
729  else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
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_) {
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_) {
964  for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
965  const Property& source = properties_[sourceIndex];
966  if (context.propertyExist[sourceIndex]) {
967  if (source.dependencies) {
969  for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
970  if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
971  context.error_handler.AddMissingDependentProperty(properties_[targetIndex].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:
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
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;
1379  bool required;
1380  };
1381 
1383  PatternProperty() : schema(), pattern() {}
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_;
1403  const SchemaType* not_;
1404  unsigned type_; // bitmask of kSchemaType
1407 
1409  const SchemaType* additionalPropertiesSchema_;
1419 
1420  const SchemaType* additionalItemsSchema_;
1421  const SchemaType* itemsList_;
1422  const SchemaType** itemsTuple_;
1428 
1429  RegexType* pattern_;
1432 
1433  SValue minimum_;
1434  SValue maximum_;
1435  SValue multipleOf_;
1438 
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 
1474 ///////////////////////////////////////////////////////////////////////////////
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 
1486 ///////////////////////////////////////////////////////////////////////////////
1487 // GenericSchemaDocument
1488 
1489 //! JSON schema document.
1490 /*!
1491  A JSON schema document is a compiled version of a JSON schema.
1492  It is basically a tree of internal::Schema.
1493 
1494  \note This is an immutable class (i.e. its instance cannot be modified after construction).
1495  \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1496  \tparam Allocator Allocator type for allocating memory of this document.
1497 */
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 
1513  //! Constructor.
1514  /*!
1515  Compile a JSON document into schema document.
1516 
1517  \param document A JSON document as source.
1518  \param uri The base URI of this schema document for purposes of violation reporting.
1519  \param uriLength Length of \c name, in code points.
1520  \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1521  \param allocator An optional allocator instance for allocating memory. Can be null.
1522  */
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  //! Move constructor in C++11
1571  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 
1588  //! Destructor
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 
1603  //! Get the root schema.
1604  const SchemaType& GetRoot() const { return *root_; }
1605 
1606 private:
1607  //! Prohibit copying
1609  //! Prohibit assignment
1610  GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1611 
1613  SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1614  PointerType source;
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) {}
1622  if (owned) {
1623  schema->~SchemaType();
1624  Allocator::Free(schema);
1625  }
1626  }
1627  PointerType pointer;
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_; //!< Root schema.
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 
1737 //! GenericSchemaDocument using Value type.
1739 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
1741 
1742 ///////////////////////////////////////////////////////////////////////////////
1743 // GenericSchemaValidator
1744 
1745 //! JSON Schema Validator.
1746 /*!
1747  A SAX style JSON schema validator.
1748  It uses a \c GenericSchemaDocument to validate SAX events.
1749  It delegates the incoming SAX events to an output handler.
1750  The default output handler does nothing.
1751  It can be reused multiple times by calling \c Reset().
1752 
1753  \tparam SchemaDocumentType Type of schema document.
1754  \tparam OutputHandler Type of output handler. Default handler does nothing.
1755  \tparam StateAllocator Allocator for storing the internal validation states.
1756 */
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 
1775  //! Constructor without output handler.
1776  /*!
1777  \param schemaDocument The schema document to conform to.
1778  \param allocator Optional allocator for storing internal validation states.
1779  \param schemaStackCapacity Optional initial capacity of schema path stack.
1780  \param documentStackCapacity Optional initial capacity of document path stack.
1781  */
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 
1805  //! Constructor with output handler.
1806  /*!
1807  \param schemaDocument The schema document to conform to.
1808  \param allocator Optional allocator for storing internal validation states.
1809  \param schemaStackCapacity Optional initial capacity of schema path stack.
1810  \param documentStackCapacity Optional initial capacity of document path stack.
1811  */
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 
1836  //! Destructor.
1838  Reset();
1839  RAPIDJSON_DELETE(ownStateAllocator_);
1840  }
1841 
1842  //! Reset the internal states.
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 
1853  //! Checks whether the current state is valid.
1854  // Implementation of ISchemaValidator
1855  virtual bool IsValid() const { return valid_; }
1856 
1857  //! Gets the error object.
1858  ValueType& GetError() { return error_; }
1859  const ValueType& GetError() const { return error_; }
1860 
1861  //! Gets the JSON pointer pointed to the invalid schema.
1862  PointerType GetInvalidSchemaPointer() const {
1863  return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1864  }
1865 
1866  //! Gets the keyword of invalid schema.
1867  const Ch* GetInvalidSchemaKeyword() const {
1868  return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1869  }
1870 
1871  //! Gets the JSON pointer pointed to the invalid value.
1872  PointerType GetInvalidDocumentPointer() const {
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 
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  }
1962  void AddMissingProperty(const SValue& name) {
1963  currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1964  }
1966  if (currentError_.Empty())
1967  return false;
1968  ValueType error(kObjectType);
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;
2005  ValueType error(kObjectType);
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) {
2023  ValueType error(kObjectType);
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()));
2115  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
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;
2123  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2124  return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2125  }
2126 
2127  bool EndObject(SizeType memberCount) {
2128  if (!valid_) return false;
2129  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
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()));
2136  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2137  return valid_ = !outputHandler_ || outputHandler_->StartArray();
2138  }
2139 
2140  bool EndArray(SizeType elementCount) {
2141  if (!valid_) return false;
2142  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
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_; //!< stack to store the current path of schema (BaseSchemaType *)
2403  internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
2404  OutputHandler* outputHandler_;
2405  ValueType error_;
2406  ValueType currentError_;
2408  bool valid_;
2409 #if RAPIDJSON_SCHEMA_VERBOSE
2410  unsigned depth_;
2411 #endif
2412 };
2413 
2415 
2416 ///////////////////////////////////////////////////////////////////////////////
2417 // SchemaValidatingReader
2418 
2419 //! A helper class for parsing with validation.
2420 /*!
2421  This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
2422 
2423  \tparam parseFlags Combination of \ref ParseFlag.
2424  \tparam InputStream Type of input stream, implementing Stream concept.
2425  \tparam SourceEncoding Encoding of the input stream.
2426  \tparam SchemaDocumentType Type of schema document.
2427  \tparam StackAllocator Allocator type for stack.
2428 */
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 
2441  //! Constructor
2442  /*!
2443  \param is Input stream.
2444  \param sd Schema document.
2445  */
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 
2486  StackAllocator allocator_;
2487  ValueType error_;
2488  bool isValid_;
2489 };
2490 
2492 RAPIDJSON_DIAG_POP
2493 
2494 #endif // RAPIDJSON_SCHEMA_H_
static QCString name
Definition: declinfo.cpp:673
bool StartObject()
Definition: schema.h:250
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
bool hasRequired_
Definition: schema.h:1417
Encoding::Ch Ch
Definition: schema.h:222
SizeType enumCount_
Definition: schema.h:1399
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Definition: schema.h:892
SchemaDocumentType::Ch Ch
Definition: schema.h:1480
virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)=0
char * u64toa(uint64_t value, char *buffer)
Definition: itoa.h:126
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2029
Allocator * ownAllocator_
Definition: schema.h:1729
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition: stringbuffer.h:82
const CharType(& source)[N]
Definition: pointer.h:1147
SchemaArray allOf_
Definition: schema.h:1400
SizeType patternPropertyCount_
Definition: schema.h:1411
SizeType minProperties_
Definition: schema.h:1413
SizeType defaultValueLength_
Definition: schema.h:1439
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
Definition: schema.h:1502
const SchemaType ** patternPropertiesSchemas
Definition: schema.h:381
SchemaDocumentType::PointerType PointerType
Definition: schema.h:1768
bool RawNumber(const Ch *str, SizeType len, bool)
Definition: schema.h:240
ParseResult parseResult_
Definition: schema.h:2482
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:384
void CreateSchemaRecursive(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document)
Definition: schema.h:1632
virtual void DestroySchemaValidator(ISchemaValidator *validator)
Definition: schema.h:2161
bool WriteType(Type type)
Definition: schema.h:288
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:406
virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator)=0
PointerType invalidDocumentPointer_
Definition: schema.h:2485
static QCString result
const Ch * invalidSchemaKeyword_
Definition: schema.h:2484
PointerType invalidSchemaPointer_
Definition: schema.h:2483
GenericValue< EncodingType, Allocator > URIType
Definition: schema.h:1508
void MergeError(ValueType &other)
Definition: schema.h:2366
AllocatorType * allocator_
Definition: schema.h:1394
virtual bool EndDependencyErrors()=0
void AddErrorLocation(ValueType &result, bool parent)
Definition: schema.h:2328
const SchemaType ** schemas
Definition: schema.h:1084
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:289
static bool IsPatternMatch(const RegexType *pattern, const Ch *str, SizeType)
Definition: schema.h:1145
virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount)=0
object
Definition: rapidjson.h:622
Default implementation of Handler.
Definition: fwd.h:85
const SchemaType * GetSchema(const PointerType &pointer) const
Definition: schema.h:1708
static void AssignIfExist(SizeType &out, const ValueType &value, const ValueType &name)
Definition: schema.h:1109
bool operator()(Handler &handler)
Definition: schema.h:2449
const Ch * GetString() const
Definition: stringbuffer.h:73
const char expected[]
Definition: Exception_t.cc:22
JSON schema document.
Definition: fwd.h:136
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:317
void AddUniqueElement(V1 &a, const V2 &v)
Definition: schema.h:1090
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:404
const SValue & GetURI() const
Definition: schema.h:668
PatternValidatorType objectPatternValidatorType
Definition: schema.h:384
void AddNumberError(const typename SchemaType::ValueType &keyword, ValueType &actual, const SValue &expected, const typename SchemaType::ValueType &(*exclusive)()=0)
Definition: schema.h:2372
const SchemaType * typeless_
Definition: schema.h:1397
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s)
Definition: schema.h:329
bool Int64(int64_t i)
Definition: schema.h:230
PatternProperty * patternProperties_
Definition: schema.h:1410
(Constant) member iterator for a JSON object value
Definition: document.h:99
array
Definition: rapidjson.h:623
virtual void FreeState(void *p)
Definition: schema.h:2185
StateAllocator * stateAllocator_
Definition: schema.h:2400
SchemaDocumentType::PointerType PointerType
Definition: schema.h:400
SchemaDocumentType::SchemaType SchemaType
Definition: schema.h:1767
void DoesNotMatch(const Ch *str, SizeType length)
Definition: schema.h:1923
~GenericSchemaValidator()
Destructor.
Definition: schema.h:1837
const SchemaType * additionalItemsSchema_
Definition: schema.h:1420
bool StartArray()
Definition: schema.h:261
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
Definition: schema.h:2096
void AppendToken(const Ch *str, SizeType len)
Definition: schema.h:2300
virtual void EndMissingDependentProperties(const SValue &sourceName)=0
GenericValue< EncodingType, StateAllocator > ValueType
Definition: schema.h:1773
InputStream & is_
Definition: schema.h:2479
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, const SchemaType &root, const char *basePath, size_t basePathSize, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Definition: schema.h:2194
const ValueType & GetError() const
Definition: schema.h:1859
virtual bool EndMissingProperties()=0
Stack< Allocator > stack_
Definition: schema.h:309
virtual ~IGenericRemoteSchemaDocumentProvider()
Definition: schema.h:1482
SizeType maxProperties_
Definition: schema.h:1414
bool String(const Ch *str, SizeType length, bool copy)
Definition: schema.h:2110
A type-unsafe stack for storing different types of data.
Definition: stack.h:36
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:1890
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:2446
SchemaType::EncodingType EncodingType
Definition: schema.h:1769
bool EndArray(SizeType elementCount)
Definition: schema.h:262
PatternValidatorType valuePatternValidatorType
Definition: schema.h:383
internal::Stack< Allocator > schemaRef_
Definition: schema.h:1733
IValidationErrorHandler< Schema > ErrorHandler
Definition: schema.h:406
const SchemaType * dependenciesSchema
Definition: schema.h:1376
StateAllocator * ownStateAllocator_
Definition: schema.h:2401
error
Definition: include.cc:26
ValueType & GetError()
Gets the error object.
Definition: schema.h:1858
bool Double(double d)
Definition: schema.h:2107
internal::GenericRegex< EncodingType, AllocatorType > RegexType
Definition: schema.h:1074
bool IsValid() const
Definition: regex.h:131
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:1906
bool Double(double d)
Definition: schema.h:232
false
Definition: rapidjson.h:620
const SchemaType * GetTypeless() const
Definition: schema.h:1722
SizeType notValidatorIndex_
Definition: schema.h:1406
void DisallowedItem(SizeType index)
Definition: schema.h:1929
IRemoteSchemaDocumentProviderType * remoteProvider_
Definition: schema.h:1727
bool EndArray(SizeType elementCount)
Definition: schema.h:2140
bool EndObject(Context &context, SizeType memberCount) const
Definition: schema.h:941
bool BeginValue(Context &context) const
Definition: schema.h:676
void AddCurrentError(const typename SchemaType::ValueType &keyword, bool parent=false)
Definition: schema.h:2361
static const ValueType * GetMember(const ValueType &value, const ValueType &name)
Definition: schema.h:1098
static const double g
Definition: Units.h:144
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:251
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
Definition: schema.h:1998
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
Definition: schema.h:224
const SchemaType * schema
Definition: schema.h:372
const SchemaType * valueSchema
Definition: schema.h:373
const SchemaType * itemsList_
Definition: schema.h:1421
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:114
void NotMultipleOf(uint64_t actual, const SValue &expected)
Definition: schema.h:1884
const SchemaType ** itemsTuple_
Definition: schema.h:1422
SValue minimum_
Definition: schema.h:1433
SchemaType::ValueType ValueType
Definition: schema.h:320
Result of parsing (wraps ParseErrorCode)
Definition: error.h:106
bool Uint64(uint64_t u)
Definition: schema.h:231
SizeType itemsTupleCount_
Definition: schema.h:1423
internal::Stack< StateAllocator > documentStack_
stack to store the current path of validating document (Ch)
Definition: schema.h:2403
static QStrList * l
Definition: config.cpp:1044
bool HandleRefSchema(const PointerType &source, const SchemaType **schema, const ValueType &v, const ValueType &document)
Definition: schema.h:1661
internal::Schema< GenericSchemaDocument > SchemaType
Definition: schema.h:1506
void StartDisallowedType()
Definition: schema.h:2016
RAPIDJSON_FORCEINLINE void PopSchema()
Definition: schema.h:2319
const URIType & GetURI() const
Definition: schema.h:1601
void Reset()
Reset the internal states.
Definition: schema.h:1843
virtual void TooLong(const Ch *str, SizeType length, SizeType expected)=0
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
uint64_t * enum_
Definition: schema.h:1398
SchemaType::SValue SValue
Definition: schema.h:1770
#define RAPIDJSON_STRING_(name,...)
Definition: schema.h:2045
bool CreateParallelValidator(Context &context) const
Definition: schema.h:1182
SchemaType::SValue SValue
Definition: schema.h:166
unsigned type_
Definition: schema.h:1404
Allocator * allocator_
Definition: schema.h:1728
ISchemaValidator ** patternPropertiesValidators
Definition: schema.h:379
bool WriteBuffer(Type type, const void *data, size_t len)
Definition: schema.h:292
bool EndDependencyErrors()
Definition: schema.h:2002
SizeType maxItems_
Definition: schema.h:1425
GenericValue< EncodingType, AllocatorType > SValue
Definition: schema.h:405
ISchemaValidator ** validators
Definition: schema.h:377
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
virtual void DisallowedProperty(const Ch *name, SizeType length)=0
bool Bool(bool b)
Definition: schema.h:227
ValueType::EncodingType EncodingType
Definition: schema.h:401
bool EndMissingProperties()
Definition: schema.h:1965
void AssignIfExist(SchemaArray &out, SchemaDocumentType &schemaDocument, const PointerType &p, const ValueType &value, const ValueType &name, const ValueType &document)
Definition: schema.h:1115
bool CheckDoubleMultipleOf(Context &context, double d) const
Definition: schema.h:1344
SchemaValidatorFactoryType & factory
Definition: schema.h:370
PointerType pointer_
Definition: schema.h:1396
ValueType missingDependents_
Definition: schema.h:2407
T abs(T value)
virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count)=0
SizeType dependenciesValidatorIndex
Definition: schema.h:1377
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:601
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1444
bool IsValid() const
Definition: schema.h:271
bool Int64(int64_t i)
Definition: schema.h:2105
string
Definition: rapidjson.h:624
void AddMissingDependentProperty(const SValue &targetName)
Definition: schema.h:1990
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: fwd.h:88
const double e
bool Uint64(Context &context, uint64_t u) const
Definition: schema.h:819
void TooShort(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:1919
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &)=0
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2034
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
#define Array
Definition: scanner.cpp:11549
const SchemaType * additionalPropertiesSchema_
Definition: schema.h:1409
void NotMultipleOf(double actual, const SValue &expected)
Definition: schema.h:1887
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
Definition: schema.h:2022
SchemaDocumentType::PointerType PointerType
Definition: schema.h:2437
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
SizeType propertyCount_
Definition: schema.h:1412
virtual void NotMultipleOf(int64_t actual, const SValue &expected)=0
PointerType GetPointer(const SchemaType *schema) const
Definition: schema.h:1715
virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count)=0
Definition: manual.c:13
OutputHandler * outputHandler_
Definition: schema.h:2404
std::void_t< T > n
void DisallowedProperty(const Ch *name, SizeType length)
Definition: schema.h:1978
void DisallowedType(Context &context, const ValueType &actualType) const
Definition: schema.h:1355
def move(depos, offset)
Definition: depos.py:107
virtual void StartDependencyErrors()=0
SchemaValidationContext< SchemaDocumentType > Context
Definition: schema.h:403
SizeType patternPropertiesValidatorCount
Definition: schema.h:380
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:1955
bool CheckUint(Context &context, uint64_t i) const
Definition: schema.h:1280
void CreateSchema(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document)
Definition: schema.h:1649
SchemaArray anyOf_
Definition: schema.h:1401
bool IsValid() const
Definition: schema.h:2472
uint64_t GetHashCode() const
Definition: schema.h:273
Ch * Push(size_t count)
Definition: stringbuffer.h:69
IValidationErrorHandler< SchemaType > ErrorHandlerType
Definition: schema.h:319
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
Definition: schema.h:2019
const PointerType & GetInvalidSchemaPointer() const
Definition: schema.h:2473
bool Int(Context &context, int i) const
Definition: schema.h:801
GenericStringRef< Ch > StringRefType
Definition: schema.h:1772
const SchemaDocumentType * schemaDocument_
Definition: schema.h:2398
virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)=0
void AddError(ValueType &keyword, ValueType &error)
Definition: schema.h:2347
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:2119
ValueType currentError_
Definition: schema.h:2406
const SchemaType * not_
Definition: schema.h:1403
internal::Hasher< EncodingType, StateAllocator > HasherType
Definition: schema.h:2192
virtual ~ISchemaValidator()
Definition: schema.h:139
virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType)=0
Context & CurrentContext()
Definition: schema.h:2393
unsigned __int64 uint64_t
Definition: stdint.h:136
bool CheckDoubleMaximum(Context &context, double d) const
Definition: schema.h:1336
const ParseResult & GetParseResult() const
Definition: schema.h:2471
JAVACC_STRING_TYPE String
Definition: JavaCC.h:22
virtual void * MallocState(size_t size)
Definition: schema.h:2181
InputStream::Ch Ch
Definition: schema.h:2438
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:1894
const PointerType & GetInvalidDocumentPointer() const
Definition: schema.h:2475
bool Null()
Definition: schema.h:226
void CreateSchemaValidators(Context &context, const SchemaArray &schemas) const
Definition: schema.h:1213
void StartMissingDependentProperties()
Definition: schema.h:1987
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:1862
#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)
Definition: schema.h:116
const SchemaDocumentType & sd_
Definition: schema.h:2480
void AddErrorArray(const typename SchemaType::ValueType &keyword, ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2382
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
Definition: schema.h:1902
number
Definition: rapidjson.h:625
SizeType maxLength_
Definition: schema.h:1431
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
Definition: schema.h:1738
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:1898
bool Double(Context &context, double d) const
Definition: schema.h:825
#define RAPIDJSON_SCHEMA_VERBOSE
Definition: schema.h:48
bool CheckInt(Context &context, int64_t i) const
Definition: schema.h:1232
void TooLong(const Ch *str, SizeType length, SizeType expected)
Definition: schema.h:1915
bool Uint64(uint64_t u)
Definition: schema.h:2106
void NotMultipleOf(int64_t actual, const SValue &expected)
Definition: schema.h:1881
Allocator AllocatorType
Definition: schema.h:1503
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:605
const ValueType & GetError() const
Definition: schema.h:2476
SchemaEntry(const PointerType &p, SchemaType *s, bool o, Allocator *allocator)
Definition: schema.h:1620
char * u32toa(uint32_t value, char *buffer)
Definition: itoa.h:39
bool CheckDoubleMinimum(Context &context, double d) const
Definition: schema.h:1328
virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count)=0
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
Definition: schema.h:318
void TooFewItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:1934
bool Uint(unsigned u)
Definition: schema.h:2104
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
Definition: schema.h:2074
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
Definition: schema.h:2081
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:2037
virtual void * CreateHasher()
Definition: schema.h:2167
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
virtual void StartMissingDependentProperties()=0
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
Definition: schema.h:1910
bool Search(InputStream &is)
Definition: regex.h:632
static uint64_t Hash(uint64_t h, uint64_t d)
Definition: schema.h:302
p
Definition: test.py:223
SchemaType * typeless_
Definition: schema.h:1731
virtual ~ISchemaStateFactory()
Definition: schema.h:149
ErrorHandlerType & error_handler
Definition: schema.h:371
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:1872
C-runtime library allocator.
Definition: allocators.h:75
SValue multipleOf_
Definition: schema.h:1435
StateAllocator & GetStateAllocator()
Definition: schema.h:2224
bool additionalItems_
Definition: schema.h:1426
virtual bool IsValid() const
Checks whether the current state is valid.
Definition: schema.h:1855
A helper class for parsing with validation.
Definition: schema.h:2435
Represents an in-memory output stream.
Definition: fwd.h:59
bool hasDependencies_
Definition: schema.h:1416
StackAllocator allocator_
Definition: schema.h:2486
ValueType::EncodingType EncodingType
Definition: schema.h:1504
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:399
const SchemaType * schema
Definition: schema.h:1375
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:1867
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1225
bool String(const Ch *str, SizeType len, bool)
Definition: schema.h:245
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition: pointer.h:214
SchemaDocumentType::ValueType ValueType
Definition: schema.h:398
virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType)=0
GenericValue< UTF8<>, StateAllocator > HashCodeArray
Definition: schema.h:2191
SchemaType::Context Context
Definition: schema.h:2190
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator)
Definition: schema.h:409
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
Definition: schema.h:1974
bool StartObject(Context &context) const
Definition: schema.h:871
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1604
const PointerType & GetPointer() const
Definition: schema.h:672
Property * properties_
Definition: schema.h:1408
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
Definition: schema.h:1523
signed __int64 int64_t
Definition: stdint.h:135
std::string pattern
Definition: regex_t.cc:33
void StartDependencyErrors()
Definition: schema.h:1984
union internal::Hasher::Number::U u
const SchemaType & root_
Definition: schema.h:2399
internal::Stack< Allocator > schemaMap_
Definition: schema.h:1732
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition: schema.h:1740
const SchemaType * schema
Definition: schema.h:1390
const SchemaType * root_
Root schema.
Definition: schema.h:1730
bool exclusiveMinimum_
Definition: schema.h:1436
virtual void StartDisallowedType()=0
T copy(T const &v)
virtual void * MallocState(size_t size)=0
void AddMissingProperty(const SValue &name)
Definition: schema.h:1962
static bool * b
Definition: config.cpp:1043
SchemaRefEntry(const PointerType &s, const PointerType &t, const SchemaType **outSchema, Allocator *allocator)
Definition: schema.h:1613
true
Definition: rapidjson.h:621
bool additionalProperties_
Definition: schema.h:1415
static msg_handler handler
Definition: qglobal.cpp:234
EncodingType::Ch Ch
Definition: schema.h:1771
bool Int(int i)
Definition: schema.h:228
SizeType minItems_
Definition: schema.h:1424
internal::Stack< StateAllocator > schemaStack_
stack to store the current path of schema (BaseSchemaType *)
Definition: schema.h:2402
list x
Definition: train.py:276
bool Int64(Context &context, int64_t i) const
Definition: schema.h:813
void EndMissingDependentProperties(const SValue &sourceName)
Definition: schema.h:1993
bool Int(int i)
Definition: schema.h:2103
bool StartArray(Context &context) const
Definition: schema.h:988
Reference to a constant string (not taking a copy)
Definition: document.h:253
bool Null(Context &context) const
Definition: schema.h:785
bool EndArray(Context &context, SizeType elementCount) const
Definition: schema.h:1000
RegexType * pattern_
Definition: schema.h:1429
SValue maximum_
Definition: schema.h:1434
bool FindPropertyIndex(const ValueType &name, SizeType *outIndex) const
Definition: schema.h:1219
virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount)=0
bool uniqueItems_
Definition: schema.h:1427
const SchemaType & CurrentSchema() const
Definition: schema.h:2392
EncodingType::Ch Ch
Definition: schema.h:1505
virtual void * CreateHasher()=0
SizeType minLength_
Definition: schema.h:1430
bool EndObject(SizeType memberCount)
Definition: schema.h:252
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1589
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1124
bool hasSchemaDependencies_
Definition: schema.h:1418
bool String(Context &context, const Ch *str, SizeType length, bool) const
Definition: schema.h:843
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:1951
void StartMissingProperties()
Definition: schema.h:1959
bool Bool(bool b)
Definition: schema.h:2102
virtual void DoesNotMatch(const Ch *str, SizeType length)=0
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Definition: schema.h:703
bool exclusiveMaximum_
Definition: schema.h:1437
Type
Type of JSON value.
Definition: rapidjson.h:618
if(!yymsg) yymsg
virtual uint64_t GetHashCode(void *hasher)
Definition: schema.h:2171
virtual bool IsValid() const =0
virtual void AddMissingProperty(const SValue &name)=0
GenericValue< SourceEncoding, StackAllocator > ValueType
Definition: schema.h:2439
Default memory allocator used by the parser and DOM.
Definition: allocators.h:115
RegexType * CreatePattern(const ValueType &value)
Definition: schema.h:1132
virtual void StartMissingProperties()=0
bool RawNumber(const Ch *str, SizeType length, bool copy)
Definition: schema.h:2108
virtual void DisallowedItem(SizeType index)=0
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:1782
const Ch * GetInvalidSchemaKeyword() const
Definition: schema.h:2474
Definition: types.h:32
virtual uint64_t GetHashCode(void *hasher)=0
bool Uint(unsigned u)
Definition: schema.h:229
GenericSchemaValidator< SchemaDocument > SchemaValidator
Definition: schema.h:2414
static QCString * s
Definition: config.cpp:1042
bool WriteNumber(const Number &n)
Definition: schema.h:290
def parent(G, child, parent_type)
Definition: graph.py:67
static void AssignIfExist(bool &out, const ValueType &value, const ValueType &name)
Definition: schema.h:1103
virtual void TooShort(const Ch *str, SizeType length, SizeType expected)=0
static QCString str
void DuplicateItems(SizeType index1, SizeType index2)
Definition: schema.h:1942
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1456
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
Definition: schema.h:2093
virtual void TooFewItems(SizeType actualCount, SizeType expectedCount)=0
JSON Schema Validator.
Definition: fwd.h:145
virtual void TooManyItems(SizeType actualCount, SizeType expectedCount)=0
virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual void DestroryHasher(void *hasher)
Definition: schema.h:2175
RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType &schema)
Definition: schema.h:2317
void TooManyItems(SizeType actualCount, SizeType expectedCount)
Definition: schema.h:1938
SizeType validatorCount_
Definition: schema.h:1405
h
training ###############################
Definition: train_cnn.py:186
bool Uint(Context &context, unsigned u) const
Definition: schema.h:807
void AddType(const ValueType &type)
Definition: schema.h:1172
bool Bool(Context &context, bool) const
Definition: schema.h:793
bool EndObject(SizeType memberCount)
Definition: schema.h:2127
virtual void AddMissingDependentProperty(const SValue &targetName)=0
null
Definition: rapidjson.h:619
SchemaArray oneOf_
Definition: schema.h:1402
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root)
Definition: schema.h:2153
EncodingType::Ch Ch
Definition: schema.h:402
const Context & CurrentContext() const
Definition: schema.h:2394
GenericPointer< ValueType, Allocator > PointerType
Definition: schema.h:1507