schema.h
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 
70 RAPIDJSON_NAMESPACE_BEGIN
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 // Verbose Utilities
74 
75 #if RAPIDJSON_SCHEMA_VERBOSE
76 
77 namespace internal {
78 
79 inline void PrintInvalidKeyword(const char* keyword) {
80  printf("Fail keyword: %s\n", keyword);
81 }
82 
83 inline void PrintInvalidKeyword(const wchar_t* keyword) {
84  wprintf(L"Fail keyword: %ls\n", keyword);
85 }
86 
87 inline void PrintInvalidDocument(const char* document) {
88  printf("Fail document: %s\n\n", document);
89 }
90 
91 inline void PrintInvalidDocument(const wchar_t* document) {
92  wprintf(L"Fail document: %ls\n\n", document);
93 }
94 
95 inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
96  printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
97 }
98 
99 inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
100  wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
101 }
102 
103 } // namespace internal
104 
105 #endif // RAPIDJSON_SCHEMA_VERBOSE
106 
107 ///////////////////////////////////////////////////////////////////////////////
108 // RAPIDJSON_INVALID_KEYWORD_RETURN
109 
110 #if RAPIDJSON_SCHEMA_VERBOSE
111 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
112 #else
113 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
114 #endif
115 
116 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
117 RAPIDJSON_MULTILINEMACRO_BEGIN\
118  context.invalidKeyword = keyword.GetString();\
119  RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
120  return false;\
121 RAPIDJSON_MULTILINEMACRO_END
122 
123 ///////////////////////////////////////////////////////////////////////////////
124 // Forward declarations
125 
126 template <typename ValueType, typename Allocator>
127 class GenericSchemaDocument;
128 
129 namespace internal {
130 
131 template <typename SchemaDocumentType>
132 class Schema;
133 
134 ///////////////////////////////////////////////////////////////////////////////
135 // ISchemaValidator
136 
137 class ISchemaValidator {
138 public:
139  virtual ~ISchemaValidator() {}
140  virtual bool IsValid() const = 0;
141 };
142 
143 ///////////////////////////////////////////////////////////////////////////////
144 // ISchemaStateFactory
145 
146 template <typename SchemaType>
147 class ISchemaStateFactory {
148 public:
149  virtual ~ISchemaStateFactory() {}
150  virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
151  virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
152  virtual void* CreateHasher() = 0;
153  virtual uint64_t GetHashCode(void* hasher) = 0;
154  virtual void DestroryHasher(void* hasher) = 0;
155  virtual void* MallocState(size_t size) = 0;
156  virtual void FreeState(void* p) = 0;
157 };
158 
159 ///////////////////////////////////////////////////////////////////////////////
160 // IValidationErrorHandler
161 
162 template <typename SchemaType>
163 class IValidationErrorHandler {
164 public:
165  typedef typename SchemaType::Ch Ch;
166  typedef typename SchemaType::SValue SValue;
167 
168  virtual ~IValidationErrorHandler() {}
169 
170  virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
171  virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
172  virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
173  virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
174  virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
175  virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
176  virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
177  virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
178  virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
179 
180  virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
181  virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
182  virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
183 
184  virtual void DisallowedItem(SizeType index) = 0;
185  virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
186  virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
187  virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
188 
189  virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
190  virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
191  virtual void StartMissingProperties() = 0;
192  virtual void AddMissingProperty(const SValue& name) = 0;
193  virtual bool EndMissingProperties() = 0;
194  virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
195  virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
196 
197  virtual void StartDependencyErrors() = 0;
198  virtual void StartMissingDependentProperties() = 0;
199  virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
200  virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
201  virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
202  virtual bool EndDependencyErrors() = 0;
203 
204  virtual void DisallowedValue() = 0;
205  virtual void StartDisallowedType() = 0;
206  virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
207  virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
208  virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
209  virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
210  virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
211  virtual void Disallowed() = 0;
212 };
213 
214 
215 ///////////////////////////////////////////////////////////////////////////////
216 // Hasher
217 
218 // For comparison of compound value
219 template<typename Encoding, typename Allocator>
220 class Hasher {
221 public:
222  typedef typename Encoding::Ch Ch;
223 
224  Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
225 
226  bool Null() { return WriteType(kNullType); }
227  bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
228  bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
229  bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
230  bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
231  bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
232  bool Double(double d) {
233  Number n;
234  if (d < 0) n.u.i = static_cast<int64_t>(d);
235  else n.u.u = static_cast<uint64_t>(d);
236  n.d = d;
237  return WriteNumber(n);
238  }
239 
240  bool RawNumber(const Ch* str, SizeType len, bool) {
241  WriteBuffer(kNumberType, str, len * sizeof(Ch));
242  return true;
243  }
244 
245  bool String(const Ch* str, SizeType len, bool) {
246  WriteBuffer(kStringType, str, len * sizeof(Ch));
247  return true;
248  }
249 
250  bool StartObject() { return true; }
251  bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
252  bool EndObject(SizeType memberCount) {
253  uint64_t h = Hash(0, kObjectType);
254  uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
255  for (SizeType i = 0; i < memberCount; i++)
256  h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
257  *stack_.template Push<uint64_t>() = h;
258  return true;
259  }
260 
261  bool StartArray() { return true; }
262  bool EndArray(SizeType elementCount) {
263  uint64_t h = Hash(0, kArrayType);
264  uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
265  for (SizeType i = 0; i < elementCount; i++)
266  h = Hash(h, e[i]); // Use hash to achieve element order sensitive
267  *stack_.template Push<uint64_t>() = h;
268  return true;
269  }
270 
271  bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
272 
273  uint64_t GetHashCode() const {
274  RAPIDJSON_ASSERT(IsValid());
275  return *stack_.template Top<uint64_t>();
276  }
277 
278 private:
279  static const size_t kDefaultSize = 256;
280  struct Number {
281  union U {
282  uint64_t u;
283  int64_t i;
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 
302  static uint64_t Hash(uint64_t h, uint64_t d) {
303  static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
304  h ^= d;
305  h *= kPrime;
306  return h;
307  }
308 
309  Stack<Allocator> stack_;
310 };
311 
312 ///////////////////////////////////////////////////////////////////////////////
313 // SchemaValidationContext
314 
315 template <typename SchemaDocumentType>
316 struct SchemaValidationContext {
317  typedef Schema<SchemaDocumentType> SchemaType;
318  typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
319  typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
320  typedef typename SchemaType::ValueType ValueType;
321  typedef typename ValueType::Ch Ch;
322 
323  enum PatternValidatorType {
324  kPatternValidatorOnly,
325  kPatternValidatorWithProperty,
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 
351  ~SchemaValidationContext() {
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
377  ISchemaValidator** validators;
378  SizeType validatorCount;
379  ISchemaValidator** patternPropertiesValidators;
380  SizeType patternPropertiesValidatorCount;
381  const SchemaType** patternPropertiesSchemas;
382  SizeType patternPropertiesSchemaCount;
383  PatternValidatorType valuePatternValidatorType;
384  PatternValidatorType objectPatternValidatorType;
385  SizeType arrayElementIndex;
386  bool* propertyExist;
387  bool inArray;
388  bool valueUniqueness;
389  bool arrayUniqueness;
390 };
391 
392 ///////////////////////////////////////////////////////////////////////////////
393 // Schema
394 
395 template <typename SchemaDocumentType>
396 class Schema {
397 public:
398  typedef typename SchemaDocumentType::ValueType ValueType;
399  typedef typename SchemaDocumentType::AllocatorType AllocatorType;
400  typedef typename SchemaDocumentType::PointerType PointerType;
401  typedef typename ValueType::EncodingType EncodingType;
402  typedef typename EncodingType::Ch Ch;
403  typedef SchemaValidationContext<SchemaDocumentType> Context;
404  typedef Schema<SchemaDocumentType> SchemaType;
405  typedef GenericValue<EncodingType, AllocatorType> SValue;
406  typedef IValidationErrorHandler<Schema> ErrorHandler;
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 ValueType::ConstValueIterator ConstValueIterator;
447  typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
448 
449  if (!value.IsObject())
450  return;
451 
452  if (const ValueType* v = GetMember(value, GetTypeString())) {
453  type_ = 0;
454  if (v->IsString())
455  AddType(*v);
456  else if (v->IsArray())
457  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
458  AddType(*itr);
459  }
460 
461  if (const ValueType* v = GetMember(value, GetEnumString()))
462  if (v->IsArray() && v->Size() > 0) {
463  enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
464  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
465  typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
466  char buffer[256u + 24];
467  MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
468  EnumHasherType h(&hasherAllocator, 256);
469  itr->Accept(h);
470  enum_[enumCount_++] = h.GetHashCode();
471  }
472  }
473 
474  if (schemaDocument) {
475  AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
476  AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
477  AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
478  }
479 
480  if (const ValueType* v = GetMember(value, GetNotString())) {
481  schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
482  notValidatorIndex_ = validatorCount_;
483  validatorCount_++;
484  }
485 
486  // Object
487 
488  const ValueType* properties = GetMember(value, GetPropertiesString());
489  const ValueType* required = GetMember(value, GetRequiredString());
490  const ValueType* dependencies = GetMember(value, GetDependenciesString());
491  {
492  // Gather properties from properties/required/dependencies
493  SValue allProperties(kArrayType);
494 
495  if (properties && properties->IsObject())
496  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
497  AddUniqueElement(allProperties, itr->name);
498 
499  if (required && required->IsArray())
500  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
501  if (itr->IsString())
502  AddUniqueElement(allProperties, *itr);
503 
504  if (dependencies && dependencies->IsObject())
505  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
506  AddUniqueElement(allProperties, itr->name);
507  if (itr->value.IsArray())
508  for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
509  if (i->IsString())
510  AddUniqueElement(allProperties, *i);
511  }
512 
513  if (allProperties.Size() > 0) {
514  propertyCount_ = allProperties.Size();
515  properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
516  for (SizeType i = 0; i < propertyCount_; i++) {
517  new (&properties_[i]) Property();
518  properties_[i].name = allProperties[i];
519  properties_[i].schema = typeless_;
520  }
521  }
522  }
523 
524  if (properties && properties->IsObject()) {
525  PointerType q = p.Append(GetPropertiesString(), allocator_);
526  for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
527  SizeType index;
528  if (FindPropertyIndex(itr->name, &index))
529  schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
530  }
531  }
532 
533  if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
534  PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
535  patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
536  patternPropertyCount_ = 0;
537 
538  for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
539  new (&patternProperties_[patternPropertyCount_]) PatternProperty();
540  patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
541  schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
542  patternPropertyCount_++;
543  }
544  }
545 
546  if (required && required->IsArray())
547  for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
548  if (itr->IsString()) {
549  SizeType index;
550  if (FindPropertyIndex(*itr, &index)) {
551  properties_[index].required = true;
552  hasRequired_ = true;
553  }
554  }
555 
556  if (dependencies && dependencies->IsObject()) {
557  PointerType q = p.Append(GetDependenciesString(), allocator_);
558  hasDependencies_ = true;
559  for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
560  SizeType sourceIndex;
561  if (FindPropertyIndex(itr->name, &sourceIndex)) {
562  if (itr->value.IsArray()) {
563  properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
564  std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
565  for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
566  SizeType targetIndex;
567  if (FindPropertyIndex(*targetItr, &targetIndex))
568  properties_[sourceIndex].dependencies[targetIndex] = true;
569  }
570  }
571  else if (itr->value.IsObject()) {
572  hasSchemaDependencies_ = true;
573  schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
574  properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
575  validatorCount_++;
576  }
577  }
578  }
579  }
580 
581  if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
582  if (v->IsBool())
583  additionalProperties_ = v->GetBool();
584  else if (v->IsObject())
585  schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
586  }
587 
588  AssignIfExist(minProperties_, value, GetMinPropertiesString());
589  AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
590 
591  // Array
592  if (const ValueType* v = GetMember(value, GetItemsString())) {
593  PointerType q = p.Append(GetItemsString(), allocator_);
594  if (v->IsObject()) // List validation
595  schemaDocument->CreateSchema(&itemsList_, q, *v, document);
596  else if (v->IsArray()) { // Tuple validation
597  itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
598  SizeType index = 0;
599  for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
600  schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
601  }
602  }
603 
604  AssignIfExist(minItems_, value, GetMinItemsString());
605  AssignIfExist(maxItems_, value, GetMaxItemsString());
606 
607  if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
608  if (v->IsBool())
609  additionalItems_ = v->GetBool();
610  else if (v->IsObject())
611  schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
612  }
613 
614  AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
615 
616  // String
617  AssignIfExist(minLength_, value, GetMinLengthString());
618  AssignIfExist(maxLength_, value, GetMaxLengthString());
619 
620  if (const ValueType* v = GetMember(value, GetPatternString()))
621  pattern_ = CreatePattern(*v);
622 
623  // Number
624  if (const ValueType* v = GetMember(value, GetMinimumString()))
625  if (v->IsNumber())
626  minimum_.CopyFrom(*v, *allocator_);
627 
628  if (const ValueType* v = GetMember(value, GetMaximumString()))
629  if (v->IsNumber())
630  maximum_.CopyFrom(*v, *allocator_);
631 
632  AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
633  AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
634 
635  if (const ValueType* v = GetMember(value, GetMultipleOfString()))
636  if (v->IsNumber() && v->GetDouble() > 0.0)
637  multipleOf_.CopyFrom(*v, *allocator_);
638 
639  // Default
640  if (const ValueType* v = GetMember(value, GetDefaultValueString()))
641  if (v->IsString())
642  defaultValueLength_ = v->GetStringLength();
643 
644  }
645 
646  ~Schema() {
647  AllocatorType::Free(enum_);
648  if (properties_) {
649  for (SizeType i = 0; i < propertyCount_; i++)
650  properties_[i].~Property();
651  AllocatorType::Free(properties_);
652  }
653  if (patternProperties_) {
654  for (SizeType i = 0; i < patternPropertyCount_; i++)
655  patternProperties_[i].~PatternProperty();
656  AllocatorType::Free(patternProperties_);
657  }
658  AllocatorType::Free(itemsTuple_);
659 #if RAPIDJSON_SCHEMA_HAS_REGEX
660  if (pattern_) {
661  pattern_->~RegexType();
662  AllocatorType::Free(pattern_);
663  }
664 #endif
665  }
666 
667  const SValue& GetURI() const {
668  return uri_;
669  }
670 
671  const PointerType& GetPointer() const {
672  return pointer_;
673  }
674 
675  bool BeginValue(Context& context) const {
676  if (context.inArray) {
677  if (uniqueItems_)
678  context.valueUniqueness = true;
679 
680  if (itemsList_)
681  context.valueSchema = itemsList_;
682  else if (itemsTuple_) {
683  if (context.arrayElementIndex < itemsTupleCount_)
684  context.valueSchema = itemsTuple_[context.arrayElementIndex];
685  else if (additionalItemsSchema_)
686  context.valueSchema = additionalItemsSchema_;
687  else if (additionalItems_)
688  context.valueSchema = typeless_;
689  else {
690  context.error_handler.DisallowedItem(context.arrayElementIndex);
691  RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
692  }
693  }
694  else
695  context.valueSchema = typeless_;
696 
697  context.arrayElementIndex++;
698  }
699  return true;
700  }
701 
702  RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
703  if (context.patternPropertiesValidatorCount > 0) {
704  bool otherValid = false;
705  SizeType count = context.patternPropertiesValidatorCount;
706  if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
707  otherValid = context.patternPropertiesValidators[--count]->IsValid();
708 
709  bool patternValid = true;
710  for (SizeType i = 0; i < count; i++)
711  if (!context.patternPropertiesValidators[i]->IsValid()) {
712  patternValid = false;
713  break;
714  }
715 
716  if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
717  if (!patternValid) {
718  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
719  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
720  }
721  }
722  else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
723  if (!patternValid || !otherValid) {
724  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
725  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
726  }
727  }
728  else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
729  context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
730  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
731  }
732  }
733 
734  if (enum_) {
735  const uint64_t h = context.factory.GetHashCode(context.hasher);
736  for (SizeType i = 0; i < enumCount_; i++)
737  if (enum_[i] == h)
738  goto foundEnum;
739  context.error_handler.DisallowedValue();
740  RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
741  foundEnum:;
742  }
743 
744  if (allOf_.schemas)
745  for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
746  if (!context.validators[i]->IsValid()) {
747  context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
748  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
749  }
750 
751  if (anyOf_.schemas) {
752  for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
753  if (context.validators[i]->IsValid())
754  goto foundAny;
755  context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
756  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
757  foundAny:;
758  }
759 
760  if (oneOf_.schemas) {
761  bool oneValid = false;
762  for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
763  if (context.validators[i]->IsValid()) {
764  if (oneValid) {
765  context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
766  RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
767  } else
768  oneValid = true;
769  }
770  if (!oneValid) {
771  context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
772  RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
773  }
774  }
775 
776  if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777  context.error_handler.Disallowed();
778  RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
779  }
780 
781  return true;
782  }
783 
784  bool Null(Context& context) const {
785  if (!(type_ & (1 << kNullSchemaType))) {
786  DisallowedType(context, GetNullString());
787  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
788  }
789  return CreateParallelValidator(context);
790  }
791 
792  bool Bool(Context& context, bool) const {
793  if (!(type_ & (1 << kBooleanSchemaType))) {
794  DisallowedType(context, GetBooleanString());
795  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
796  }
797  return CreateParallelValidator(context);
798  }
799 
800  bool Int(Context& context, int i) const {
801  if (!CheckInt(context, i))
802  return false;
803  return CreateParallelValidator(context);
804  }
805 
806  bool Uint(Context& context, unsigned u) const {
807  if (!CheckUint(context, u))
808  return false;
809  return CreateParallelValidator(context);
810  }
811 
812  bool Int64(Context& context, int64_t i) const {
813  if (!CheckInt(context, i))
814  return false;
815  return CreateParallelValidator(context);
816  }
817 
818  bool Uint64(Context& context, uint64_t u) const {
819  if (!CheckUint(context, u))
820  return false;
821  return CreateParallelValidator(context);
822  }
823 
824  bool Double(Context& context, double d) const {
825  if (!(type_ & (1 << kNumberSchemaType))) {
826  DisallowedType(context, GetNumberString());
827  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
828  }
829 
830  if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
831  return false;
832 
833  if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
834  return false;
835 
836  if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
837  return false;
838 
839  return CreateParallelValidator(context);
840  }
841 
842  bool String(Context& context, const Ch* str, SizeType length, bool) const {
843  if (!(type_ & (1 << kStringSchemaType))) {
844  DisallowedType(context, GetStringString());
845  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
846  }
847 
848  if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
849  SizeType count;
850  if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
851  if (count < minLength_) {
852  context.error_handler.TooShort(str, length, minLength_);
853  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
854  }
855  if (count > maxLength_) {
856  context.error_handler.TooLong(str, length, maxLength_);
857  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
858  }
859  }
860  }
861 
862  if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863  context.error_handler.DoesNotMatch(str, length);
864  RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
865  }
866 
867  return CreateParallelValidator(context);
868  }
869 
870  bool StartObject(Context& context) const {
871  if (!(type_ & (1 << kObjectSchemaType))) {
872  DisallowedType(context, GetObjectString());
873  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
874  }
875 
876  if (hasDependencies_ || hasRequired_) {
877  context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
878  std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
879  }
880 
881  if (patternProperties_) { // pre-allocate schema array
882  SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
883  context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
884  context.patternPropertiesSchemaCount = 0;
885  std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
886  }
887 
888  return CreateParallelValidator(context);
889  }
890 
891  bool Key(Context& context, const Ch* str, SizeType len, bool) const {
892  if (patternProperties_) {
893  context.patternPropertiesSchemaCount = 0;
894  for (SizeType i = 0; i < patternPropertyCount_; i++)
895  if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
896  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
897  context.valueSchema = typeless_;
898  }
899  }
900 
901  SizeType index = 0;
902  if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
903  if (context.patternPropertiesSchemaCount > 0) {
904  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
905  context.valueSchema = typeless_;
906  context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
907  }
908  else
909  context.valueSchema = properties_[index].schema;
910 
911  if (context.propertyExist)
912  context.propertyExist[index] = true;
913 
914  return true;
915  }
916 
917  if (additionalPropertiesSchema_) {
918  if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
919  context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
920  context.valueSchema = typeless_;
921  context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
922  }
923  else
924  context.valueSchema = additionalPropertiesSchema_;
925  return true;
926  }
927  else if (additionalProperties_) {
928  context.valueSchema = typeless_;
929  return true;
930  }
931 
932  if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
933  context.error_handler.DisallowedProperty(str, len);
934  RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
935  }
936 
937  return true;
938  }
939 
940  bool EndObject(Context& context, SizeType memberCount) const {
941  if (hasRequired_) {
942  context.error_handler.StartMissingProperties();
943  for (SizeType index = 0; index < propertyCount_; index++)
944  if (properties_[index].required && !context.propertyExist[index])
945  if (properties_[index].schema->defaultValueLength_ == 0 )
946  context.error_handler.AddMissingProperty(properties_[index].name);
947  if (context.error_handler.EndMissingProperties())
948  RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
949  }
950 
951  if (memberCount < minProperties_) {
952  context.error_handler.TooFewProperties(memberCount, minProperties_);
953  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
954  }
955 
956  if (memberCount > maxProperties_) {
957  context.error_handler.TooManyProperties(memberCount, maxProperties_);
958  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
959  }
960 
961  if (hasDependencies_) {
962  context.error_handler.StartDependencyErrors();
963  for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
964  const Property& source = properties_[sourceIndex];
965  if (context.propertyExist[sourceIndex]) {
966  if (source.dependencies) {
967  context.error_handler.StartMissingDependentProperties();
968  for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
969  if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
970  context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
971  context.error_handler.EndMissingDependentProperties(source.name);
972  }
973  else if (source.dependenciesSchema) {
974  ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
975  if (!dependenciesValidator->IsValid())
976  context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
977  }
978  }
979  }
980  if (context.error_handler.EndDependencyErrors())
981  RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
982  }
983 
984  return true;
985  }
986 
987  bool StartArray(Context& context) const {
988  if (!(type_ & (1 << kArraySchemaType))) {
989  DisallowedType(context, GetArrayString());
990  RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
991  }
992 
993  context.arrayElementIndex = 0;
994  context.inArray = true;
995 
996  return CreateParallelValidator(context);
997  }
998 
999  bool EndArray(Context& context, SizeType elementCount) const {
1000  context.inArray = false;
1001 
1002  if (elementCount < minItems_) {
1003  context.error_handler.TooFewItems(elementCount, minItems_);
1004  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1005  }
1006 
1007  if (elementCount > maxItems_) {
1008  context.error_handler.TooManyItems(elementCount, maxItems_);
1009  RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1010  }
1011 
1012  return true;
1013  }
1014 
1015  // Generate functions for string literal according to Ch
1016 #define RAPIDJSON_STRING_(name, ...) \
1017  static const ValueType& Get##name##String() {\
1018  static const Ch s[] = { __VA_ARGS__, '\0' };\
1019  static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1020  return v;\
1021  }
1022 
1023  RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1024  RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1025  RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1026  RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1027  RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1028  RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1029  RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1030  RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1031  RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1032  RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1033  RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1034  RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1035  RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1036  RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1037  RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1038  RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1039  RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1040  RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1041  RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1042  RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1043  RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1044  RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1045  RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1046  RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1047  RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1048  RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1049  RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1050  RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1051  RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1052  RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1053  RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1054  RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1055  RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1056  RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1057 
1058 #undef RAPIDJSON_STRING_
1059 
1060 private:
1061  enum SchemaValueType {
1062  kNullSchemaType,
1063  kBooleanSchemaType,
1064  kObjectSchemaType,
1065  kArraySchemaType,
1066  kStringSchemaType,
1067  kNumberSchemaType,
1068  kIntegerSchemaType,
1069  kTotalSchemaType
1070  };
1071 
1072 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1073  typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1074 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1075  typedef std::basic_regex<Ch> RegexType;
1076 #else
1077  typedef char RegexType;
1078 #endif
1079 
1080  struct SchemaArray {
1081  SchemaArray() : schemas(), count() {}
1082  ~SchemaArray() { AllocatorType::Free(schemas); }
1083  const SchemaType** schemas;
1084  SizeType begin; // begin index of context.validators
1085  SizeType count;
1086  };
1087 
1088  template <typename V1, typename V2>
1089  void AddUniqueElement(V1& a, const V2& v) {
1090  for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1091  if (*itr == v)
1092  return;
1093  V1 c(v, *allocator_);
1094  a.PushBack(c, *allocator_);
1095  }
1096 
1097  static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
1098  typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1099  return itr != value.MemberEnd() ? &(itr->value) : 0;
1100  }
1101 
1102  static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
1103  if (const ValueType* v = GetMember(value, name))
1104  if (v->IsBool())
1105  out = v->GetBool();
1106  }
1107 
1108  static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
1109  if (const ValueType* v = GetMember(value, name))
1110  if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
1111  out = static_cast<SizeType>(v->GetUint64());
1112  }
1113 
1114  void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
1115  if (const ValueType* v = GetMember(value, name)) {
1116  if (v->IsArray() && v->Size() > 0) {
1117  PointerType q = p.Append(name, allocator_);
1118  out.count = v->Size();
1119  out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
1120  memset(out.schemas, 0, sizeof(Schema*)* out.count);
1121  for (SizeType i = 0; i < out.count; i++)
1122  schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1123  out.begin = validatorCount_;
1124  validatorCount_ += out.count;
1125  }
1126  }
1127  }
1128 
1129 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1130  template <typename ValueType>
1131  RegexType* CreatePattern(const ValueType& value) {
1132  if (value.IsString()) {
1133  RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1134  if (!r->IsValid()) {
1135  r->~RegexType();
1136  AllocatorType::Free(r);
1137  r = 0;
1138  }
1139  return r;
1140  }
1141  return 0;
1142  }
1143 
1144  static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1145  GenericRegexSearch<RegexType> rs(*pattern);
1146  return rs.Search(str);
1147  }
1148 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1149  template <typename ValueType>
1150  RegexType* CreatePattern(const ValueType& value) {
1151  if (value.IsString()) {
1152  RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1153  try {
1154  return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1155  }
1156  catch (const std::regex_error&) {
1157  AllocatorType::Free(r);
1158  }
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;
1379  SizeType dependenciesValidatorIndex;
1380  bool* dependencies;
1381  bool required;
1382  };
1383 
1384  struct PatternProperty {
1385  PatternProperty() : schema(), pattern() {}
1386  ~PatternProperty() {
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_;
1400  uint64_t* enum_;
1401  SizeType enumCount_;
1402  SchemaArray allOf_;
1403  SchemaArray anyOf_;
1404  SchemaArray oneOf_;
1405  const SchemaType* not_;
1406  unsigned type_; // bitmask of kSchemaType
1407  SizeType validatorCount_;
1408  SizeType notValidatorIndex_;
1409 
1410  Property* properties_;
1411  const SchemaType* additionalPropertiesSchema_;
1412  PatternProperty* patternProperties_;
1413  SizeType patternPropertyCount_;
1414  SizeType propertyCount_;
1415  SizeType minProperties_;
1416  SizeType maxProperties_;
1417  bool additionalProperties_;
1418  bool hasDependencies_;
1419  bool hasRequired_;
1420  bool hasSchemaDependencies_;
1421 
1422  const SchemaType* additionalItemsSchema_;
1423  const SchemaType* itemsList_;
1424  const SchemaType** itemsTuple_;
1425  SizeType itemsTupleCount_;
1426  SizeType minItems_;
1427  SizeType maxItems_;
1428  bool additionalItems_;
1429  bool uniqueItems_;
1430 
1431  RegexType* pattern_;
1432  SizeType minLength_;
1433  SizeType maxLength_;
1434 
1435  SValue minimum_;
1436  SValue maximum_;
1437  SValue multipleOf_;
1438  bool exclusiveMinimum_;
1439  bool exclusiveMaximum_;
1440 
1441  SizeType defaultValueLength_;
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 
1476 ///////////////////////////////////////////////////////////////////////////////
1477 // IGenericRemoteSchemaDocumentProvider
1478 
1479 template <typename SchemaDocumentType>
1480 class IGenericRemoteSchemaDocumentProvider {
1481 public:
1482  typedef typename SchemaDocumentType::Ch Ch;
1483 
1484  virtual ~IGenericRemoteSchemaDocumentProvider() {}
1485  virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
1486 };
1487 
1488 ///////////////////////////////////////////////////////////////////////////////
1489 // GenericSchemaDocument
1490 
1491 //! JSON schema document.
1492 /*!
1493  A JSON schema document is a compiled version of a JSON schema.
1494  It is basically a tree of internal::Schema.
1495 
1496  \note This is an immutable class (i.e. its instance cannot be modified after construction).
1497  \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
1498  \tparam Allocator Allocator type for allocating memory of this document.
1499 */
1500 template <typename ValueT, typename Allocator = CrtAllocator>
1501 class GenericSchemaDocument {
1502 public:
1503  typedef ValueT ValueType;
1504  typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
1505  typedef Allocator AllocatorType;
1506  typedef typename ValueType::EncodingType EncodingType;
1507  typedef typename EncodingType::Ch Ch;
1508  typedef internal::Schema<GenericSchemaDocument> SchemaType;
1509  typedef GenericPointer<ValueType, Allocator> PointerType;
1510  typedef GenericValue<EncodingType, Allocator> URIType;
1511  friend class internal::Schema<GenericSchemaDocument>;
1512  template <typename, typename, typename>
1513  friend class GenericSchemaValidator;
1514 
1515  //! Constructor.
1516  /*!
1517  Compile a JSON document into schema document.
1518 
1519  \param document A JSON document as source.
1520  \param uri The base URI of this schema document for purposes of violation reporting.
1521  \param uriLength Length of \c name, in code points.
1522  \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
1523  \param allocator An optional allocator instance for allocating memory. Can be null.
1524  */
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  //! Move constructor in C++11
1573  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 
1590  //! Destructor
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 
1605  //! Get the root schema.
1606  const SchemaType& GetRoot() const { return *root_; }
1607 
1608 private:
1609  //! Prohibit copying
1611  //! Prohibit assignment
1612  GenericSchemaDocument& operator=(const GenericSchemaDocument&);
1613 
1614  struct SchemaRefEntry {
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) {}
1623  ~SchemaEntry() {
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_; //!< Root schema.
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 
1739 //! GenericSchemaDocument using Value type.
1740 typedef GenericSchemaDocument<Value> SchemaDocument;
1741 //! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
1742 typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
1743 
1744 ///////////////////////////////////////////////////////////////////////////////
1745 // GenericSchemaValidator
1746 
1747 //! JSON Schema Validator.
1748 /*!
1749  A SAX style JSON schema validator.
1750  It uses a \c GenericSchemaDocument to validate SAX events.
1751  It delegates the incoming SAX events to an output handler.
1752  The default output handler does nothing.
1753  It can be reused multiple times by calling \c Reset().
1754 
1755  \tparam SchemaDocumentType Type of schema document.
1756  \tparam OutputHandler Type of output handler. Default handler does nothing.
1757  \tparam StateAllocator Allocator for storing the internal validation states.
1758 */
1759 template <
1760  typename SchemaDocumentType,
1761  typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
1762  typename StateAllocator = CrtAllocator>
1763 class GenericSchemaValidator :
1764  public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1765  public internal::ISchemaValidator,
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;
1774  typedef GenericStringRef<Ch> StringRefType;
1775  typedef GenericValue<EncodingType, StateAllocator> ValueType;
1776 
1777  //! Constructor without output handler.
1778  /*!
1779  \param schemaDocument The schema document to conform to.
1780  \param allocator Optional allocator for storing internal validation states.
1781  \param schemaStackCapacity Optional initial capacity of schema path stack.
1782  \param documentStackCapacity Optional initial capacity of document path stack.
1783  */
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)
1801 #if RAPIDJSON_SCHEMA_VERBOSE
1802  , depth_(0)
1803 #endif
1804  {
1805  }
1806 
1807  //! Constructor with output handler.
1808  /*!
1809  \param schemaDocument The schema document to conform to.
1810  \param allocator Optional allocator for storing internal validation states.
1811  \param schemaStackCapacity Optional initial capacity of schema path stack.
1812  \param documentStackCapacity Optional initial capacity of document path stack.
1813  */
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)
1832 #if RAPIDJSON_SCHEMA_VERBOSE
1833  , depth_(0)
1834 #endif
1835  {
1836  }
1837 
1838  //! Destructor.
1840  Reset();
1841  RAPIDJSON_DELETE(ownStateAllocator_);
1842  }
1843 
1844  //! Reset the internal states.
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 
1855  //! Checks whether the current state is valid.
1856  // Implementation of ISchemaValidator
1857  virtual bool IsValid() const { return valid_; }
1858 
1859  //! Gets the error object.
1860  ValueType& GetError() { return error_; }
1861  const ValueType& GetError() const { return error_; }
1862 
1863  //! Gets the JSON pointer pointed to the invalid schema.
1864  PointerType GetInvalidSchemaPointer() const {
1865  return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1866  }
1867 
1868  //! Gets the keyword of invalid schema.
1869  const Ch* GetInvalidSchemaKeyword() const {
1870  return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1871  }
1872 
1873  //! Gets the JSON pointer pointed to the invalid value.
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  }
1961  void StartMissingProperties() {
1962  currentError_.SetArray();
1963  }
1964  void AddMissingProperty(const SValue& name) {
1965  currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1966  }
1967  bool EndMissingProperties() {
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 
1986  void StartDependencyErrors() {
1987  currentError_.SetObject();
1988  }
1989  void StartMissingDependentProperties() {
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  }
2004  bool EndDependencyErrors() {
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 
2014  void DisallowedValue() {
2015  currentError_.SetObject();
2016  AddCurrentError(SchemaType::GetEnumString());
2017  }
2018  void StartDisallowedType() {
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);
2165  v->~GenericSchemaValidator();
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;
2194  typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2195 
2196  GenericSchemaValidator(
2197  const SchemaDocumentType& schemaDocument,
2198  const SchemaType& root,
2199  const char* basePath, size_t basePathSize,
2200 #if RAPIDJSON_SCHEMA_VERBOSE
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)
2218 #if RAPIDJSON_SCHEMA_VERBOSE
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
2268  GenericStringBuffer<EncodingType> sb;
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) {
2331  GenericStringBuffer<EncodingType> sb;
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_;
2404  internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
2405  internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
2406  OutputHandler* outputHandler_;
2407  ValueType error_;
2408  ValueType currentError_;
2409  ValueType missingDependents_;
2410  bool valid_;
2411 #if RAPIDJSON_SCHEMA_VERBOSE
2412  unsigned depth_;
2413 #endif
2414 };
2415 
2416 typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
2417 
2418 ///////////////////////////////////////////////////////////////////////////////
2419 // SchemaValidatingReader
2420 
2421 //! A helper class for parsing with validation.
2422 /*!
2423  This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
2424 
2425  \tparam parseFlags Combination of \ref ParseFlag.
2426  \tparam InputStream Type of input stream, implementing Stream concept.
2427  \tparam SourceEncoding Encoding of the input stream.
2428  \tparam SchemaDocumentType Type of schema document.
2429  \tparam StackAllocator Allocator type for stack.
2430 */
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 
2443  //! Constructor
2444  /*!
2445  \param is Input stream.
2446  \param sd Schema document.
2447  */
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 
2484  ParseResult parseResult_;
2485  PointerType invalidSchemaPointer_;
2486  const Ch* invalidSchemaKeyword_;
2487  PointerType invalidDocumentPointer_;
2488  StackAllocator allocator_;
2489  ValueType error_;
2490  bool isValid_;
2491 };
2492 
2493 RAPIDJSON_NAMESPACE_END
2494 RAPIDJSON_DIAG_POP
2495 
2496 #endif // RAPIDJSON_SCHEMA_H_
rapidjson::GenericValue< EncodingType, StateAllocator >
rapidjson::GenericSchemaValidator::GenericSchemaValidator
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
Allocator
Concept for allocating, resizing and freeing memory block.
rapidjson::GenericSchemaValidator::~GenericSchemaValidator
~GenericSchemaValidator()
Destructor.
Definition: schema.h:1839
rapidjson::Type
Type
Type of JSON value.
Definition: rapidjson.h:664
rapidjson::IGenericRemoteSchemaDocumentProvider
Definition: fwd.h:133
document.h
rapidjson::kTrueType
true
Definition: rapidjson.h:667
rapidjson::GenericSchemaValidator::GetInvalidSchemaKeyword
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:1869
rapidjson::kFalseType
false
Definition: rapidjson.h:666
rapidjson::GenericSchemaValidator::GenericSchemaValidator
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:1784
rapidjson::SchemaDocument
GenericSchemaDocument< Value, CrtAllocator > SchemaDocument
GenericSchemaDocument using Value type.
Definition: fwd.h:136
rapidjson::GenericSchemaDocument::~GenericSchemaDocument
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1591
rapidjson::kObjectType
object
Definition: rapidjson.h:668
rapidjson::SizeType
unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:384
rapidjson::GenericSchemaValidator::IsValid
virtual bool IsValid() const
Checks whether the current state is valid.
Definition: schema.h:1857
RAPIDJSON_ASSERT
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:406
rapidjson::kArrayType
array
Definition: rapidjson.h:669
rapidjson::GenericSchemaValidator::Reset
void Reset()
Reset the internal states.
Definition: schema.h:1845
rapidjson::kNullType
null
Definition: rapidjson.h:665
rapidjson::GenericReader
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: fwd.h:88
rapidjson::SchemaValidatingReader
A helper class for parsing with validation.
Definition: schema.h:2437
rapidjson::GenericSchemaDocument::GetRoot
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1606
rapidjson::kStringType
string
Definition: rapidjson.h:670
rapidjson::GenericPointer
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
RAPIDJSON_NEW
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition: rapidjson.h:647
RAPIDJSON_DELETE
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:651
rapidjson::IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition: fwd.h:139
rapidjson::GenericSchemaValidator::GetInvalidSchemaPointer
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:1864
rapidjson::SchemaValidatingReader::SchemaValidatingReader
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:2448
rapidjson::kNumberType
number
Definition: rapidjson.h:671
rapidjson::GenericSchemaDocument::GenericSchemaDocument
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
Definition: schema.h:1525
rapidjson::GenericSchemaValidator::GetError
ValueType & GetError()
Gets the error object.
Definition: schema.h:1860
rapidjson::GenericSchemaValidator::GetInvalidDocumentPointer
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:1874
RAPIDJSON_UINT64_C2
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:289
rapidjson::GenericSchemaDocument
JSON schema document.
Definition: fwd.h:136
rapidjson::GenericSchemaValidator
JSON Schema Validator.
Definition: fwd.h:145
Handler
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...