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