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


Copyright © 2005-2023 MAK Technologies. All Rights Reserved (www.mak.com)