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 <cmath> // abs, floor
21 
22 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
23 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
24 #else
25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
26 #endif
27 
28 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
29 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
30 #else
31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
32 #endif
33 
34 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
35 #include "internal/regex.h"
36 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
37 #include <regex>
38 #endif
39 
40 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
41 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
42 #else
43 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
44 #endif
45 
46 #ifndef RAPIDJSON_SCHEMA_VERBOSE
47 #define RAPIDJSON_SCHEMA_VERBOSE 0
48 #endif
49 
50 #if RAPIDJSON_SCHEMA_VERBOSE
51 #include "stringbuffer.h"
52 #endif
53 
54 RAPIDJSON_DIAG_PUSH
55 
56 #if defined(__GNUC__)
57 RAPIDJSON_DIAG_OFF(effc++)
58 #endif
59 
60 #ifdef __clang__
61 RAPIDJSON_DIAG_OFF(weak-vtables)
62 RAPIDJSON_DIAG_OFF(exit-time-destructors)
63 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
64 RAPIDJSON_DIAG_OFF(variadic-macros)
65 #endif
66 
67 #ifdef _MSC_VER
68 RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
69 #endif
70 
72 
74 // Verbose Utilities
75 
76 #if RAPIDJSON_SCHEMA_VERBOSE
77 
78 namespace internal {
79 
80 inline void PrintInvalidKeyword(const char* keyword) {
81  printf("Fail keyword: %s\n", keyword);
82 }
83 
84 inline void PrintInvalidKeyword(const wchar_t* keyword) {
85  wprintf(L"Fail keyword: %ls\n", keyword);
86 }
87 
88 inline void PrintInvalidDocument(const char* document) {
89  printf("Fail document: %s\n\n", document);
90 }
91 
92 inline void PrintInvalidDocument(const wchar_t* document) {
93  wprintf(L"Fail document: %ls\n\n", document);
94 }
95 
96 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
97  printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
98 }
99 
100 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
101  wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
102 }
103 
104 } // namespace internal
105 
106 #endif // RAPIDJSON_SCHEMA_VERBOSE
107 
109 // RAPIDJSON_INVALID_KEYWORD_RETURN
110 
111 #if RAPIDJSON_SCHEMA_VERBOSE
112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
113 #else
114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
115 #endif
116 
117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
118 RAPIDJSON_MULTILINEMACRO_BEGIN\
119  context.invalidKeyword = keyword.GetString();\
120  RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
121  return false;\
122 RAPIDJSON_MULTILINEMACRO_END
123 
125 // Forward declarations
126 
127 template <typename ValueType, typename Allocator>
129 
130 namespace internal {
131 
132 template <typename SchemaDocumentType>
133 class Schema;
134 
136 // ISchemaValidator
137 
139 public:
140  virtual ~ISchemaValidator() {}
141  virtual bool IsValid() const = 0;
142 };
143 
145 // ISchemaStateFactory
146 
147 template <typename SchemaType>
149 public:
150  virtual ~ISchemaStateFactory() {}
151  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
152  virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
153  virtual void* CreateHasher() = 0;
154  virtual uint64_t GetHashCode(void* hasher) = 0;
155  virtual void DestroryHasher(void* hasher) = 0;
156  virtual void* MallocState(size_t size) = 0;
157  virtual void FreeState(void* p) = 0;
158 };
159 
161 // Hasher
162 
163 // For comparison of compound value
164 template<typename Encoding, typename Allocator>
165 class Hasher {
166 public:
167  typedef typename Encoding::Ch Ch;
168 
169  Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
170 
171  bool Null() { return WriteType(kNullType); }
172  bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
173  bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
174  bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
175  bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
176  bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
177  bool Double(double d) {
178  Number n;
179  if (d < 0) n.u.i = static_cast<int64_t>(d);
180  else n.u.u = static_cast<uint64_t>(d);
181  n.d = d;
182  return WriteNumber(n);
183  }
184 
185  bool RawNumber(const Ch* str, SizeType len, bool) {
186  WriteBuffer(kNumberType, str, len * sizeof(Ch));
187  return true;
188  }
189 
190  bool String(const Ch* str, SizeType len, bool) {
191  WriteBuffer(kStringType, str, len * sizeof(Ch));
192  return true;
193  }
194 
195  bool StartObject() { return true; }
196  bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
197  bool EndObject(SizeType memberCount) {
198  uint64_t h = Hash(0, kObjectType);
199  uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
200  for (SizeType i = 0; i < memberCount; i++)
201  h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
202  *stack_.template Push<uint64_t>() = h;
203  return true;
204  }
205 
206  bool StartArray() { return true; }
207  bool EndArray(SizeType elementCount) {
208  uint64_t h = Hash(0, kArrayType);
209  uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
210  for (SizeType i = 0; i < elementCount; i++)
211  h = Hash(h, e[i]); // Use hash to achieve element order sensitive
212  *stack_.template Push<uint64_t>() = h;
213  return true;
214  }
215 
216  bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
217 
220  return *stack_.template Top<uint64_t>();
221  }
222 
223 private:
224  static const size_t kDefaultSize = 256;
225  struct Number {
226  union U {
229  }u;
230  double d;
231  };
232 
233  bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
234 
235  bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
236 
237  bool WriteBuffer(Type type, const void* data, size_t len) {
238  // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
239  uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
240  const unsigned char* d = static_cast<const unsigned char*>(data);
241  for (size_t i = 0; i < len; i++)
242  h = Hash(h, d[i]);
243  *stack_.template Push<uint64_t>() = h;
244  return true;
245  }
246 
248  static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
249  h ^= d;
250  h *= kPrime;
251  return h;
252  }
253 
255 };
256 
258 // SchemaValidationContext
259 
260 template <typename SchemaDocumentType>
265  typedef typename ValueType::Ch Ch;
266 
270  kPatternValidatorWithAdditionalProperty
271  };
272 
273  SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
274  factory(f),
275  schema(s),
276  valueSchema(),
277  invalidKeyword(),
278  hasher(),
279  arrayElementHashCodes(),
280  validators(),
281  validatorCount(),
282  patternPropertiesValidators(),
283  patternPropertiesValidatorCount(),
284  patternPropertiesSchemas(),
285  patternPropertiesSchemaCount(),
286  valuePatternValidatorType(kPatternValidatorOnly),
287  propertyExist(),
288  inArray(false),
289  valueUniqueness(false),
290  arrayUniqueness(false)
291  {
292  }
293 
295  if (hasher)
296  factory.DestroryHasher(hasher);
297  if (validators) {
298  for (SizeType i = 0; i < validatorCount; i++)
299  factory.DestroySchemaValidator(validators[i]);
300  factory.FreeState(validators);
301  }
302  if (patternPropertiesValidators) {
303  for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
304  factory.DestroySchemaValidator(patternPropertiesValidators[i]);
305  factory.FreeState(patternPropertiesValidators);
306  }
307  if (patternPropertiesSchemas)
308  factory.FreeState(patternPropertiesSchemas);
309  if (propertyExist)
310  factory.FreeState(propertyExist);
311  }
312 
313  SchemaValidatorFactoryType& factory;
314  const SchemaType* schema;
315  const SchemaType* valueSchema;
316  const Ch* invalidKeyword;
317  void* hasher; // Only validator access
318  void* arrayElementHashCodes; // Only validator access this
323  const SchemaType** patternPropertiesSchemas;
329  bool inArray;
332 };
333 
335 // Schema
336 
337 template <typename SchemaDocumentType>
338 class Schema {
339 public:
340  typedef typename SchemaDocumentType::ValueType ValueType;
341  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
342  typedef typename SchemaDocumentType::PointerType PointerType;
343  typedef typename ValueType::EncodingType EncodingType;
344  typedef typename EncodingType::Ch Ch;
348  friend class GenericSchemaDocument<ValueType, AllocatorType>;
349 
350  Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
351  allocator_(allocator),
352  typeless_(schemaDocument->GetTypeless()),
353  enum_(),
354  enumCount_(),
355  not_(),
356  type_((1 << kTotalSchemaType) - 1), // typeless
357  validatorCount_(),
358  properties_(),
359  additionalPropertiesSchema_(),
360  patternProperties_(),
361  patternPropertyCount_(),
362  propertyCount_(),
363  minProperties_(),
364  maxProperties_(SizeType(~0)),
365  additionalProperties_(true),
366  hasDependencies_(),
367  hasRequired_(),
368  hasSchemaDependencies_(),
369  additionalItemsSchema_(),
370  itemsList_(),
371  itemsTuple_(),
372  itemsTupleCount_(),
373  minItems_(),
374  maxItems_(SizeType(~0)),
375  additionalItems_(true),
376  uniqueItems_(false),
377  pattern_(),
378  minLength_(0),
379  maxLength_(~SizeType(0)),
380  exclusiveMinimum_(false),
381  exclusiveMaximum_(false)
382  {
383  typedef typename SchemaDocumentType::ValueType ValueType;
384  typedef typename ValueType::ConstValueIterator ConstValueIterator;
385  typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
386 
387  if (!value.IsObject())
388  return;
389 
390  if (const ValueType* v = GetMember(value, GetTypeString())) {
391  type_ = 0;
392  if (v->IsString())
393  AddType(*v);
394  else if (v->IsArray())
395  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
396  AddType(*itr);
397  }
398 
399  if (const ValueType* v = GetMember(value, GetEnumString()))
400  if (v->IsArray() && v->Size() > 0) {
401  enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
402  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
403  typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
404  char buffer[256 + 24];
405  MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
406  EnumHasherType h(&hasherAllocator, 256);
407  itr->Accept(h);
408  enum_[enumCount_++] = h.GetHashCode();
409  }
410  }
411 
412  if (schemaDocument) {
413  AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
414  AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
415  AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
416  }
417 
418  if (const ValueType* v = GetMember(value, GetNotString())) {
419  schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
420  notValidatorIndex_ = validatorCount_;
421  validatorCount_++;
422  }
423 
424  // Object
425 
426  const ValueType* properties = GetMember(value, GetPropertiesString());
427  const ValueType* required = GetMember(value, GetRequiredString());
428  const ValueType* dependencies = GetMember(value, GetDependenciesString());
429  {
430  // Gather properties from properties/required/dependencies
431  SValue allProperties(kArrayType);
432 
433  if (properties && properties->IsObject())
434  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
435  AddUniqueElement(allProperties, itr->name);
436 
437  if (required && required->IsArray())
438  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
439  if (itr->IsString())
440  AddUniqueElement(allProperties, *itr);
441 
442  if (dependencies && dependencies->IsObject())
443  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
444  AddUniqueElement(allProperties, itr->name);
445  if (itr->value.IsArray())
446  for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
447  if (i->IsString())
448  AddUniqueElement(allProperties, *i);
449  }
450 
451  if (allProperties.Size() > 0) {
452  propertyCount_ = allProperties.Size();
453  properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
454  for (SizeType i = 0; i < propertyCount_; i++) {
455  new (&properties_[i]) Property();
456  properties_[i].name = allProperties[i];
457  properties_[i].schema = typeless_;
458  }
459  }
460  }
461 
462  if (properties && properties->IsObject()) {
463  PointerType q = p.Append(GetPropertiesString(), allocator_);
464  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
465  SizeType index;
466  if (FindPropertyIndex(itr->name, &index))
467  schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
468  }
469  }
470 
471  if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
472  PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
473  patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
474  patternPropertyCount_ = 0;
475 
476  for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
477  new (&patternProperties_[patternPropertyCount_]) PatternProperty();
478  patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
479  schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
480  patternPropertyCount_++;
481  }
482  }
483 
484  if (required && required->IsArray())
485  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
486  if (itr->IsString()) {
487  SizeType index;
488  if (FindPropertyIndex(*itr, &index)) {
489  properties_[index].required = true;
490  hasRequired_ = true;
491  }
492  }
493 
494  if (dependencies && dependencies->IsObject()) {
495  PointerType q = p.Append(GetDependenciesString(), allocator_);
496  hasDependencies_ = true;
497  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
498  SizeType sourceIndex;
499  if (FindPropertyIndex(itr->name, &sourceIndex)) {
500  if (itr->value.IsArray()) {
501  properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
502  std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
503  for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
504  SizeType targetIndex;
505  if (FindPropertyIndex(*targetItr, &targetIndex))
506  properties_[sourceIndex].dependencies[targetIndex] = true;
507  }
508  }
509  else if (itr->value.IsObject()) {
510  hasSchemaDependencies_ = true;
511  schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
512  properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
513  validatorCount_++;
514  }
515  }
516  }
517  }
518 
519  if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
520  if (v->IsBool())
521  additionalProperties_ = v->GetBool();
522  else if (v->IsObject())
523  schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
524  }
525 
526  AssignIfExist(minProperties_, value, GetMinPropertiesString());
527  AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
528 
529  // Array
530  if (const ValueType* v = GetMember(value, GetItemsString())) {
531  PointerType q = p.Append(GetItemsString(), allocator_);
532  if (v->IsObject()) // List validation
533  schemaDocument->CreateSchema(&itemsList_, q, *v, document);
534  else if (v->IsArray()) { // Tuple validation
535  itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
536  SizeType index = 0;
537  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
538  schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
539  }
540  }
541 
542  AssignIfExist(minItems_, value, GetMinItemsString());
543  AssignIfExist(maxItems_, value, GetMaxItemsString());
544 
545  if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
546  if (v->IsBool())
547  additionalItems_ = v->GetBool();
548  else if (v->IsObject())
549  schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
550  }
551 
552  AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
553 
554  // String
555  AssignIfExist(minLength_, value, GetMinLengthString());
556  AssignIfExist(maxLength_, value, GetMaxLengthString());
557 
558  if (const ValueType* v = GetMember(value, GetPatternString()))
559  pattern_ = CreatePattern(*v);
560 
561  // Number
562  if (const ValueType* v = GetMember(value, GetMinimumString()))
563  if (v->IsNumber())
564  minimum_.CopyFrom(*v, *allocator_);
565 
566  if (const ValueType* v = GetMember(value, GetMaximumString()))
567  if (v->IsNumber())
568  maximum_.CopyFrom(*v, *allocator_);
569 
570  AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
571  AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
572 
573  if (const ValueType* v = GetMember(value, GetMultipleOfString()))
574  if (v->IsNumber() && v->GetDouble() > 0.0)
575  multipleOf_.CopyFrom(*v, *allocator_);
576  }
577 
579  AllocatorType::Free(enum_);
580  if (properties_) {
581  for (SizeType i = 0; i < propertyCount_; i++)
582  properties_[i].~Property();
583  AllocatorType::Free(properties_);
584  }
585  if (patternProperties_) {
586  for (SizeType i = 0; i < patternPropertyCount_; i++)
587  patternProperties_[i].~PatternProperty();
588  AllocatorType::Free(patternProperties_);
589  }
590  AllocatorType::Free(itemsTuple_);
591 #if RAPIDJSON_SCHEMA_HAS_REGEX
592  if (pattern_) {
593  pattern_->~RegexType();
594  AllocatorType::Free(pattern_);
595  }
596 #endif
597  }
598 
599  bool BeginValue(Context& context) const {
600  if (context.inArray) {
601  if (uniqueItems_)
602  context.valueUniqueness = true;
603 
604  if (itemsList_)
605  context.valueSchema = itemsList_;
606  else if (itemsTuple_) {
607  if (context.arrayElementIndex < itemsTupleCount_)
608  context.valueSchema = itemsTuple_[context.arrayElementIndex];
609  else if (additionalItemsSchema_)
610  context.valueSchema = additionalItemsSchema_;
611  else if (additionalItems_)
612  context.valueSchema = typeless_;
613  else
614  RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
615  }
616  else
617  context.valueSchema = typeless_;
618 
619  context.arrayElementIndex++;
620  }
621  return true;
622  }
623 
624  RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
625  if (context.patternPropertiesValidatorCount > 0) {
626  bool otherValid = false;
628  if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
629  otherValid = context.patternPropertiesValidators[--count]->IsValid();
630 
631  bool patternValid = true;
632  for (SizeType i = 0; i < count; i++)
633  if (!context.patternPropertiesValidators[i]->IsValid()) {
634  patternValid = false;
635  break;
636  }
637 
638  if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
639  if (!patternValid)
640  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
641  }
642  else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
643  if (!patternValid || !otherValid)
644  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
645  }
646  else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
647  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
648  }
649 
650  if (enum_) {
651  const uint64_t h = context.factory.GetHashCode(context.hasher);
652  for (SizeType i = 0; i < enumCount_; i++)
653  if (enum_[i] == h)
654  goto foundEnum;
655  RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
656  foundEnum:;
657  }
658 
659  if (allOf_.schemas)
660  for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
661  if (!context.validators[i]->IsValid())
662  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
663 
664  if (anyOf_.schemas) {
665  for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
666  if (context.validators[i]->IsValid())
667  goto foundAny;
668  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
669  foundAny:;
670  }
671 
672  if (oneOf_.schemas) {
673  bool oneValid = false;
674  for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
675  if (context.validators[i]->IsValid()) {
676  if (oneValid)
677  RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
678  else
679  oneValid = true;
680  }
681  if (!oneValid)
682  RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
683  }
684 
685  if (not_ && context.validators[notValidatorIndex_]->IsValid())
686  RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
687 
688  return true;
689  }
690 
691  bool Null(Context& context) const {
692  if (!(type_ & (1 << kNullSchemaType)))
693  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
694  return CreateParallelValidator(context);
695  }
696 
697  bool Bool(Context& context, bool) const {
698  if (!(type_ & (1 << kBooleanSchemaType)))
699  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
700  return CreateParallelValidator(context);
701  }
702 
703  bool Int(Context& context, int i) const {
704  if (!CheckInt(context, i))
705  return false;
706  return CreateParallelValidator(context);
707  }
708 
709  bool Uint(Context& context, unsigned u) const {
710  if (!CheckUint(context, u))
711  return false;
712  return CreateParallelValidator(context);
713  }
714 
715  bool Int64(Context& context, int64_t i) const {
716  if (!CheckInt(context, i))
717  return false;
718  return CreateParallelValidator(context);
719  }
720 
721  bool Uint64(Context& context, uint64_t u) const {
722  if (!CheckUint(context, u))
723  return false;
724  return CreateParallelValidator(context);
725  }
726 
727  bool Double(Context& context, double d) const {
728  if (!(type_ & (1 << kNumberSchemaType)))
729  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
730 
731  if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
732  return false;
733 
734  if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
735  return false;
736 
737  if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
738  return false;
739 
740  return CreateParallelValidator(context);
741  }
742 
743  bool String(Context& context, const Ch* str, SizeType length, bool) const {
744  if (!(type_ & (1 << kStringSchemaType)))
745  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
746 
747  if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
748  SizeType count;
749  if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
750  if (count < minLength_)
751  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
752  if (count > maxLength_)
753  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
754  }
755  }
756 
757  if (pattern_ && !IsPatternMatch(pattern_, str, length))
758  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
759 
760  return CreateParallelValidator(context);
761  }
762 
763  bool StartObject(Context& context) const {
764  if (!(type_ & (1 << kObjectSchemaType)))
765  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
766 
767  if (hasDependencies_ || hasRequired_) {
768  context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
769  std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
770  }
771 
772  if (patternProperties_) { // pre-allocate schema array
773  SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
774  context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
775  context.patternPropertiesSchemaCount = 0;
776  std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
777  }
778 
779  return CreateParallelValidator(context);
780  }
781 
782  bool Key(Context& context, const Ch* str, SizeType len, bool) const {
783  if (patternProperties_) {
784  context.patternPropertiesSchemaCount = 0;
785  for (SizeType i = 0; i < patternPropertyCount_; i++)
786  if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
787  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
788  context.valueSchema = typeless_;
789  }
790  }
791 
792  SizeType index;
793  if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
794  if (context.patternPropertiesSchemaCount > 0) {
795  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
796  context.valueSchema = typeless_;
797  context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
798  }
799  else
800  context.valueSchema = properties_[index].schema;
801 
802  if (context.propertyExist)
803  context.propertyExist[index] = true;
804 
805  return true;
806  }
807 
808  if (additionalPropertiesSchema_) {
809  if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
810  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
811  context.valueSchema = typeless_;
812  context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
813  }
814  else
815  context.valueSchema = additionalPropertiesSchema_;
816  return true;
817  }
818  else if (additionalProperties_) {
819  context.valueSchema = typeless_;
820  return true;
821  }
822 
823  if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
824  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
825 
826  return true;
827  }
828 
829  bool EndObject(Context& context, SizeType memberCount) const {
830  if (hasRequired_)
831  for (SizeType index = 0; index < propertyCount_; index++)
832  if (properties_[index].required)
833  if (!context.propertyExist[index])
834  RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
835 
836  if (memberCount < minProperties_)
837  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
838 
839  if (memberCount > maxProperties_)
840  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
841 
842  if (hasDependencies_) {
843  for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
844  if (context.propertyExist[sourceIndex]) {
845  if (properties_[sourceIndex].dependencies) {
846  for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
847  if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
848  RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
849  }
850  else if (properties_[sourceIndex].dependenciesSchema)
851  if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
852  RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
853  }
854  }
855 
856  return true;
857  }
858 
859  bool StartArray(Context& context) const {
860  if (!(type_ & (1 << kArraySchemaType)))
861  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
862 
863  context.arrayElementIndex = 0;
864  context.inArray = true;
865 
866  return CreateParallelValidator(context);
867  }
868 
869  bool EndArray(Context& context, SizeType elementCount) const {
870  context.inArray = false;
871 
872  if (elementCount < minItems_)
873  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
874 
875  if (elementCount > maxItems_)
876  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
877 
878  return true;
879  }
880 
881  // Generate functions for string literal according to Ch
882 #define RAPIDJSON_STRING_(name, ...) \
883  static const ValueType& Get##name##String() {\
884  static const Ch s[] = { __VA_ARGS__, '\0' };\
885  static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
886  return v;\
887  }
888 
889  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
890  RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
891  RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
892  RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
893  RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
894  RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
895  RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
896  RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
897  RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
898  RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
899  RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
900  RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
901  RAPIDJSON_STRING_(Not, 'n', 'o', 't')
902  RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
903  RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
904  RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
905  RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
906  RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
907  RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
908  RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
909  RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
910  RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
911  RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
912  RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
913  RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
914  RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
915  RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
916  RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
917  RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
918  RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
919  RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
920  RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
921  RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
922 
923 #undef RAPIDJSON_STRING_
924 
925 private:
934  kTotalSchemaType
935  };
936 
937 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
939 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
940  typedef std::basic_regex<Ch> RegexType;
941 #else
942  typedef char RegexType;
943 #endif
944 
945  struct SchemaArray {
946  SchemaArray() : schemas(), count() {}
947  ~SchemaArray() { AllocatorType::Free(schemas); }
948  const SchemaType** schemas;
949  SizeType begin; // begin index of context.validators
951  };
952 
953  template <typename V1, typename V2>
954  void AddUniqueElement(V1& a, const V2& v) {
955  for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
956  if (*itr == v)
957  return;
958  V1 c(v, *allocator_);
959  a.PushBack(c, *allocator_);
960  }
961 
962  static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
963  typename ValueType::ConstMemberIterator itr = value.FindMember(name);
964  return itr != value.MemberEnd() ? &(itr->value) : 0;
965  }
966 
967  static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
968  if (const ValueType* v = GetMember(value, name))
969  if (v->IsBool())
970  out = v->GetBool();
971  }
972 
973  static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
974  if (const ValueType* v = GetMember(value, name))
975  if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
976  out = static_cast<SizeType>(v->GetUint64());
977  }
978 
979  void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
980  if (const ValueType* v = GetMember(value, name)) {
981  if (v->IsArray() && v->Size() > 0) {
982  PointerType q = p.Append(name, allocator_);
983  out.count = v->Size();
984  out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
985  memset(out.schemas, 0, sizeof(Schema*)* out.count);
986  for (SizeType i = 0; i < out.count; i++)
987  schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
988  out.begin = validatorCount_;
989  validatorCount_ += out.count;
990  }
991  }
992  }
993 
994 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
995  template <typename ValueType>
996  RegexType* CreatePattern(const ValueType& value) {
997  if (value.IsString()) {
998  RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
999  if (!r->IsValid()) {
1000  r->~RegexType();
1001  AllocatorType::Free(r);
1002  r = 0;
1003  }
1004  return r;
1005  }
1006  return 0;
1007  }
1008 
1009  static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1010  GenericRegexSearch<RegexType> rs(*pattern);
1011  return rs.Search(str);
1012  }
1013 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1014  template <typename ValueType>
1015  RegexType* CreatePattern(const ValueType& value) {
1016  if (value.IsString())
1017  try {
1018  return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1019  }
1020  catch (const std::regex_error&) {
1021  }
1022  return 0;
1023  }
1024 
1025  static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
1026  std::match_results<const Ch*> r;
1027  return std::regex_search(str, str + length, r, *pattern);
1028  }
1029 #else
1030  template <typename ValueType>
1031  RegexType* CreatePattern(const ValueType&) { return 0; }
1032 
1033  static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
1034 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1035 
1036  void AddType(const ValueType& type) {
1037  if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1038  else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1039  else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1040  else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1041  else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1042  else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1043  else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1044  }
1045 
1046  bool CreateParallelValidator(Context& context) const {
1047  if (enum_ || context.arrayUniqueness)
1048  context.hasher = context.factory.CreateHasher();
1049 
1050  if (validatorCount_) {
1051  RAPIDJSON_ASSERT(context.validators == 0);
1052  context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
1053  context.validatorCount = validatorCount_;
1054 
1055  if (allOf_.schemas)
1056  CreateSchemaValidators(context, allOf_);
1057 
1058  if (anyOf_.schemas)
1059  CreateSchemaValidators(context, anyOf_);
1060 
1061  if (oneOf_.schemas)
1062  CreateSchemaValidators(context, oneOf_);
1063 
1064  if (not_)
1065  context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1066 
1067  if (hasSchemaDependencies_) {
1068  for (SizeType i = 0; i < propertyCount_; i++)
1069  if (properties_[i].dependenciesSchema)
1070  context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1071  }
1072  }
1073 
1074  return true;
1075  }
1076 
1077  void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
1078  for (SizeType i = 0; i < schemas.count; i++)
1079  context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1080  }
1081 
1082  // O(n)
1083  bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
1084  SizeType len = name.GetStringLength();
1085  const Ch* str = name.GetString();
1086  for (SizeType index = 0; index < propertyCount_; index++)
1087  if (properties_[index].name.GetStringLength() == len &&
1088  (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1089  {
1090  *outIndex = index;
1091  return true;
1092  }
1093  return false;
1094  }
1095 
1096  bool CheckInt(Context& context, int64_t i) const {
1097  if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1098  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1099 
1100  if (!minimum_.IsNull()) {
1101  if (minimum_.IsInt64()) {
1102  if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1103  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1104  }
1105  else if (minimum_.IsUint64()) {
1106  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
1107  }
1108  else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1109  return false;
1110  }
1111 
1112  if (!maximum_.IsNull()) {
1113  if (maximum_.IsInt64()) {
1114  if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1115  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1116  }
1117  else if (maximum_.IsUint64()) { }
1118  /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1119  else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1120  return false;
1121  }
1122 
1123  if (!multipleOf_.IsNull()) {
1124  if (multipleOf_.IsUint64()) {
1125  if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1126  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1127  }
1128  else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1129  return false;
1130  }
1131 
1132  return true;
1133  }
1134 
1135  bool CheckUint(Context& context, uint64_t i) const {
1136  if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1137  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1138 
1139  if (!minimum_.IsNull()) {
1140  if (minimum_.IsUint64()) {
1141  if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1142  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1143  }
1144  else if (minimum_.IsInt64())
1145  /* do nothing */; // i >= 0 > minimum.Getint64()
1146  else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1147  return false;
1148  }
1149 
1150  if (!maximum_.IsNull()) {
1151  if (maximum_.IsUint64()) {
1152  if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1153  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1154  }
1155  else if (maximum_.IsInt64())
1156  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
1157  else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1158  return false;
1159  }
1160 
1161  if (!multipleOf_.IsNull()) {
1162  if (multipleOf_.IsUint64()) {
1163  if (i % multipleOf_.GetUint64() != 0)
1164  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1165  }
1166  else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1167  return false;
1168  }
1169 
1170  return true;
1171  }
1172 
1173  bool CheckDoubleMinimum(Context& context, double d) const {
1174  if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
1175  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1176  return true;
1177  }
1178 
1179  bool CheckDoubleMaximum(Context& context, double d) const {
1180  if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
1181  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1182  return true;
1183  }
1184 
1185  bool CheckDoubleMultipleOf(Context& context, double d) const {
1186  double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1187  double q = std::floor(a / b);
1188  double r = a - q * b;
1189  if (r > 0.0)
1190  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1191  return true;
1192  }
1193 
1194  struct Property {
1195  Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1196  ~Property() { AllocatorType::Free(dependencies); }
1197  SValue name;
1198  const SchemaType* schema;
1199  const SchemaType* dependenciesSchema;
1202  bool required;
1203  };
1204 
1206  PatternProperty() : schema(), pattern() {}
1208  if (pattern) {
1209  pattern->~RegexType();
1210  AllocatorType::Free(pattern);
1211  }
1212  }
1213  const SchemaType* schema;
1214  RegexType* pattern;
1215  };
1216 
1217  AllocatorType* allocator_;
1218  const SchemaType* typeless_;
1224  const SchemaType* not_;
1225  unsigned type_; // bitmask of kSchemaType
1228 
1230  const SchemaType* additionalPropertiesSchema_;
1240 
1241  const SchemaType* additionalItemsSchema_;
1242  const SchemaType* itemsList_;
1243  const SchemaType** itemsTuple_;
1249 
1250  RegexType* pattern_;
1253 
1254  SValue minimum_;
1255  SValue maximum_;
1256  SValue multipleOf_;
1259 };
1260 
1261 template<typename Stack, typename Ch>
1262 struct TokenHelper {
1263  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1264  *documentStack.template Push<Ch>() = '/';
1265  char buffer[21];
1266  size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1267  for (size_t i = 0; i < length; i++)
1268  *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
1269  }
1270 };
1271 
1272 // Partial specialized version for char to prevent buffer copying.
1273 template <typename Stack>
1274 struct TokenHelper<Stack, char> {
1275  RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
1276  if (sizeof(SizeType) == 4) {
1277  char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
1278  *buffer++ = '/';
1279  const char* end = internal::u32toa(index, buffer);
1280  documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
1281  }
1282  else {
1283  char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
1284  *buffer++ = '/';
1285  const char* end = internal::u64toa(index, buffer);
1286  documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
1287  }
1288  }
1289 };
1290 
1291 } // namespace internal
1292 
1294 // IGenericRemoteSchemaDocumentProvider
1295 
1296 template <typename SchemaDocumentType>
1298 public:
1299  typedef typename SchemaDocumentType::Ch Ch;
1300 
1302  virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1303 };
1304 
1306 // GenericSchemaDocument
1307 
1309 
1317 template <typename ValueT, typename Allocator = CrtAllocator>
1318 class GenericSchemaDocument {
1319 public:
1320  typedef ValueT ValueType;
1322  typedef Allocator AllocatorType;
1323  typedef typename ValueType::EncodingType EncodingType;
1324  typedef typename EncodingType::Ch Ch;
1328  template <typename, typename, typename>
1330 
1332 
1339  explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1340  remoteProvider_(remoteProvider),
1341  allocator_(allocator),
1342  ownAllocator_(),
1343  root_(),
1344  typeless_(),
1345  schemaMap_(allocator, kInitialSchemaMapSize),
1346  schemaRef_(allocator, kInitialSchemaRefSize)
1347  {
1348  if (!allocator_)
1349  ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
1350 
1351  typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1352  new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
1353 
1354  // Generate root schema, it will call CreateSchema() to create sub-schemas,
1355  // And call AddRefSchema() if there are $ref.
1356  CreateSchemaRecursive(&root_, PointerType(), document, document);
1357 
1358  // Resolve $ref
1359  while (!schemaRef_.Empty()) {
1360  SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1361  if (const SchemaType* s = GetSchema(refEntry->target)) {
1362  if (refEntry->schema)
1363  *refEntry->schema = s;
1364 
1365  // Create entry in map if not exist
1366  if (!GetSchema(refEntry->source)) {
1367  new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
1368  }
1369  }
1370  else if (refEntry->schema)
1371  *refEntry->schema = typeless_;
1372 
1373  refEntry->~SchemaRefEntry();
1374  }
1375 
1376  RAPIDJSON_ASSERT(root_ != 0);
1377 
1378  schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
1379  }
1380 
1381 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1382  GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1384  remoteProvider_(rhs.remoteProvider_),
1385  allocator_(rhs.allocator_),
1386  ownAllocator_(rhs.ownAllocator_),
1387  root_(rhs.root_),
1388  typeless_(rhs.typeless_),
1389  schemaMap_(std::move(rhs.schemaMap_)),
1390  schemaRef_(std::move(rhs.schemaRef_))
1391  {
1392  rhs.remoteProvider_ = 0;
1393  rhs.allocator_ = 0;
1394  rhs.ownAllocator_ = 0;
1395  rhs.typeless_ = 0;
1396  }
1397 #endif
1398 
1401  while (!schemaMap_.Empty())
1402  schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1403 
1404  if (typeless_) {
1405  typeless_->~SchemaType();
1406  Allocator::Free(typeless_);
1407  }
1408 
1409  RAPIDJSON_DELETE(ownAllocator_);
1410  }
1411 
1413  const SchemaType& GetRoot() const { return *root_; }
1414 
1415 private:
1419  GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1420 
1422  SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1423  PointerType source;
1424  PointerType target;
1425  const SchemaType** schema;
1426  };
1427 
1428  struct SchemaEntry {
1429  SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1431  if (owned) {
1432  schema->~SchemaType();
1433  Allocator::Free(schema);
1434  }
1435  }
1436  PointerType pointer;
1437  SchemaType* schema;
1438  bool owned;
1439  };
1440 
1441  void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1442  if (schema)
1443  *schema = typeless_;
1444 
1445  if (v.GetType() == kObjectType) {
1446  const SchemaType* s = GetSchema(pointer);
1447  if (!s)
1448  CreateSchema(schema, pointer, v, document);
1449 
1450  for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1451  CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
1452  }
1453  else if (v.GetType() == kArrayType)
1454  for (SizeType i = 0; i < v.Size(); i++)
1455  CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
1456  }
1457 
1458  void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
1459  RAPIDJSON_ASSERT(pointer.IsValid());
1460  if (v.IsObject()) {
1461  if (!HandleRefSchema(pointer, schema, v, document)) {
1462  SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
1463  new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
1464  if (schema)
1465  *schema = s;
1466  }
1467  }
1468  }
1469 
1470  bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
1471  static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
1472  static const ValueType kRefValue(kRefString, 4);
1473 
1474  typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1475  if (itr == v.MemberEnd())
1476  return false;
1477 
1478  if (itr->value.IsString()) {
1479  SizeType len = itr->value.GetStringLength();
1480  if (len > 0) {
1481  const Ch* s = itr->value.GetString();
1482  SizeType i = 0;
1483  while (i < len && s[i] != '#') // Find the first #
1484  i++;
1485 
1486  if (i > 0) { // Remote reference, resolve immediately
1487  if (remoteProvider_) {
1488  if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1489  PointerType pointer(&s[i], len - i, allocator_);
1490  if (pointer.IsValid()) {
1491  if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1492  if (schema)
1493  *schema = sc;
1494  return true;
1495  }
1496  }
1497  }
1498  }
1499  }
1500  else if (s[i] == '#') { // Local reference, defer resolution
1501  PointerType pointer(&s[i], len - i, allocator_);
1502  if (pointer.IsValid()) {
1503  if (const ValueType* nv = pointer.Get(document))
1504  if (HandleRefSchema(source, schema, *nv, document))
1505  return true;
1506 
1507  new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1508  return true;
1509  }
1510  }
1511  }
1512  }
1513  return false;
1514  }
1515 
1516  const SchemaType* GetSchema(const PointerType& pointer) const {
1517  for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1518  if (pointer == target->pointer)
1519  return target->schema;
1520  return 0;
1521  }
1522 
1523  PointerType GetPointer(const SchemaType* schema) const {
1524  for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1525  if (schema == target->schema)
1526  return target->pointer;
1527  return PointerType();
1528  }
1529 
1530  const SchemaType* GetTypeless() const { return typeless_; }
1531 
1532  static const size_t kInitialSchemaMapSize = 64;
1533  static const size_t kInitialSchemaRefSize = 64;
1534 
1535  IRemoteSchemaDocumentProviderType* remoteProvider_;
1536  Allocator *allocator_;
1537  Allocator *ownAllocator_;
1538  const SchemaType* root_;
1539  SchemaType* typeless_;
1540  internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
1541  internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
1542 };
1543 
1548 
1550 // GenericSchemaValidator
1551 
1553 
1564 template <
1565  typename SchemaDocumentType,
1567  typename StateAllocator = CrtAllocator>
1568 class GenericSchemaValidator :
1569  public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1571 {
1572 public:
1573  typedef typename SchemaDocumentType::SchemaType SchemaType;
1574  typedef typename SchemaDocumentType::PointerType PointerType;
1575  typedef typename SchemaType::EncodingType EncodingType;
1576  typedef typename EncodingType::Ch Ch;
1577 
1579 
1586  const SchemaDocumentType& schemaDocument,
1587  StateAllocator* allocator = 0,
1588  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1589  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1590  :
1591  schemaDocument_(&schemaDocument),
1592  root_(schemaDocument.GetRoot()),
1593  stateAllocator_(allocator),
1594  ownStateAllocator_(0),
1595  schemaStack_(allocator, schemaStackCapacity),
1596  documentStack_(allocator, documentStackCapacity),
1597  outputHandler_(0),
1598  valid_(true)
1600  , depth_(0)
1601 #endif
1602  {
1603  }
1604 
1606 
1613  const SchemaDocumentType& schemaDocument,
1614  OutputHandler& outputHandler,
1615  StateAllocator* allocator = 0,
1616  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1617  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1618  :
1619  schemaDocument_(&schemaDocument),
1620  root_(schemaDocument.GetRoot()),
1621  stateAllocator_(allocator),
1622  ownStateAllocator_(0),
1623  schemaStack_(allocator, schemaStackCapacity),
1624  documentStack_(allocator, documentStackCapacity),
1625  outputHandler_(&outputHandler),
1626  valid_(true)
1628  , depth_(0)
1629 #endif
1630  {
1631  }
1632 
1635  Reset();
1636  RAPIDJSON_DELETE(ownStateAllocator_);
1637  }
1638 
1640  void Reset() {
1641  while (!schemaStack_.Empty())
1642  PopSchema();
1643  documentStack_.Clear();
1644  valid_ = true;
1645  }
1646 
1648  // Implementation of ISchemaValidator
1649  virtual bool IsValid() const { return valid_; }
1650 
1652  PointerType GetInvalidSchemaPointer() const {
1653  return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
1654  }
1655 
1657  const Ch* GetInvalidSchemaKeyword() const {
1658  return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1659  }
1660 
1662  PointerType GetInvalidDocumentPointer() const {
1663  return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1664  }
1665 
1666 #if RAPIDJSON_SCHEMA_VERBOSE
1667 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
1668 RAPIDJSON_MULTILINEMACRO_BEGIN\
1669  *documentStack_.template Push<Ch>() = '\0';\
1670  documentStack_.template Pop<Ch>(1);\
1671  internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
1672 RAPIDJSON_MULTILINEMACRO_END
1673 #else
1674 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
1675 #endif
1676 
1677 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
1678  if (!valid_) return false; \
1679  if (!BeginValue() || !CurrentSchema().method arg1) {\
1680  RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
1681  return valid_ = false;\
1682  }
1683 
1684 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
1685  for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
1686  if (context->hasher)\
1687  static_cast<HasherType*>(context->hasher)->method arg2;\
1688  if (context->validators)\
1689  for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
1690  static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
1691  if (context->patternPropertiesValidators)\
1692  for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
1693  static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
1694  }
1695 
1696 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
1697  return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
1698 
1699 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
1700  RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
1701  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
1702  RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
1703 
1704  bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
1705  bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
1706  bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
1707  bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
1708  bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
1709  bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
1710  bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
1711  bool RawNumber(const Ch* str, SizeType length, bool copy)
1712  { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1713  bool String(const Ch* str, SizeType length, bool copy)
1714  { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1715 
1716  bool StartObject() {
1717  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
1718  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
1719  return valid_ = !outputHandler_ || outputHandler_->StartObject();
1720  }
1721 
1722  bool Key(const Ch* str, SizeType len, bool copy) {
1723  if (!valid_) return false;
1724  AppendToken(str, len);
1725  if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
1726  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
1727  return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
1728  }
1729 
1730  bool EndObject(SizeType memberCount) {
1731  if (!valid_) return false;
1732  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
1733  if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
1734  RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
1735  }
1736 
1737  bool StartArray() {
1738  RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
1739  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
1740  return valid_ = !outputHandler_ || outputHandler_->StartArray();
1741  }
1742 
1743  bool EndArray(SizeType elementCount) {
1744  if (!valid_) return false;
1745  RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
1746  if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
1747  RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
1748  }
1749 
1750 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
1751 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
1752 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
1753 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
1754 
1755  // Implementation of ISchemaStateFactory<SchemaType>
1756  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
1757  return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
1759  depth_ + 1,
1760 #endif
1761  &GetStateAllocator());
1762  }
1763 
1764  virtual void DestroySchemaValidator(ISchemaValidator* validator) {
1765  GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
1767  StateAllocator::Free(v);
1768  }
1769 
1770  virtual void* CreateHasher() {
1771  return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
1772  }
1773 
1774  virtual uint64_t GetHashCode(void* hasher) {
1775  return static_cast<HasherType*>(hasher)->GetHashCode();
1776  }
1777 
1778  virtual void DestroryHasher(void* hasher) {
1779  HasherType* h = static_cast<HasherType*>(hasher);
1780  h->~HasherType();
1781  StateAllocator::Free(h);
1782  }
1783 
1784  virtual void* MallocState(size_t size) {
1785  return GetStateAllocator().Malloc(size);
1786  }
1787 
1788  virtual void FreeState(void* p) {
1789  StateAllocator::Free(p);
1790  }
1791 
1792 private:
1793  typedef typename SchemaType::Context Context;
1794  typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
1796 
1798  const SchemaDocumentType& schemaDocument,
1799  const SchemaType& root,
1801  unsigned depth,
1802 #endif
1803  StateAllocator* allocator = 0,
1804  size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1805  size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1806  :
1807  schemaDocument_(&schemaDocument),
1808  root_(root),
1809  stateAllocator_(allocator),
1810  ownStateAllocator_(0),
1811  schemaStack_(allocator, schemaStackCapacity),
1812  documentStack_(allocator, documentStackCapacity),
1813  outputHandler_(0),
1814  valid_(true)
1816  , depth_(depth)
1817 #endif
1818  {
1819  }
1820 
1821  StateAllocator& GetStateAllocator() {
1822  if (!stateAllocator_)
1823  stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
1824  return *stateAllocator_;
1825  }
1826 
1827  bool BeginValue() {
1828  if (schemaStack_.Empty())
1829  PushSchema(root_);
1830  else {
1831  if (CurrentContext().inArray)
1832  internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
1833 
1834  if (!CurrentSchema().BeginValue(CurrentContext()))
1835  return false;
1836 
1837  SizeType count = CurrentContext().patternPropertiesSchemaCount;
1838  const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
1839  typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
1840  bool valueUniqueness = CurrentContext().valueUniqueness;
1841  RAPIDJSON_ASSERT(CurrentContext().valueSchema);
1842  PushSchema(*CurrentContext().valueSchema);
1843 
1844  if (count > 0) {
1845  CurrentContext().objectPatternValidatorType = patternValidatorType;
1846  ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
1847  SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
1848  va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
1849  for (SizeType i = 0; i < count; i++)
1850  va[validatorCount++] = CreateSchemaValidator(*sa[i]);
1851  }
1852 
1853  CurrentContext().arrayUniqueness = valueUniqueness;
1854  }
1855  return true;
1856  }
1857 
1858  bool EndValue() {
1859  if (!CurrentSchema().EndValue(CurrentContext()))
1860  return false;
1861 
1862 #if RAPIDJSON_SCHEMA_VERBOSE
1864  schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
1865 
1866  *documentStack_.template Push<Ch>() = '\0';
1867  documentStack_.template Pop<Ch>(1);
1868  internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
1869 #endif
1870 
1871  uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
1872 
1873  PopSchema();
1874 
1875  if (!schemaStack_.Empty()) {
1876  Context& context = CurrentContext();
1877  if (context.valueUniqueness) {
1878  HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
1879  if (!a)
1880  CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
1881  for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
1882  if (itr->GetUint64() == h)
1883  RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
1884  a->PushBack(h, GetStateAllocator());
1885  }
1886  }
1887 
1888  // Remove the last token of document pointer
1889  while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
1890  ;
1891 
1892  return true;
1893  }
1894 
1895  void AppendToken(const Ch* str, SizeType len) {
1896  documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
1897  *documentStack_.template PushUnsafe<Ch>() = '/';
1898  for (SizeType i = 0; i < len; i++) {
1899  if (str[i] == '~') {
1900  *documentStack_.template PushUnsafe<Ch>() = '~';
1901  *documentStack_.template PushUnsafe<Ch>() = '0';
1902  }
1903  else if (str[i] == '/') {
1904  *documentStack_.template PushUnsafe<Ch>() = '~';
1905  *documentStack_.template PushUnsafe<Ch>() = '1';
1906  }
1907  else
1908  *documentStack_.template PushUnsafe<Ch>() = str[i];
1909  }
1910  }
1911 
1912  RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
1913 
1914  RAPIDJSON_FORCEINLINE void PopSchema() {
1915  Context* c = schemaStack_.template Pop<Context>(1);
1916  if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
1917  a->~HashCodeArray();
1918  StateAllocator::Free(a);
1919  }
1920  c->~Context();
1921  }
1922 
1923  const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
1924  Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
1925  const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
1926 
1927  static const size_t kDefaultSchemaStackCapacity = 1024;
1928  static const size_t kDefaultDocumentStackCapacity = 256;
1929  const SchemaDocumentType* schemaDocument_;
1930  const SchemaType& root_;
1931  StateAllocator* stateAllocator_;
1932  StateAllocator* ownStateAllocator_;
1935  OutputHandler* outputHandler_;
1936  bool valid_;
1937 #if RAPIDJSON_SCHEMA_VERBOSE
1938  unsigned depth_;
1939 #endif
1940 };
1941 
1943 
1945 // SchemaValidatingReader
1946 
1948 
1957 template <
1958  unsigned parseFlags,
1959  typename InputStream,
1960  typename SourceEncoding,
1961  typename SchemaDocumentType = SchemaDocument,
1962  typename StackAllocator = CrtAllocator>
1964 public:
1965  typedef typename SchemaDocumentType::PointerType PointerType;
1966  typedef typename InputStream::Ch Ch;
1967 
1969 
1973  SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
1974 
1975  template <typename Handler>
1976  bool operator()(Handler& handler) {
1979  parseResult_ = reader.template Parse<parseFlags>(is_, validator);
1980 
1981  isValid_ = validator.IsValid();
1982  if (isValid_) {
1983  invalidSchemaPointer_ = PointerType();
1984  invalidSchemaKeyword_ = 0;
1985  invalidDocumentPointer_ = PointerType();
1986  }
1987  else {
1988  invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
1989  invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
1990  invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
1991  }
1992 
1993  return parseResult_;
1994  }
1995 
1996  const ParseResult& GetParseResult() const { return parseResult_; }
1997  bool IsValid() const { return isValid_; }
1998  const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
1999  const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
2000  const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
2001 
2002 private:
2003  InputStream& is_;
2004  const SchemaDocumentType& sd_;
2005 
2010  bool isValid_;
2011 };
2012 
2014 RAPIDJSON_DIAG_POP
2015 
2016 #endif // RAPIDJSON_SCHEMA_H_
bool StartObject()
Definition: schema.h:195
d
bool hasRequired_
Definition: schema.h:1238
Encoding::Ch Ch
Definition: schema.h:167
SizeType enumCount_
Definition: schema.h:1220
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Definition: schema.h:782
SchemaDocumentType::Ch Ch
Definition: schema.h:1299
char * u64toa(uint64_t value, char *buffer)
Definition: itoa.h:123
Allocator * ownAllocator_
Definition: schema.h:1537
const CharType(& source)[N]
Definition: pointer.h:1144
SchemaArray allOf_
Definition: schema.h:1221
SizeType patternPropertyCount_
Definition: schema.h:1232
SizeType minProperties_
Definition: schema.h:1234
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
Definition: schema.h:1321
const SchemaType ** patternPropertiesSchemas
Definition: schema.h:323
SchemaDocumentType::PointerType PointerType
Definition: schema.h:1574
bool RawNumber(const Ch *str, SizeType len, bool)
Definition: schema.h:185
ParseResult parseResult_
Definition: schema.h:2006
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:389
void CreateSchemaRecursive(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document)
Definition: schema.h:1441
virtual void DestroySchemaValidator(ISchemaValidator *validator)
Definition: schema.h:1764
bool WriteType(Type type)
Definition: schema.h:233
virtual bool IsValid() const =0
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:411
PointerType invalidDocumentPointer_
Definition: schema.h:2009
const Ch * invalidSchemaKeyword_
Definition: schema.h:2008
PointerType invalidSchemaPointer_
Definition: schema.h:2007
AllocatorType * allocator_
Definition: schema.h:1217
const SchemaType ** schemas
Definition: schema.h:948
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:294
static bool IsPatternMatch(const RegexType *pattern, const Ch *str, SizeType)
Definition: schema.h:1009
object
Definition: rapidjson.h:620
Default implementation of Handler.
Definition: fwd.h:85
const SchemaType * GetSchema(const PointerType &pointer) const
Definition: schema.h:1516
static void AssignIfExist(SizeType &out, const ValueType &value, const ValueType &name)
Definition: schema.h:973
bool operator()(Handler &handler)
Definition: schema.h:1976
const Ch * GetString() const
Definition: stringbuffer.h:73
JSON schema document.
Definition: fwd.h:136
GenericSchemaDocument(const ValueType &document, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
Definition: schema.h:1339
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:262
void AddUniqueElement(V1 &a, const V2 &v)
Definition: schema.h:954
Schema< SchemaDocumentType > SchemaType
Definition: schema.h:346
PatternValidatorType objectPatternValidatorType
Definition: schema.h:326
const SchemaType * typeless_
Definition: schema.h:1218
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:124
bool Int64(int64_t i)
Definition: schema.h:175
PatternProperty * patternProperties_
Definition: schema.h:1231
array
Definition: rapidjson.h:621
virtual void FreeState(void *p)
Definition: schema.h:1788
StateAllocator * stateAllocator_
Definition: schema.h:1931
SchemaDocumentType::PointerType PointerType
Definition: schema.h:342
SchemaDocumentType::SchemaType SchemaType
Definition: schema.h:1573
~GenericSchemaValidator()
Destructor.
Definition: schema.h:1634
const SchemaType * additionalItemsSchema_
Definition: schema.h:1241
bool StartArray()
Definition: schema.h:206
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
Definition: schema.h:1699
void AppendToken(const Ch *str, SizeType len)
Definition: schema.h:1895
InputStream & is_
Definition: schema.h:2003
Stack< Allocator > stack_
Definition: schema.h:254
XmlRpcServer s
virtual ~IGenericRemoteSchemaDocumentProvider()
Definition: schema.h:1301
SizeType maxProperties_
Definition: schema.h:1235
bool String(const Ch *str, SizeType length, bool copy)
Definition: schema.h:1713
A type-unsafe stack for storing different types of data.
Definition: stack.h:36
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:1973
SchemaType::EncodingType EncodingType
Definition: schema.h:1575
bool EndArray(SizeType elementCount)
Definition: schema.h:207
PatternValidatorType valuePatternValidatorType
Definition: schema.h:325
internal::Stack< Allocator > schemaRef_
Definition: schema.h:1541
const SchemaType * dependenciesSchema
Definition: schema.h:1199
StateAllocator * ownStateAllocator_
Definition: schema.h:1932
bool Double(double d)
Definition: schema.h:1710
bool IsValid() const
Definition: regex.h:133
bool Double(double d)
Definition: schema.h:177
false
Definition: rapidjson.h:618
const SchemaType * GetTypeless() const
Definition: schema.h:1530
SizeType notValidatorIndex_
Definition: schema.h:1227
IRemoteSchemaDocumentProviderType * remoteProvider_
Definition: schema.h:1535
bool EndArray(SizeType elementCount)
Definition: schema.h:1743
bool EndObject(Context &context, SizeType memberCount) const
Definition: schema.h:829
bool BeginValue(Context &context) const
Definition: schema.h:599
static const ValueType * GetMember(const ValueType &value, const ValueType &name)
Definition: schema.h:962
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:196
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
Definition: schema.h:169
const SchemaType * schema
Definition: schema.h:314
const SchemaType * valueSchema
Definition: schema.h:315
const SchemaType * itemsList_
Definition: schema.h:1242
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:116
const SchemaType ** itemsTuple_
Definition: schema.h:1243
SValue minimum_
Definition: schema.h:1254
SchemaType::ValueType ValueType
Definition: schema.h:264
Result of parsing (wraps ParseErrorCode)
Definition: error.h:106
bool Uint64(uint64_t u)
Definition: schema.h:176
SizeType itemsTupleCount_
Definition: schema.h:1244
internal::Stack< StateAllocator > documentStack_
stack to store the current path of validating document (Ch)
Definition: schema.h:1934
bool HandleRefSchema(const PointerType &source, const SchemaType **schema, const ValueType &v, const ValueType &document)
Definition: schema.h:1470
internal::Schema< GenericSchemaDocument > SchemaType
Definition: schema.h:1325
RAPIDJSON_FORCEINLINE void PopSchema()
Definition: schema.h:1914
void Reset()
Reset the internal states.
Definition: schema.h:1640
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:121
uint64_t * enum_
Definition: schema.h:1219
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, const SchemaType &root, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Definition: schema.h:1797
#define RAPIDJSON_STRING_(name,...)
Definition: schema.h:882
bool CreateParallelValidator(Context &context) const
Definition: schema.h:1046
unsigned type_
Definition: schema.h:1225
Allocator * allocator_
Definition: schema.h:1536
ISchemaValidator ** patternPropertiesValidators
Definition: schema.h:321
bool WriteBuffer(Type type, const void *data, size_t len)
Definition: schema.h:237
SizeType maxItems_
Definition: schema.h:1246
GenericValue< EncodingType, AllocatorType > SValue
Definition: schema.h:347
ISchemaValidator ** validators
Definition: schema.h:319
bool Bool(bool b)
Definition: schema.h:172
ValueType::EncodingType EncodingType
Definition: schema.h:343
void AssignIfExist(SchemaArray &out, SchemaDocumentType &schemaDocument, const PointerType &p, const ValueType &value, const ValueType &name, const ValueType &document)
Definition: schema.h:979
bool CheckDoubleMultipleOf(Context &context, double d) const
Definition: schema.h:1185
SchemaValidatorFactoryType & factory
Definition: schema.h:313
SizeType dependenciesValidatorIndex
Definition: schema.h:1200
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:599
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1263
bool IsValid() const
Definition: schema.h:216
bool Int64(int64_t i)
Definition: schema.h:1708
string
Definition: rapidjson.h:622
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: fwd.h:88
bool Uint64(Context &context, uint64_t u) const
Definition: schema.h:721
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &)=0
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
const SchemaType * additionalPropertiesSchema_
Definition: schema.h:1230
SchemaDocumentType::PointerType PointerType
Definition: schema.h:1965
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition: schema.h:1612
SizeType propertyCount_
Definition: schema.h:1233
PointerType GetPointer(const SchemaType *schema) const
Definition: schema.h:1523
OutputHandler * outputHandler_
Definition: schema.h:1935
SchemaValidationContext< SchemaDocumentType > Context
Definition: schema.h:345
SizeType patternPropertiesValidatorCount
Definition: schema.h:322
bool CheckUint(Context &context, uint64_t i) const
Definition: schema.h:1135
void CreateSchema(const SchemaType **schema, const PointerType &pointer, const ValueType &v, const ValueType &document)
Definition: schema.h:1458
SchemaArray anyOf_
Definition: schema.h:1222
bool IsValid() const
Definition: schema.h:1997
uint64_t GetHashCode() const
Definition: schema.h:218
const PointerType & GetInvalidSchemaPointer() const
Definition: schema.h:1998
bool Int(Context &context, int i) const
Definition: schema.h:703
const SchemaDocumentType * schemaDocument_
Definition: schema.h:1929
bool Key(const Ch *str, SizeType len, bool copy)
Definition: schema.h:1722
const SchemaType * not_
Definition: schema.h:1224
internal::Hasher< EncodingType, StateAllocator > HasherType
Definition: schema.h:1795
virtual ~ISchemaValidator()
Definition: schema.h:140
Context & CurrentContext()
Definition: schema.h:1924
unsigned __int64 uint64_t
Definition: stdint.h:136
bool CheckDoubleMaximum(Context &context, double d) const
Definition: schema.h:1179
const ParseResult & GetParseResult() const
Definition: schema.h:1996
virtual void * MallocState(size_t size)
Definition: schema.h:1784
InputStream::Ch Ch
Definition: schema.h:1966
const PointerType & GetInvalidDocumentPointer() const
Definition: schema.h:2000
bool Null()
Definition: schema.h:171
void CreateSchemaValidators(Context &context, const SchemaArray &schemas) const
Definition: schema.h:1077
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:1652
#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)
Definition: schema.h:117
const SchemaDocumentType & sd_
Definition: schema.h:2004
number
Definition: rapidjson.h:623
SizeType maxLength_
Definition: schema.h:1252
GenericSchemaDocument< Value > SchemaDocument
GenericSchemaDocument using Value type.
Definition: schema.h:1545
bool Double(Context &context, double d) const
Definition: schema.h:727
#define RAPIDJSON_SCHEMA_VERBOSE
Definition: schema.h:47
bool CheckInt(Context &context, int64_t i) const
Definition: schema.h:1096
bool Uint64(uint64_t u)
Definition: schema.h:1709
Allocator AllocatorType
Definition: schema.h:1322
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:603
SchemaEntry(const PointerType &p, SchemaType *s, bool o, Allocator *allocator)
Definition: schema.h:1429
char * u32toa(uint32_t value, char *buffer)
Definition: itoa.h:39
SchemaValidationContext(SchemaValidatorFactoryType &f, const SchemaType *s)
Definition: schema.h:273
bool CheckDoubleMinimum(Context &context, double d) const
Definition: schema.h:1173
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
Definition: schema.h:263
bool Uint(unsigned u)
Definition: schema.h:1707
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
Definition: schema.h:1677
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
Definition: schema.h:1684
virtual void * CreateHasher()
Definition: schema.h:1770
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1121
bool Search(InputStream &is)
Definition: regex.h:634
static uint64_t Hash(uint64_t h, uint64_t d)
Definition: schema.h:247
SchemaType * typeless_
Definition: schema.h:1539
virtual ~ISchemaStateFactory()
Definition: schema.h:150
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:1662
C-runtime library allocator.
Definition: allocators.h:62
SValue multipleOf_
Definition: schema.h:1256
StateAllocator & GetStateAllocator()
Definition: schema.h:1821
bool additionalItems_
Definition: schema.h:1247
virtual bool IsValid() const
Checks whether the current state is valid.
Definition: schema.h:1649
A helper class for parsing with validation.
Definition: schema.h:1963
Represents an in-memory output stream.
Definition: fwd.h:59
bool hasDependencies_
Definition: schema.h:1237
ValueType::EncodingType EncodingType
Definition: schema.h:1323
SchemaDocumentType::AllocatorType AllocatorType
Definition: schema.h:341
const SchemaType * schema
Definition: schema.h:1198
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:1657
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1222
bool String(const Ch *str, SizeType len, bool)
Definition: schema.h:190
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition: pointer.h:211
SchemaDocumentType::ValueType ValueType
Definition: schema.h:340
GenericValue< UTF8<>, StateAllocator > HashCodeArray
Definition: schema.h:1794
SchemaType::Context Context
Definition: schema.h:1793
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator)
Definition: schema.h:350
bool StartObject(Context &context) const
Definition: schema.h:763
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1413
Property * properties_
Definition: schema.h:1229
signed __int64 int64_t
Definition: stdint.h:135
union internal::Hasher::Number::U u
const SchemaType & root_
Definition: schema.h:1930
internal::Stack< Allocator > schemaMap_
Definition: schema.h:1540
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition: schema.h:1547
const SchemaType * schema
Definition: schema.h:1213
const SchemaType * root_
Root schema.
Definition: schema.h:1538
bool exclusiveMinimum_
Definition: schema.h:1257
virtual void * MallocState(size_t size)=0
SchemaRefEntry(const PointerType &s, const PointerType &t, const SchemaType **outSchema, Allocator *allocator)
Definition: schema.h:1422
true
Definition: rapidjson.h:619
bool additionalProperties_
Definition: schema.h:1236
EncodingType::Ch Ch
Definition: schema.h:1576
bool Int(int i)
Definition: schema.h:173
SizeType minItems_
Definition: schema.h:1245
internal::Stack< StateAllocator > schemaStack_
stack to store the current path of schema (BaseSchemaType *)
Definition: schema.h:1933
bool Int64(Context &context, int64_t i) const
Definition: schema.h:715
bool Int(int i)
Definition: schema.h:1706
bool StartArray(Context &context) const
Definition: schema.h:859
bool Null(Context &context) const
Definition: schema.h:691
bool EndArray(Context &context, SizeType elementCount) const
Definition: schema.h:869
RegexType * pattern_
Definition: schema.h:1250
SValue maximum_
Definition: schema.h:1255
bool FindPropertyIndex(const ValueType &name, SizeType *outIndex) const
Definition: schema.h:1083
bool uniqueItems_
Definition: schema.h:1248
const SchemaType & CurrentSchema() const
Definition: schema.h:1923
EncodingType::Ch Ch
Definition: schema.h:1324
internal::GenericRegex< EncodingType > RegexType
Definition: schema.h:938
virtual void * CreateHasher()=0
SizeType minLength_
Definition: schema.h:1251
bool EndObject(SizeType memberCount)
Definition: schema.h:197
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1400
const GenericPointer< typename T::ValueType > & pointer
Definition: pointer.h:1121
bool hasSchemaDependencies_
Definition: schema.h:1239
bool String(Context &context, const Ch *str, SizeType length, bool) const
Definition: schema.h:743
bool Bool(bool b)
Definition: schema.h:1705
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Definition: schema.h:624
bool exclusiveMaximum_
Definition: schema.h:1258
Type
Type of JSON value.
Definition: rapidjson.h:616
virtual uint64_t GetHashCode(void *hasher)
Definition: schema.h:1774
RegexType * CreatePattern(const ValueType &value)
Definition: schema.h:996
bool RawNumber(const Ch *str, SizeType length, bool copy)
Definition: schema.h:1711
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:1585
const Ch * GetInvalidSchemaKeyword() const
Definition: schema.h:1999
virtual uint64_t GetHashCode(void *hasher)=0
bool Uint(unsigned u)
Definition: schema.h:174
GenericSchemaValidator< SchemaDocument > SchemaValidator
Definition: schema.h:1942
bool WriteNumber(const Number &n)
Definition: schema.h:235
static void AssignIfExist(bool &out, const ValueType &value, const ValueType &name)
Definition: schema.h:967
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition: schema.h:1275
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
Definition: schema.h:1696
JSON Schema Validator.
Definition: fwd.h:145
virtual void DestroryHasher(void *hasher)
Definition: schema.h:1778
RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType &schema)
Definition: schema.h:1912
SizeType validatorCount_
Definition: schema.h:1226
bool Uint(Context &context, unsigned u) const
Definition: schema.h:709
void AddType(const ValueType &type)
Definition: schema.h:1036
bool Bool(Context &context, bool) const
Definition: schema.h:697
bool EndObject(SizeType memberCount)
Definition: schema.h:1730
null
Definition: rapidjson.h:617
SchemaArray oneOf_
Definition: schema.h:1223
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root)
Definition: schema.h:1756
EncodingType::Ch Ch
Definition: schema.h:344
const Context & CurrentContext() const
Definition: schema.h:1925
GenericPointer< ValueType, Allocator > PointerType
Definition: schema.h:1326


choreo_rapidjson
Author(s):
autogenerated on Thu Jul 18 2019 03:59:09