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


xbot_talker
Author(s): wangxiaoyun
autogenerated on Sat Oct 10 2020 03:27:54