schema.h Source File

schema.h Source File#

Composable Kernel: schema.h Source File
schema.h
Go to the documentation of this file.
1// Tencent is pleased to support the open source community by making RapidJSON available->
2//
3// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
4//
5// Licensed under the MIT License (the "License"); you may not use this file except
6// in compliance with the License-> You may obtain a copy of the License at
7//
8// http://opensource->org/licenses/MIT
9//
10// Unless required by applicable law or agreed to in writing, software distributed
11// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
13// specific language governing permissions and limitations under the License->
14
15#ifndef RAPIDJSON_SCHEMA_H_
16#define RAPIDJSON_SCHEMA_H_
17
18#include "document.h"
19#include "pointer.h"
20#include "stringbuffer.h"
21#include "error/en.h"
22#include "uri.h"
23#include <cmath> // abs, floor
24
25#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
26#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
27#endif
28
29#if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) || \
30 !(__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
31#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
32#endif
33
34#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
35#include "internal/regex.h"
36#elif RAPIDJSON_SCHEMA_USE_STDREGEX
37#include <regex>
38#endif
39
40#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
41#define RAPIDJSON_SCHEMA_HAS_REGEX 1
42#else
43#define RAPIDJSON_SCHEMA_HAS_REGEX 0
44#endif
45
46#ifndef RAPIDJSON_SCHEMA_VERBOSE
47#define RAPIDJSON_SCHEMA_VERBOSE 0
48#endif
49
50RAPIDJSON_DIAG_PUSH
51
52#if defined(__GNUC__)
53RAPIDJSON_DIAG_OFF(effc++)
54#endif
55
56#ifdef __clang__
57RAPIDJSON_DIAG_OFF(weak - vtables)
58RAPIDJSON_DIAG_OFF(exit - time - destructors)
59RAPIDJSON_DIAG_OFF(c++ 98 - compat - pedantic)
60RAPIDJSON_DIAG_OFF(variadic - macros)
61#elif defined(_MSC_VER)
62RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
63#endif
64
66
68// Verbose Utilities
69
70#if RAPIDJSON_SCHEMA_VERBOSE
71
72namespace internal {
73
74inline void PrintInvalidKeywordData(const char* keyword)
75{
76 printf(" Fail keyword: '%s'\n", keyword);
77}
78
79inline void PrintInvalidKeywordData(const wchar_t* keyword)
80{
81 wprintf(L" Fail keyword: '%ls'\n", keyword);
82}
83
84inline void PrintInvalidDocumentData(const char* document)
85{
86 printf(" Fail document: '%s'\n", document);
87}
88
89inline void PrintInvalidDocumentData(const wchar_t* document)
90{
91 wprintf(L" Fail document: '%ls'\n", document);
92}
93
94inline void PrintValidatorPointersData(const char* s, const char* d, unsigned depth)
95{
96 printf(" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4, " ", s, depth * 4, " ", d);
97}
98
99inline void PrintValidatorPointersData(const wchar_t* s, const wchar_t* d, unsigned depth)
100{
101 wprintf(L" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L" ", s, depth * 4, L" ", d);
102}
103
104inline void PrintSchemaIdsData(const char* base, const char* local, const char* resolved)
105{
106 printf(" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
107}
108
109inline void PrintSchemaIdsData(const wchar_t* base, const wchar_t* local, const wchar_t* resolved)
110{
111 wprintf(
112 L" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
113}
114
115inline void PrintMethodData(const char* method) { printf("%s\n", method); }
116
117inline void PrintMethodData(const char* method, bool b)
118{
119 printf("%s, Data: '%s'\n", method, b ? "true" : "false");
120}
121
122inline void PrintMethodData(const char* method, int64_t i)
123{
124 printf("%s, Data: '%" PRId64 "'\n", method, i);
125}
126
127inline void PrintMethodData(const char* method, uint64_t u)
128{
129 printf("%s, Data: '%" PRIu64 "'\n", method, u);
130}
131
132inline void PrintMethodData(const char* method, double d)
133{
134 printf("%s, Data: '%lf'\n", method, d);
135}
136
137inline void PrintMethodData(const char* method, const char* s)
138{
139 printf("%s, Data: '%s'\n", method, s);
140}
141
142inline void PrintMethodData(const char* method, const wchar_t* s)
143{
144 wprintf(L"%hs, Data: '%ls'\n", method, s);
145}
146
147inline void PrintMethodData(const char* method, const char* s1, const char* s2)
148{
149 printf("%s, Data: '%s', '%s'\n", method, s1, s2);
150}
151
152inline void PrintMethodData(const char* method, const wchar_t* s1, const wchar_t* s2)
153{
154 wprintf(L"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
155}
156
157} // namespace internal
158
159#endif // RAPIDJSON_SCHEMA_VERBOSE
160
161#ifndef RAPIDJSON_SCHEMA_PRINT
162#if RAPIDJSON_SCHEMA_VERBOSE
163#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
164#else
165#define RAPIDJSON_SCHEMA_PRINT(name, ...)
166#endif
167#endif
168
170// RAPIDJSON_INVALID_KEYWORD_RETURN
171
172#define RAPIDJSON_INVALID_KEYWORD_RETURN(code) \
173 RAPIDJSON_MULTILINEMACRO_BEGIN \
174 context.invalidCode = code; \
175 context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString(); \
176 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword); \
177 return false; \
178 RAPIDJSON_MULTILINEMACRO_END
179
181// ValidateFlag
182
189#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
190#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
191#endif
192
204
206// Specification
221
232
234{
237 {
238 if(oapi == kVersion20)
239 draft = kDraft04;
240 else if(oapi == kVersion30)
241 draft = kDraft05;
242 else if(oapi == kVersion31)
244 else
245 draft = kDraft04;
246 }
248 bool IsSupported() const
249 {
250 return ((draft >= kDraftMin && draft <= kDraftMax) &&
251 ((oapi == kVersionNone) || (oapi >= kVersionMin && oapi <= kVersionMax)));
252 }
255};
256
258// Forward declarations
259
260template <typename ValueType, typename Allocator>
262
263namespace internal {
264
265template <typename SchemaDocumentType>
266class Schema;
267
269// ISchemaValidator
270
272{
273 public:
274 virtual ~ISchemaValidator() {}
275 virtual bool IsValid() const = 0;
276 virtual void SetValidateFlags(unsigned flags) = 0;
277 virtual unsigned GetValidateFlags() const = 0;
278};
279
281// ISchemaStateFactory
282
283template <typename SchemaType>
285{
286 public:
288 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&,
289 const bool inheritContinueOnErrors) = 0;
290 virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
291 virtual void* CreateHasher() = 0;
292 virtual uint64_t GetHashCode(void* hasher) = 0;
293 virtual void DestroryHasher(void* hasher) = 0;
294 virtual void* MallocState(size_t size) = 0;
295 virtual void FreeState(void* p) = 0;
296};
297
299// IValidationErrorHandler
300
301template <typename SchemaType>
303{
304 public:
305 typedef typename SchemaType::Ch Ch;
306 typedef typename SchemaType::SValue SValue;
307
309
310 virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
311 virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
312 virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
313 virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
314 virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
315 virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
316 virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
317 virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
318 virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
319
320 virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
321 virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
322 virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
323
324 virtual void DisallowedItem(SizeType index) = 0;
325 virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
326 virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
327 virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
328
329 virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
330 virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
331 virtual void StartMissingProperties() = 0;
332 virtual void AddMissingProperty(const SValue& name) = 0;
333 virtual bool EndMissingProperties() = 0;
334 virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
335 virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
336
337 virtual void StartDependencyErrors() = 0;
339 virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
340 virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
341 virtual void AddDependencySchemaError(const SValue& souceName,
342 ISchemaValidator* subvalidator) = 0;
343 virtual bool EndDependencyErrors() = 0;
344
345 virtual void DisallowedValue(const ValidateErrorCode code) = 0;
346 virtual void StartDisallowedType() = 0;
347 virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
348 virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
349 virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
350 virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
351 virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
352 virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
353 virtual void Disallowed() = 0;
354 virtual void DisallowedWhenWriting() = 0;
355 virtual void DisallowedWhenReading() = 0;
356};
357
359// Hasher
360
361// For comparison of compound value
362template <typename Encoding, typename Allocator>
364{
365 public:
366 typedef typename Encoding::Ch Ch;
367
368 Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize)
369 : stack_(allocator, stackCapacity)
370 {
371 }
372
373 bool Null() { return WriteType(kNullType); }
374 bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
375 bool Int(int i)
376 {
377 Number n;
378 n.u.i = i;
379 n.d = static_cast<double>(i);
380 return WriteNumber(n);
381 }
382 bool Uint(unsigned u)
383 {
384 Number n;
385 n.u.u = u;
386 n.d = static_cast<double>(u);
387 return WriteNumber(n);
388 }
390 {
391 Number n;
392 n.u.i = i;
393 n.d = static_cast<double>(i);
394 return WriteNumber(n);
395 }
397 {
398 Number n;
399 n.u.u = u;
400 n.d = static_cast<double>(u);
401 return WriteNumber(n);
402 }
403 bool Double(double d)
404 {
405 Number n;
406 if(d < 0)
407 n.u.i = static_cast<int64_t>(d);
408 else
409 n.u.u = static_cast<uint64_t>(d);
410 n.d = d;
411 return WriteNumber(n);
412 }
413
414 bool RawNumber(const Ch* str, SizeType len, bool)
415 {
416 WriteBuffer(kNumberType, str, len * sizeof(Ch));
417 return true;
418 }
419
420 bool String(const Ch* str, SizeType len, bool)
421 {
422 WriteBuffer(kStringType, str, len * sizeof(Ch));
423 return true;
424 }
425
426 bool StartObject() { return true; }
427 bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
428 bool EndObject(SizeType memberCount)
429 {
430 uint64_t h = Hash(0, kObjectType);
431 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
432 for(SizeType i = 0; i < memberCount; i++)
433 // Issue #2205
434 // Hasing the key to avoid key=value cases with bug-prone zero-value hash
435 h ^= Hash(Hash(0, kv[i * 2]),
436 kv[i * 2 + 1]); // Use xor to achieve member order insensitive
437 *stack_.template Push<uint64_t>() = h;
438 return true;
439 }
440
441 bool StartArray() { return true; }
442 bool EndArray(SizeType elementCount)
443 {
444 uint64_t h = Hash(0, kArrayType);
445 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
446 for(SizeType i = 0; i < elementCount; i++)
447 h = Hash(h, e[i]); // Use hash to achieve element order sensitive
448 *stack_.template Push<uint64_t>() = h;
449 return true;
450 }
451
452 bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
453
455 {
457 return *stack_.template Top<uint64_t>();
458 }
459
460 private:
461 static const size_t kDefaultSize = 256;
462 struct Number
463 {
464 union U
465 {
468 } u;
469 double d;
470 };
471
472 bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
473
474 bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
475
476 bool WriteBuffer(Type type, const void* data, size_t len)
477 {
478 // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
479 uint64_t h = Hash(RAPIDJSON_UINT64_C2(0xcbf29ce4, 0x84222325), type);
480 const unsigned char* d = static_cast<const unsigned char*>(data);
481 for(size_t i = 0; i < len; i++)
482 h = Hash(h, d[i]);
483 *stack_.template Push<uint64_t>() = h;
484 return true;
485 }
486
487 static uint64_t Hash(uint64_t h, uint64_t d)
488 {
489 static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
490 h ^= d;
491 h *= kPrime;
492 return h;
493 }
494
495 Stack<Allocator> stack_;
496};
497
499// SchemaValidationContext
500
501template <typename SchemaDocumentType>
503{
508 typedef typename ValueType::Ch Ch;
509
516
543
545 {
546 if(hasher)
547 factory.DestroryHasher(hasher);
548 if(validators)
549 {
550 for(SizeType i = 0; i < validatorCount; i++)
551 {
552 if(validators[i])
553 {
554 factory.DestroySchemaValidator(validators[i]);
555 }
556 }
557 factory.FreeState(validators);
558 }
560 {
561 for(SizeType i = 0; i < patternPropertiesValidatorCount; i++)
562 {
564 {
565 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
566 }
567 }
569 }
572 if(propertyExist)
573 factory.FreeState(propertyExist);
574 }
575
579 unsigned flags;
583 void* hasher; // Only validator access
584 void* arrayElementHashCodes; // Only validator access this
598};
599
601// Schema
602
603template <typename SchemaDocumentType>
605{
606 public:
607 typedef typename SchemaDocumentType::ValueType ValueType;
608 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
609 typedef typename SchemaDocumentType::PointerType PointerType;
610 typedef typename ValueType::EncodingType EncodingType;
611 typedef typename EncodingType::Ch Ch;
618
619 Schema(SchemaDocumentType* schemaDocument,
620 const PointerType& p,
621 const ValueType& value,
622 const ValueType& document,
623 AllocatorType* allocator,
624 const UriType& id = UriType())
625 : allocator_(allocator),
626 uri_(schemaDocument->GetURI(), *allocator),
627 id_(id, allocator),
628 spec_(schemaDocument->GetSpecification()),
629 pointer_(p, allocator),
630 typeless_(schemaDocument->GetTypeless()),
631 enum_(),
632 enumCount_(),
633 not_(),
634 type_((1 << kTotalSchemaType) - 1), // typeless
637 properties_(),
646 hasRequired_(),
649 itemsList_(),
650 itemsTuple_(),
652 minItems_(),
653 maxItems_(SizeType(~0)),
654 additionalItems_(true),
655 uniqueItems_(false),
656 pattern_(),
657 minLength_(0),
658 maxLength_(~SizeType(0)),
659 exclusiveMinimum_(false),
660 exclusiveMaximum_(false),
662 readOnly_(false),
663 writeOnly_(false),
664 nullable_(false)
665 {
667 p.StringifyUriFragment(sb);
668 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Schema", sb.GetString(), id.GetString());
669
670 typedef typename ValueType::ConstValueIterator ConstValueIterator;
671 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
672
673 // PR #1393
674 // Early add this Schema and its $ref(s) in schemaDocument's map to avoid infinite
675 // recursion (with recursive schemas), since schemaDocument->getSchema() is always
676 // checked before creating a new one. Don't cache typeless_, though.
677 if(this != typeless_)
678 {
679 typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
680 SchemaEntry* entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
681 new(entry) SchemaEntry(pointer_, this, true, allocator_);
682 schemaDocument->AddSchemaRefs(this);
683 }
684
685 if(!value.IsObject())
686 return;
687
688 // If we have an id property, resolve it with the in-scope id
689 // Not supported for open api 2.0 or 3.0
690 if(spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
691 if(const ValueType* v = GetMember(value, GetIdString()))
692 {
693 if(v->IsString())
694 {
695 UriType local(*v, allocator);
696 id_ = local.Resolve(id_, allocator);
698 SchemaIds, id.GetString(), v->GetString(), id_.GetString());
699 }
700 }
701
702 if(const ValueType* v = GetMember(value, GetTypeString()))
703 {
704 type_ = 0;
705 if(v->IsString())
706 AddType(*v);
707 else if(v->IsArray())
708 for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
709 AddType(*itr);
710 }
711
712 if(const ValueType* v = GetMember(value, GetEnumString()))
713 {
714 if(v->IsArray() && v->Size() > 0)
715 {
716 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
717 for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
718 {
720 char buffer[256u + 24];
721 MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer, sizeof(buffer));
722 EnumHasherType h(&hasherAllocator, 256);
723 itr->Accept(h);
724 enum_[enumCount_++] = h.GetHashCode();
725 }
726 }
727 }
728
729 if(schemaDocument)
730 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
731
732 // AnyOf, OneOf, Not not supported for open api 2.0
733 if(schemaDocument && spec_.oapi != kVersion20)
734 {
735 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
736 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
737
738 if(const ValueType* v = GetMember(value, GetNotString()))
739 {
740 schemaDocument->CreateSchema(
741 &not_, p.Append(GetNotString(), allocator_), *v, document, id_);
744 }
745 }
746
747 // Object
748
749 const ValueType* properties = GetMember(value, GetPropertiesString());
750 const ValueType* required = GetMember(value, GetRequiredString());
751 const ValueType* dependencies = GetMember(value, GetDependenciesString());
752 {
753 // Gather properties from properties/required/dependencies
754 SValue allProperties(kArrayType);
755
756 if(properties && properties->IsObject())
757 for(ConstMemberIterator itr = properties->MemberBegin();
758 itr != properties->MemberEnd();
759 ++itr)
760 AddUniqueElement(allProperties, itr->name);
761
762 if(required && required->IsArray())
763 for(ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
764 if(itr->IsString())
765 AddUniqueElement(allProperties, *itr);
766
767 // Dependencies not supported for open api 2.0 and 3.0
768 if(spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
769 if(dependencies && dependencies->IsObject())
770 for(ConstMemberIterator itr = dependencies->MemberBegin();
771 itr != dependencies->MemberEnd();
772 ++itr)
773 {
774 AddUniqueElement(allProperties, itr->name);
775 if(itr->value.IsArray())
776 for(ConstValueIterator i = itr->value.Begin(); i != itr->value.End();
777 ++i)
778 if(i->IsString())
779 AddUniqueElement(allProperties, *i);
780 }
781
782 if(allProperties.Size() > 0)
783 {
784 propertyCount_ = allProperties.Size();
786 static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
787 for(SizeType i = 0; i < propertyCount_; i++)
788 {
789 new(&properties_[i]) Property();
790 properties_[i].name = allProperties[i];
791 properties_[i].schema = typeless_;
792 }
793 }
794 }
795
796 if(properties && properties->IsObject())
797 {
798 PointerType q = p.Append(GetPropertiesString(), allocator_);
799 for(ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd();
800 ++itr)
801 {
802 SizeType index;
803 if(FindPropertyIndex(itr->name, &index))
804 schemaDocument->CreateSchema(&properties_[index].schema,
805 q.Append(itr->name, allocator_),
806 itr->value,
807 document,
808 id_);
809 }
810 }
811
812 // PatternProperties not supported for open api 2.0 and 3.0
813 if(spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
814 if(const ValueType* v = GetMember(value, GetPatternPropertiesString()))
815 {
816 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
817 patternProperties_ = static_cast<PatternProperty*>(
818 allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
820
821 for(ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr)
822 {
823 new(&patternProperties_[patternPropertyCount_]) PatternProperty();
824 PointerType r = q.Append(itr->name, allocator_);
826 CreatePattern(itr->name, schemaDocument, r);
827 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema,
828 r,
829 itr->value,
830 document,
831 id_);
833 }
834 }
835
836 if(required && required->IsArray())
837 for(ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
838 if(itr->IsString())
839 {
840 SizeType index;
841 if(FindPropertyIndex(*itr, &index))
842 {
843 properties_[index].required = true;
844 hasRequired_ = true;
845 }
846 }
847
848 // Dependencies not supported for open api 2.0 and 3.0
849 if(spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
850 if(dependencies && dependencies->IsObject())
851 {
852 PointerType q = p.Append(GetDependenciesString(), allocator_);
853 hasDependencies_ = true;
854 for(ConstMemberIterator itr = dependencies->MemberBegin();
855 itr != dependencies->MemberEnd();
856 ++itr)
857 {
858 SizeType sourceIndex;
859 if(FindPropertyIndex(itr->name, &sourceIndex))
860 {
861 if(itr->value.IsArray())
862 {
863 properties_[sourceIndex].dependencies = static_cast<bool*>(
864 allocator_->Malloc(sizeof(bool) * propertyCount_));
865 std::memset(properties_[sourceIndex].dependencies,
866 0,
867 sizeof(bool) * propertyCount_);
868 for(ConstValueIterator targetItr = itr->value.Begin();
869 targetItr != itr->value.End();
870 ++targetItr)
871 {
872 SizeType targetIndex;
873 if(FindPropertyIndex(*targetItr, &targetIndex))
874 properties_[sourceIndex].dependencies[targetIndex] = true;
875 }
876 }
877 else if(itr->value.IsObject())
878 {
880 schemaDocument->CreateSchema(
881 &properties_[sourceIndex].dependenciesSchema,
882 q.Append(itr->name, allocator_),
883 itr->value,
884 document,
885 id_);
886 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
888 }
889 }
890 }
891 }
892
893 if(const ValueType* v = GetMember(value, GetAdditionalPropertiesString()))
894 {
895 if(v->IsBool())
896 additionalProperties_ = v->GetBool();
897 else if(v->IsObject())
898 schemaDocument->CreateSchema(&additionalPropertiesSchema_,
899 p.Append(GetAdditionalPropertiesString(), allocator_),
900 *v,
901 document,
902 id_);
903 }
904
905 AssignIfExist(minProperties_, value, GetMinPropertiesString());
906 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
907
908 // Array
909 if(const ValueType* v = GetMember(value, GetItemsString()))
910 {
911 PointerType q = p.Append(GetItemsString(), allocator_);
912 if(v->IsObject()) // List validation
913 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
914 else if(v->IsArray())
915 { // Tuple validation
916 itemsTuple_ = static_cast<const Schema**>(
917 allocator_->Malloc(sizeof(const Schema*) * v->Size()));
918 SizeType index = 0;
919 for(ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
920 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++],
921 q.Append(index, allocator_),
922 *itr,
923 document,
924 id_);
925 }
926 }
927
928 AssignIfExist(minItems_, value, GetMinItemsString());
929 AssignIfExist(maxItems_, value, GetMaxItemsString());
930
931 // AdditionalItems not supported for openapi 2.0 and 3.0
932 if(spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
933 if(const ValueType* v = GetMember(value, GetAdditionalItemsString()))
934 {
935 if(v->IsBool())
936 additionalItems_ = v->GetBool();
937 else if(v->IsObject())
938 schemaDocument->CreateSchema(&additionalItemsSchema_,
939 p.Append(GetAdditionalItemsString(), allocator_),
940 *v,
941 document,
942 id_);
943 }
944
945 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
946
947 // String
948 AssignIfExist(minLength_, value, GetMinLengthString());
949 AssignIfExist(maxLength_, value, GetMaxLengthString());
950
951 if(const ValueType* v = GetMember(value, GetPatternString()))
952 pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
953
954 // Number
955 if(const ValueType* v = GetMember(value, GetMinimumString()))
956 if(v->IsNumber())
957 minimum_.CopyFrom(*v, *allocator_);
958
959 if(const ValueType* v = GetMember(value, GetMaximumString()))
960 if(v->IsNumber())
961 maximum_.CopyFrom(*v, *allocator_);
962
963 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
964 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
965
966 if(const ValueType* v = GetMember(value, GetMultipleOfString()))
967 if(v->IsNumber() && v->GetDouble() > 0.0)
968 multipleOf_.CopyFrom(*v, *allocator_);
969
970 // Default
971 if(const ValueType* v = GetMember(value, GetDefaultValueString()))
972 if(v->IsString())
973 defaultValueLength_ = v->GetStringLength();
974
975 // ReadOnly - open api only (until draft 7 supported)
976 // WriteOnly - open api 3 only (until draft 7 supported)
977 // Both can't be true
978 if(spec_.oapi != kVersionNone)
979 AssignIfExist(readOnly_, value, GetReadOnlyString());
980 if(spec_.oapi >= kVersion30)
981 AssignIfExist(writeOnly_, value, GetWriteOnlyString());
982 if(readOnly_ && writeOnly_)
983 schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
984
985 // Nullable - open api 3 only
986 // If true add 'null' as allowable type
987 if(spec_.oapi >= kVersion30)
988 {
989 AssignIfExist(nullable_, value, GetNullableString());
990 if(nullable_)
991 AddType(GetNullString());
992 }
993 }
994
996 {
997 AllocatorType::Free(enum_);
998 if(properties_)
999 {
1000 for(SizeType i = 0; i < propertyCount_; i++)
1001 properties_[i].~Property();
1002 AllocatorType::Free(properties_);
1003 }
1005 {
1006 for(SizeType i = 0; i < patternPropertyCount_; i++)
1007 patternProperties_[i].~PatternProperty();
1008 AllocatorType::Free(patternProperties_);
1009 }
1010 AllocatorType::Free(itemsTuple_);
1011#if RAPIDJSON_SCHEMA_HAS_REGEX
1012 if(pattern_)
1013 {
1014 pattern_->~RegexType();
1015 AllocatorType::Free(pattern_);
1016 }
1017#endif
1018 }
1019
1020 const SValue& GetURI() const { return uri_; }
1021
1022 const UriType& GetId() const { return id_; }
1023
1024 const Specification& GetSpecification() const { return spec_; }
1025
1026 const PointerType& GetPointer() const { return pointer_; }
1027
1028 bool BeginValue(Context& context) const
1029 {
1030 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::BeginValue");
1031 if(context.inArray)
1032 {
1033 if(uniqueItems_)
1034 context.valueUniqueness = true;
1035
1036 if(itemsList_)
1037 context.valueSchema = itemsList_;
1038 else if(itemsTuple_)
1039 {
1041 context.valueSchema = itemsTuple_[context.arrayElementIndex];
1042 else if(additionalItemsSchema_)
1044 else if(additionalItems_)
1045 context.valueSchema = typeless_;
1046 else
1047 {
1049 // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else
1050 // reports spurious type error
1051 context.valueSchema = typeless_;
1052 // Must bump arrayElementIndex for when kValidateContinueOnErrorFlag is set
1053 context.arrayElementIndex++;
1055 }
1056 }
1057 else
1058 context.valueSchema = typeless_;
1059
1060 context.arrayElementIndex++;
1061 }
1062 return true;
1063 }
1064
1065 RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const
1066 {
1067 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndValue");
1068 // Only check pattern properties if we have validators
1069 if(context.patternPropertiesValidatorCount > 0)
1070 {
1071 bool otherValid = false;
1074 otherValid = context.patternPropertiesValidators[--count]->IsValid();
1075
1076 bool patternValid = true;
1077 for(SizeType i = 0; i < count; i++)
1078 if(!context.patternPropertiesValidators[i]->IsValid())
1079 {
1080 patternValid = false;
1081 break;
1082 }
1083
1085 {
1086 if(!patternValid)
1087 {
1089 count);
1091 }
1092 }
1094 {
1095 if(!patternValid || !otherValid)
1096 {
1098 count + 1);
1100 }
1101 }
1102 else if(!patternValid && !otherValid)
1103 { // kPatternValidatorWithAdditionalProperty)
1105 count + 1);
1107 }
1108 }
1109
1110 // For enums only check if we have a hasher
1111 if(enum_ && context.hasher)
1112 {
1113 const uint64_t h = context.factory.GetHashCode(context.hasher);
1114 for(SizeType i = 0; i < enumCount_; i++)
1115 if(enum_[i] == h)
1116 goto foundEnum;
1119 foundEnum:;
1120 }
1121
1122 // Only check allOf etc if we have validators
1123 if(context.validatorCount > 0)
1124 {
1125 if(allOf_.schemas)
1126 for(SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
1127 if(!context.validators[i]->IsValid())
1128 {
1129 context.error_handler.NotAllOf(&context.validators[allOf_.begin],
1130 allOf_.count);
1132 }
1133
1134 if(anyOf_.schemas)
1135 {
1136 for(SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
1137 if(context.validators[i]->IsValid())
1138 goto foundAny;
1139 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
1141 foundAny:;
1142 }
1143
1144 if(oneOf_.schemas)
1145 {
1146 bool oneValid = false;
1147 SizeType firstMatch = 0;
1148 for(SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
1149 if(context.validators[i]->IsValid())
1150 {
1151 if(oneValid)
1152 {
1153 context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
1155 }
1156 else
1157 {
1158 oneValid = true;
1159 firstMatch = i - oneOf_.begin;
1160 }
1161 }
1162 if(!oneValid)
1163 {
1164 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
1166 }
1167 }
1168
1169 if(not_ && context.validators[notValidatorIndex_]->IsValid())
1170 {
1171 context.error_handler.Disallowed();
1173 }
1174 }
1175
1176 return true;
1177 }
1178
1179 bool Null(Context& context) const
1180 {
1181 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Null");
1182 if(!(type_ & (1 << kNullSchemaType)))
1183 {
1184 DisallowedType(context, GetNullString());
1186 }
1187 return CreateParallelValidator(context);
1188 }
1189
1190 bool Bool(Context& context, bool b) const
1191 {
1192 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Bool", b);
1193 if(!CheckBool(context, b))
1194 return false;
1195 return CreateParallelValidator(context);
1196 }
1197
1198 bool Int(Context& context, int i) const
1199 {
1200 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int", (int64_t)i);
1201 if(!CheckInt(context, i))
1202 return false;
1203 return CreateParallelValidator(context);
1204 }
1205
1206 bool Uint(Context& context, unsigned u) const
1207 {
1208 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint", (uint64_t)u);
1209 if(!CheckUint(context, u))
1210 return false;
1211 return CreateParallelValidator(context);
1212 }
1213
1214 bool Int64(Context& context, int64_t i) const
1215 {
1216 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Int64", i);
1217 if(!CheckInt(context, i))
1218 return false;
1219 return CreateParallelValidator(context);
1220 }
1221
1222 bool Uint64(Context& context, uint64_t u) const
1223 {
1224 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Uint64", u);
1225 if(!CheckUint(context, u))
1226 return false;
1227 return CreateParallelValidator(context);
1228 }
1229
1230 bool Double(Context& context, double d) const
1231 {
1232 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Double", d);
1233 if(!(type_ & (1 << kNumberSchemaType)))
1234 {
1235 DisallowedType(context, GetNumberString());
1237 }
1238
1239 if(!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1240 return false;
1241
1242 if(!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1243 return false;
1244
1245 if(!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1246 return false;
1247
1248 return CreateParallelValidator(context);
1249 }
1250
1251 bool String(Context& context, const Ch* str, SizeType length, bool) const
1252 {
1253 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::String", str);
1254 if(!(type_ & (1 << kStringSchemaType)))
1255 {
1256 DisallowedType(context, GetStringString());
1258 }
1259
1260 if(minLength_ != 0 || maxLength_ != SizeType(~0))
1261 {
1262 SizeType count;
1263 if(internal::CountStringCodePoint<EncodingType>(str, length, &count))
1264 {
1265 if(count < minLength_)
1266 {
1267 context.error_handler.TooShort(str, length, minLength_);
1269 }
1270 if(count > maxLength_)
1271 {
1272 context.error_handler.TooLong(str, length, maxLength_);
1274 }
1275 }
1276 }
1277
1278 if(pattern_ && !IsPatternMatch(pattern_, str, length))
1279 {
1280 context.error_handler.DoesNotMatch(str, length);
1282 }
1283
1284 return CreateParallelValidator(context);
1285 }
1286
1287 bool StartObject(Context& context) const
1288 {
1289 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartObject");
1290 if(!(type_ & (1 << kObjectSchemaType)))
1291 {
1292 DisallowedType(context, GetObjectString());
1294 }
1295
1297 {
1298 context.propertyExist =
1299 static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
1300 std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
1301 }
1302
1304 { // pre-allocate schema array
1305 SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
1306 context.patternPropertiesSchemas = static_cast<const SchemaType**>(
1307 context.factory.MallocState(sizeof(const SchemaType*) * count));
1308 context.patternPropertiesSchemaCount = 0;
1309 std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
1310 }
1311
1312 return CreateParallelValidator(context);
1313 }
1314
1315 bool Key(Context& context, const Ch* str, SizeType len, bool) const
1316 {
1317 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::Key", str);
1318
1320 {
1321 context.patternPropertiesSchemaCount = 0;
1322 for(SizeType i = 0; i < patternPropertyCount_; i++)
1323 if(patternProperties_[i].pattern &&
1324 IsPatternMatch(patternProperties_[i].pattern, str, len))
1325 {
1327 patternProperties_[i].schema;
1328 context.valueSchema = typeless_;
1329 }
1330 }
1331
1332 SizeType index = 0;
1333 if(FindPropertyIndex(ValueType(str, len).Move(), &index))
1334 {
1335 if(context.patternPropertiesSchemaCount > 0)
1336 {
1338 properties_[index].schema;
1339 context.valueSchema = typeless_;
1341 }
1342 else
1343 context.valueSchema = properties_[index].schema;
1344
1345 if(context.propertyExist)
1346 context.propertyExist[index] = true;
1347
1348 return true;
1349 }
1350
1352 {
1353 if(context.patternPropertiesSchemaCount > 0)
1354 {
1357 context.valueSchema = typeless_;
1360 }
1361 else
1363 return true;
1364 }
1365 else if(additionalProperties_)
1366 {
1367 context.valueSchema = typeless_;
1368 return true;
1369 }
1370
1371 if(context.patternPropertiesSchemaCount == 0)
1372 { // patternProperties are not additional properties
1373 // Must set valueSchema for when kValidateContinueOnErrorFlag is set, else reports
1374 // spurious type error
1375 context.valueSchema = typeless_;
1376 context.error_handler.DisallowedProperty(str, len);
1378 }
1379
1380 return true;
1381 }
1382
1383 bool EndObject(Context& context, SizeType memberCount) const
1384 {
1385 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndObject");
1386 if(hasRequired_)
1387 {
1389 for(SizeType index = 0; index < propertyCount_; index++)
1390 if(properties_[index].required && !context.propertyExist[index])
1391 if(properties_[index].schema->defaultValueLength_ == 0)
1392 context.error_handler.AddMissingProperty(properties_[index].name);
1395 }
1396
1397 if(memberCount < minProperties_)
1398 {
1399 context.error_handler.TooFewProperties(memberCount, minProperties_);
1401 }
1402
1403 if(memberCount > maxProperties_)
1404 {
1405 context.error_handler.TooManyProperties(memberCount, maxProperties_);
1407 }
1408
1410 {
1412 for(SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
1413 {
1414 const Property& source = properties_[sourceIndex];
1415 if(context.propertyExist[sourceIndex])
1416 {
1417 if(source.dependencies)
1418 {
1420 for(SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1421 if(source.dependencies[targetIndex] &&
1422 !context.propertyExist[targetIndex])
1424 properties_[targetIndex].name);
1426 }
1427 else if(source.dependenciesSchema)
1428 {
1429 ISchemaValidator* dependenciesValidator =
1430 context.validators[source.dependenciesValidatorIndex];
1431 if(!dependenciesValidator->IsValid())
1433 dependenciesValidator);
1434 }
1435 }
1436 }
1439 }
1440
1441 return true;
1442 }
1443
1444 bool StartArray(Context& context) const
1445 {
1446 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::StartArray");
1447 context.arrayElementIndex = 0;
1448 context.inArray = true; // Ensure we note that we are in an array
1449
1450 if(!(type_ & (1 << kArraySchemaType)))
1451 {
1452 DisallowedType(context, GetArrayString());
1454 }
1455
1456 return CreateParallelValidator(context);
1457 }
1458
1459 bool EndArray(Context& context, SizeType elementCount) const
1460 {
1461 RAPIDJSON_SCHEMA_PRINT(Method, "Schema::EndArray");
1462 context.inArray = false;
1463
1464 if(elementCount < minItems_)
1465 {
1466 context.error_handler.TooFewItems(elementCount, minItems_);
1468 }
1469
1470 if(elementCount > maxItems_)
1471 {
1472 context.error_handler.TooManyItems(elementCount, maxItems_);
1474 }
1475
1476 return true;
1477 }
1478
1479 static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)
1480 {
1481 switch(validateErrorCode)
1482 {
1483 case kValidateErrorMultipleOf: return GetMultipleOfString();
1484 case kValidateErrorMaximum: return GetMaximumString();
1485 case kValidateErrorExclusiveMaximum: return GetMaximumString(); // Same
1486 case kValidateErrorMinimum: return GetMinimumString();
1487 case kValidateErrorExclusiveMinimum: return GetMinimumString(); // Same
1488
1489 case kValidateErrorMaxLength: return GetMaxLengthString();
1490 case kValidateErrorMinLength: return GetMinLengthString();
1491 case kValidateErrorPattern: return GetPatternString();
1492
1493 case kValidateErrorMaxItems: return GetMaxItemsString();
1494 case kValidateErrorMinItems: return GetMinItemsString();
1495 case kValidateErrorUniqueItems: return GetUniqueItemsString();
1496 case kValidateErrorAdditionalItems: return GetAdditionalItemsString();
1497
1498 case kValidateErrorMaxProperties: return GetMaxPropertiesString();
1499 case kValidateErrorMinProperties: return GetMinPropertiesString();
1500 case kValidateErrorRequired: return GetRequiredString();
1501 case kValidateErrorAdditionalProperties: return GetAdditionalPropertiesString();
1502 case kValidateErrorPatternProperties: return GetPatternPropertiesString();
1503 case kValidateErrorDependencies: return GetDependenciesString();
1504
1505 case kValidateErrorEnum: return GetEnumString();
1506 case kValidateErrorType: return GetTypeString();
1507
1508 case kValidateErrorOneOf: return GetOneOfString();
1509 case kValidateErrorOneOfMatch: return GetOneOfString(); // Same
1510 case kValidateErrorAllOf: return GetAllOfString();
1511 case kValidateErrorAnyOf: return GetAnyOfString();
1512 case kValidateErrorNot: return GetNotString();
1513
1514 case kValidateErrorReadOnly: return GetReadOnlyString();
1515 case kValidateErrorWriteOnly: return GetWriteOnlyString();
1516
1517 default: return GetNullString();
1518 }
1519 }
1520
1521 // Generate functions for string literal according to Ch
1522#define RAPIDJSON_STRING_(name, ...) \
1523 static const ValueType& Get##name##String() \
1524 { \
1525 static const Ch s[] = {__VA_ARGS__, '\0'}; \
1526 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
1527 return v; \
1528 }
1529
1530 RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
1531 RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1532 RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1533 RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1534 RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1535 RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1536 RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1537 RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1538 RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1539 RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1540 RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1541 RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1542 RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1543 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1544 RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1545 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1546 RAPIDJSON_STRING_(PatternProperties,
1547 'p',
1548 'a',
1549 't',
1550 't',
1551 'e',
1552 'r',
1553 'n',
1554 'P',
1555 'r',
1556 'o',
1557 'p',
1558 'e',
1559 'r',
1560 't',
1561 'i',
1562 'e',
1563 's')
1564 RAPIDJSON_STRING_(AdditionalProperties,
1565 'a',
1566 'd',
1567 'd',
1568 'i',
1569 't',
1570 'i',
1571 'o',
1572 'n',
1573 'a',
1574 'l',
1575 'P',
1576 'r',
1577 'o',
1578 'p',
1579 'e',
1580 'r',
1581 't',
1582 'i',
1583 'e',
1584 's')
1586 MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1588 MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1589 RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1590 RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1591 RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1593 AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1594 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1595 RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1596 RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1597 RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1598 RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1599 RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1600 RAPIDJSON_STRING_(ExclusiveMinimum,
1601 'e',
1602 'x',
1603 'c',
1604 'l',
1605 'u',
1606 's',
1607 'i',
1608 'v',
1609 'e',
1610 'M',
1611 'i',
1612 'n',
1613 'i',
1614 'm',
1615 'u',
1616 'm')
1617 RAPIDJSON_STRING_(ExclusiveMaximum,
1618 'e',
1619 'x',
1620 'c',
1621 'l',
1622 'u',
1623 's',
1624 'i',
1625 'v',
1626 'e',
1627 'M',
1628 'a',
1629 'x',
1630 'i',
1631 'm',
1632 'u',
1633 'm')
1634 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1635 RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1636 RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
1637 RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
1638 RAPIDJSON_STRING_(Id, 'i', 'd')
1639 RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
1640 RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
1641 RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
1642 RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
1643 RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
1644
1645#undef RAPIDJSON_STRING_
1646
1647 private:
1648 enum SchemaValueType
1649 {
1650 kNullSchemaType,
1651 kBooleanSchemaType,
1652 kObjectSchemaType,
1653 kArraySchemaType,
1654 kStringSchemaType,
1655 kNumberSchemaType,
1656 kIntegerSchemaType,
1657 kTotalSchemaType
1658 };
1659
1660#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1662#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1663 typedef std::basic_regex<Ch> RegexType;
1664#else
1665 typedef char RegexType;
1666#endif
1667
1669 {
1671 ~SchemaArray() { AllocatorType::Free(schemas); }
1673 SizeType begin; // begin index of context.validators
1675 };
1676
1677 template <typename V1, typename V2>
1678 void AddUniqueElement(V1& a, const V2& v)
1679 {
1680 for(typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1681 if(*itr == v)
1682 return;
1683 V1 c(v, *allocator_);
1684 a.PushBack(c, *allocator_);
1685 }
1686
1687 static const ValueType* GetMember(const ValueType& value, const ValueType& name)
1688 {
1689 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1690 return itr != value.MemberEnd() ? &(itr->value) : 0;
1691 }
1692
1693 static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name)
1694 {
1695 if(const ValueType* v = GetMember(value, name))
1696 if(v->IsBool())
1697 out = v->GetBool();
1698 }
1699
1700 static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name)
1701 {
1702 if(const ValueType* v = GetMember(value, name))
1703 if(v->IsUint64() && v->GetUint64() <= SizeType(~0))
1704 out = static_cast<SizeType>(v->GetUint64());
1705 }
1706
1707 void AssignIfExist(SchemaArray& out,
1708 SchemaDocumentType& schemaDocument,
1709 const PointerType& p,
1710 const ValueType& value,
1711 const ValueType& name,
1712 const ValueType& document)
1713 {
1714 if(const ValueType* v = GetMember(value, name))
1715 {
1716 if(v->IsArray() && v->Size() > 0)
1717 {
1718 PointerType q = p.Append(name, allocator_);
1719 out.count = v->Size();
1720 out.schemas = static_cast<const Schema**>(
1721 allocator_->Malloc(out.count * sizeof(const Schema*)));
1722 memset(out.schemas, 0, sizeof(Schema*) * out.count);
1723 for(SizeType i = 0; i < out.count; i++)
1724 schemaDocument.CreateSchema(
1725 &out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1726 out.begin = validatorCount_;
1727 validatorCount_ += out.count;
1728 }
1729 }
1730 }
1731
1732#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1733 template <typename ValueType>
1734 RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p)
1735 {
1736 if(value.IsString())
1737 {
1738 RegexType* r =
1739 new(allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1740 if(!r->IsValid())
1741 {
1742 sd->SchemaErrorValue(
1743 kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1744 r->~RegexType();
1745 AllocatorType::Free(r);
1746 r = 0;
1747 }
1748 return r;
1749 }
1750 return 0;
1751 }
1752
1753 static bool IsPatternMatch(const RegexType* pattern, const Ch* str, SizeType)
1754 {
1755 GenericRegexSearch<RegexType> rs(*pattern);
1756 return rs.Search(str);
1757 }
1758#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1759 template <typename ValueType>
1760 RegexType* CreatePattern(const ValueType& value, SchemaDocumentType* sd, const PointerType& p)
1761 {
1762 if(value.IsString())
1763 {
1764 RegexType* r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
1765 try
1766 {
1767 return new(r) RegexType(value.GetString(),
1768 std::size_t(value.GetStringLength()),
1769 std::regex_constants::ECMAScript);
1770 }
1771 catch(const std::regex_error& e)
1772 {
1773 sd->SchemaErrorValue(
1774 kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1775 AllocatorType::Free(r);
1776 }
1777 }
1778 return 0;
1779 }
1780
1781 static bool IsPatternMatch(const RegexType* pattern, const Ch* str, SizeType length)
1782 {
1783 std::match_results<const Ch*> r;
1784 return std::regex_search(str, str + length, r, *pattern);
1785 }
1786#else
1787 template <typename ValueType>
1789 {
1790 return 0;
1791 }
1792
1793 static bool IsPatternMatch(const RegexType*, const Ch*, SizeType) { return true; }
1794#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1795
1796 void AddType(const ValueType& type)
1797 {
1798 if(type == GetNullString())
1799 type_ |= 1 << kNullSchemaType;
1800 else if(type == GetBooleanString())
1801 type_ |= 1 << kBooleanSchemaType;
1802 else if(type == GetObjectString())
1803 type_ |= 1 << kObjectSchemaType;
1804 else if(type == GetArrayString())
1805 type_ |= 1 << kArraySchemaType;
1806 else if(type == GetStringString())
1807 type_ |= 1 << kStringSchemaType;
1808 else if(type == GetIntegerString())
1809 type_ |= 1 << kIntegerSchemaType;
1810 else if(type == GetNumberString())
1811 type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1812 }
1813
1814 // Creates parallel validators for allOf, anyOf, oneOf, not and schema dependencies, if
1815 // required. Also creates a hasher for enums and array uniqueness, if required. Also a useful
1816 // place to add type-independent error checks.
1818 {
1819 if(enum_ || context.arrayUniqueness)
1820 context.hasher = context.factory.CreateHasher();
1821
1822 if(validatorCount_)
1823 {
1824 RAPIDJSON_ASSERT(context.validators == 0);
1825 context.validators = static_cast<ISchemaValidator**>(
1827 std::memset(context.validators, 0, sizeof(ISchemaValidator*) * validatorCount_);
1829
1830 // Always return after first failure for these sub-validators
1831 if(allOf_.schemas)
1832 CreateSchemaValidators(context, allOf_, false);
1833
1834 if(anyOf_.schemas)
1835 CreateSchemaValidators(context, anyOf_, false);
1836
1837 if(oneOf_.schemas)
1838 CreateSchemaValidators(context, oneOf_, false);
1839
1840 if(not_)
1842 context.factory.CreateSchemaValidator(*not_, false);
1843
1845 {
1846 for(SizeType i = 0; i < propertyCount_; i++)
1847 if(properties_[i].dependenciesSchema)
1848 context.validators[properties_[i].dependenciesValidatorIndex] =
1850 *properties_[i].dependenciesSchema, false);
1851 }
1852 }
1853
1854 // Add any other type-independent checks here
1855 if(readOnly_ && (context.flags & kValidateWriteFlag))
1856 {
1859 }
1860 if(writeOnly_ && (context.flags & kValidateReadFlag))
1861 {
1864 }
1865
1866 return true;
1867 }
1868
1870 const SchemaArray& schemas,
1871 const bool inheritContinueOnErrors) const
1872 {
1873 for(SizeType i = 0; i < schemas.count; i++)
1874 context.validators[schemas.begin + i] =
1875 context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1876 }
1877
1878 // O(n)
1879 bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const
1880 {
1881 SizeType len = name.GetStringLength();
1882 const Ch* str = name.GetString();
1883 for(SizeType index = 0; index < propertyCount_; index++)
1884 if(properties_[index].name.GetStringLength() == len &&
1885 (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
1886 {
1887 *outIndex = index;
1888 return true;
1889 }
1890 return false;
1891 }
1892
1893 bool CheckBool(Context& context, bool) const
1894 {
1895 if(!(type_ & (1 << kBooleanSchemaType)))
1896 {
1897 DisallowedType(context, GetBooleanString());
1899 }
1900 return true;
1901 }
1902
1903 bool CheckInt(Context& context, int64_t i) const
1904 {
1905 if(!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1906 {
1907 DisallowedType(context, GetIntegerString());
1909 }
1910
1911 if(!minimum_.IsNull())
1912 {
1913 if(minimum_.IsInt64())
1914 {
1915 if(exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1916 {
1920 }
1921 }
1922 else if(minimum_.IsUint64())
1923 {
1928 : kValidateErrorMinimum); // i <= max(int64_t) < minimum.GetUint64()
1929 }
1930 else if(!CheckDoubleMinimum(context, static_cast<double>(i)))
1931 return false;
1932 }
1933
1934 if(!maximum_.IsNull())
1935 {
1936 if(maximum_.IsInt64())
1937 {
1938 if(exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1939 {
1943 }
1944 }
1945 else if(maximum_.IsUint64()) {}
1946 /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
1947 else if(!CheckDoubleMaximum(context, static_cast<double>(i)))
1948 return false;
1949 }
1950
1951 if(!multipleOf_.IsNull())
1952 {
1953 if(multipleOf_.IsUint64())
1954 {
1955 if(static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1956 {
1959 }
1960 }
1961 else if(!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1962 return false;
1963 }
1964
1965 return true;
1966 }
1967
1968 bool CheckUint(Context& context, uint64_t i) const
1969 {
1970 if(!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1971 {
1972 DisallowedType(context, GetIntegerString());
1974 }
1975
1976 if(!minimum_.IsNull())
1977 {
1978 if(minimum_.IsUint64())
1979 {
1980 if(exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1981 {
1985 }
1986 }
1987 else if(minimum_.IsInt64())
1988 /* do nothing */; // i >= 0 > minimum.Getint64()
1989 else if(!CheckDoubleMinimum(context, static_cast<double>(i)))
1990 return false;
1991 }
1992
1993 if(!maximum_.IsNull())
1994 {
1995 if(maximum_.IsUint64())
1996 {
1997 if(exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1998 {
2002 }
2003 }
2004 else if(maximum_.IsInt64())
2005 {
2009 : kValidateErrorMaximum); // i >= 0 > maximum_
2010 }
2011 else if(!CheckDoubleMaximum(context, static_cast<double>(i)))
2012 return false;
2013 }
2014
2015 if(!multipleOf_.IsNull())
2016 {
2017 if(multipleOf_.IsUint64())
2018 {
2019 if(i % multipleOf_.GetUint64() != 0)
2020 {
2023 }
2024 }
2025 else if(!CheckDoubleMultipleOf(context, static_cast<double>(i)))
2026 return false;
2027 }
2028
2029 return true;
2030 }
2031
2032 bool CheckDoubleMinimum(Context& context, double d) const
2033 {
2034 if(exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
2035 {
2039 }
2040 return true;
2041 }
2042
2043 bool CheckDoubleMaximum(Context& context, double d) const
2044 {
2045 if(exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
2046 {
2050 }
2051 return true;
2052 }
2053
2054 bool CheckDoubleMultipleOf(Context& context, double d) const
2055 {
2056 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
2057 double q = a / b;
2058 double qRounded = std::floor(q + 0.5);
2059 double scaledEpsilon = (q + qRounded) * std::numeric_limits<double>::epsilon();
2060 double difference = std::abs(qRounded - q);
2061 bool isMultiple =
2062 difference <= scaledEpsilon || difference < (std::numeric_limits<double>::min)();
2063 if(!isMultiple)
2064 {
2067 }
2068 return true;
2069 }
2070
2071 void DisallowedType(Context& context, const ValueType& actualType) const
2072 {
2073 ErrorHandler& eh = context.error_handler;
2075
2076 if(type_ & (1 << kNullSchemaType))
2077 eh.AddExpectedType(GetNullString());
2078 if(type_ & (1 << kBooleanSchemaType))
2079 eh.AddExpectedType(GetBooleanString());
2080 if(type_ & (1 << kObjectSchemaType))
2081 eh.AddExpectedType(GetObjectString());
2082 if(type_ & (1 << kArraySchemaType))
2083 eh.AddExpectedType(GetArrayString());
2084 if(type_ & (1 << kStringSchemaType))
2085 eh.AddExpectedType(GetStringString());
2086
2087 if(type_ & (1 << kNumberSchemaType))
2088 eh.AddExpectedType(GetNumberString());
2089 else if(type_ & (1 << kIntegerSchemaType))
2090 eh.AddExpectedType(GetIntegerString());
2091
2092 eh.EndDisallowedType(actualType);
2093 }
2094
2113
2115 {
2118 {
2119 if(pattern)
2120 {
2121 pattern->~RegexType();
2122 AllocatorType::Free(pattern);
2123 }
2124 }
2127 };
2128
2137 SchemaArray allOf_;
2138 SchemaArray anyOf_;
2139 SchemaArray oneOf_;
2141 unsigned type_; // bitmask of kSchemaType
2144
2145 Property* properties_;
2147 PatternProperty* patternProperties_;
2156
2165
2169
2175
2177
2181};
2182
2183template <typename Stack, typename Ch>
2185{
2186 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index)
2187 {
2188 *documentStack.template Push<Ch>() = '/';
2189 char buffer[21];
2190 size_t length = static_cast<size_t>(
2191 (sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
2192 for(size_t i = 0; i < length; i++)
2193 *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
2194 }
2195};
2196
2197// Partial specialized version for char to prevent buffer copying.
2198template <typename Stack>
2199struct TokenHelper<Stack, char>
2200{
2201 RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index)
2202 {
2203 RAPIDJSON_IF_CONSTEXPR(sizeof(SizeType) == 4)
2204 {
2205 char* buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
2206 *buffer++ = '/';
2207 const char* end = internal::u32toa(index, buffer);
2208 documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
2209 }
2210 else
2211 {
2212 char* buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
2213 *buffer++ = '/';
2214 const char* end = internal::u64toa(index, buffer);
2215 documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
2216 }
2217 }
2218};
2219
2220} // namespace internal
2221
2223// IGenericRemoteSchemaDocumentProvider
2224
2225template <typename SchemaDocumentType>
2227{
2228 public:
2229 typedef typename SchemaDocumentType::Ch Ch;
2230 typedef typename SchemaDocumentType::ValueType ValueType;
2231 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
2232
2234 virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
2235 virtual const SchemaDocumentType*
2237 {
2238 // Default implementation just calls through for compatibility
2239 // Following line suppresses unused parameter warning
2240 (void)spec;
2241 // printf("GetRemoteDocument: %d %d\n", spec.draft, spec.oapi);
2243 }
2244};
2245
2247// GenericSchemaDocument
2248
2250
2258template <typename ValueT, typename Allocator = CrtAllocator>
2260{
2261 public:
2262 typedef ValueT ValueType;
2267 typedef typename EncodingType::Ch Ch;
2274 template <typename, typename, typename>
2276
2278
2290 explicit GenericSchemaDocument(const ValueType& document,
2291 const Ch* uri = 0,
2292 SizeType uriLength = 0,
2293 IRemoteSchemaDocumentProviderType* remoteProvider = 0,
2294 Allocator* allocator = 0,
2295 const PointerType& pointer = PointerType(), // PR #1393
2296 const Specification& spec = Specification(kDraft04))
2297 : remoteProvider_(remoteProvider),
2298 allocator_(allocator),
2299 ownAllocator_(),
2300 root_(),
2301 typeless_(),
2302 schemaMap_(allocator, kInitialSchemaMapSize),
2303 schemaRef_(allocator, kInitialSchemaRefSize),
2304 spec_(spec),
2305 error_(kObjectType),
2306 currentError_()
2307 {
2308 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::GenericSchemaDocument");
2309 if(!allocator_)
2310 ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
2311
2312 Ch noUri[1] = {0};
2313 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
2314 docId_ = UriType(uri_, allocator_);
2315
2316 typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
2317 new(typeless_) SchemaType(this,
2318 PointerType(),
2319 ValueType(kObjectType).Move(),
2320 ValueType(kObjectType).Move(),
2321 allocator_,
2322 docId_);
2323
2324 // Establish the schema draft or open api version.
2325 // We only ever look for '$schema' or 'swagger' or 'openapi' at the root of the document.
2326 SetSchemaSpecification(document);
2327
2328 // Generate root schema, it will call CreateSchema() to create sub-schemas,
2329 // And call HandleRefSchema() if there are $ref.
2330 // PR #1393 use input pointer if supplied
2331 root_ = typeless_;
2332 if(pointer.GetTokenCount() == 0)
2333 {
2334 CreateSchemaRecursive(&root_, pointer, document, document, docId_);
2335 }
2336 else if(const ValueType* v = pointer.Get(document))
2337 {
2338 CreateSchema(&root_, pointer, *v, document, docId_);
2339 }
2340 else
2341 {
2343 pointer.StringifyUriFragment(sb);
2345 PointerType(),
2346 sb.GetString(),
2347 static_cast<SizeType>(sb.GetSize() / sizeof(Ch)));
2348 }
2349
2350 RAPIDJSON_ASSERT(root_ != 0);
2351
2352 schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
2353 }
2354
2355#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
2357 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT
2358 : remoteProvider_(rhs.remoteProvider_),
2359 allocator_(rhs.allocator_),
2360 ownAllocator_(rhs.ownAllocator_),
2361 root_(rhs.root_),
2362 typeless_(rhs.typeless_),
2363 schemaMap_(std::move(rhs.schemaMap_)),
2364 schemaRef_(std::move(rhs.schemaRef_)),
2365 uri_(std::move(rhs.uri_)),
2366 docId_(std::move(rhs.docId_)),
2367 spec_(rhs.spec_),
2368 error_(std::move(rhs.error_)),
2369 currentError_(std::move(rhs.currentError_))
2370 {
2371 rhs.remoteProvider_ = 0;
2372 rhs.allocator_ = 0;
2373 rhs.ownAllocator_ = 0;
2374 rhs.typeless_ = 0;
2375 }
2376#endif
2377
2380 {
2381 while(!schemaMap_.Empty())
2382 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
2383
2384 if(typeless_)
2385 {
2386 typeless_->~SchemaType();
2387 Allocator::Free(typeless_);
2388 }
2389
2390 // these may contain some allocator data so clear before deleting ownAllocator_
2391 uri_.SetNull();
2392 error_.SetNull();
2393 currentError_.SetNull();
2394
2395 RAPIDJSON_DELETE(ownAllocator_);
2396 }
2397
2398 const GValue& GetURI() const { return uri_; }
2399
2400 const Specification& GetSpecification() const { return spec_; }
2401 bool IsSupportedSpecification() const { return spec_.IsSupported(); }
2402
2404 // Returns kDraftNone if document is silent
2405 static const Specification GetSpecification(const ValueType& document)
2406 {
2407 SchemaDraft draft = GetSchemaDraft(document);
2408 if(draft != kDraftNone)
2409 return Specification(draft);
2410 else
2411 {
2412 OpenApiVersion oapi = GetOpenApiVersion(document);
2413 if(oapi != kVersionNone)
2414 return Specification(oapi);
2415 }
2416 return Specification(kDraftNone);
2417 }
2418
2420 const SchemaType& GetRoot() const { return *root_; }
2421
2423 GValue& GetError() { return error_; }
2424 const GValue& GetError() const { return error_; }
2425
2427 {
2428 switch(schemaErrorCode)
2429 {
2430 case kSchemaErrorStartUnknown: return GetStartUnknownString();
2431 case kSchemaErrorRefPlainName: return GetRefPlainNameString();
2432 case kSchemaErrorRefInvalid: return GetRefInvalidString();
2433 case kSchemaErrorRefPointerInvalid: return GetRefPointerInvalidString();
2434 case kSchemaErrorRefUnknown: return GetRefUnknownString();
2435 case kSchemaErrorRefCyclical: return GetRefCyclicalString();
2436 case kSchemaErrorRefNoRemoteProvider: return GetRefNoRemoteProviderString();
2437 case kSchemaErrorRefNoRemoteSchema: return GetRefNoRemoteSchemaString();
2438 case kSchemaErrorRegexInvalid: return GetRegexInvalidString();
2439 case kSchemaErrorSpecUnknown: return GetSpecUnknownString();
2440 case kSchemaErrorSpecUnsupported: return GetSpecUnsupportedString();
2441 case kSchemaErrorSpecIllegal: return GetSpecIllegalString();
2442 case kSchemaErrorReadOnlyAndWriteOnly: return GetReadOnlyAndWriteOnlyString();
2443 default: return GetNullString();
2444 }
2445 }
2446
2448 void SchemaError(const SchemaErrorCode code, const PointerType& location)
2449 {
2450 currentError_ = GValue(kObjectType);
2451 AddCurrentError(code, location);
2452 }
2453
2456 const PointerType& location,
2457 const Ch* value,
2458 SizeType length)
2459 {
2460 currentError_ = GValue(kObjectType);
2461 currentError_.AddMember(
2462 GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
2463 AddCurrentError(code, location);
2464 }
2465
2468 const PointerType& location,
2469 const Ch* value,
2470 SizeType length,
2471 const PointerType& pointer)
2472 {
2473 currentError_ = GValue(kObjectType);
2474 currentError_.AddMember(
2475 GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
2476 currentError_.AddMember(GetOffsetString(),
2477 static_cast<SizeType>(pointer.GetParseErrorOffset() / sizeof(Ch)),
2478 *allocator_);
2479 AddCurrentError(code, location);
2480 }
2481
2482 private:
2487
2488 typedef const PointerType* SchemaRefPtr; // PR #1393
2489
2490 struct SchemaEntry
2491 {
2492 SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator)
2493 : pointer(p, allocator), schema(s), owned(o)
2494 {
2495 }
2496 ~SchemaEntry()
2497 {
2498 if(owned)
2499 {
2500 schema->~SchemaType();
2501 Allocator::Free(schema);
2502 }
2503 }
2504 PointerType pointer;
2505 SchemaType* schema;
2506 bool owned;
2507 };
2508
2509 void AddErrorInstanceLocation(GValue& result, const PointerType& location)
2510 {
2511 GenericStringBuffer<EncodingType> sb;
2512 location.StringifyUriFragment(sb);
2513 GValue instanceRef(
2514 sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), *allocator_);
2515 result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2516 }
2517
2518 void AddError(GValue& keyword, GValue& error)
2519 {
2520 typename GValue::MemberIterator member = error_.FindMember(keyword);
2521 if(member == error_.MemberEnd())
2522 error_.AddMember(keyword, error, *allocator_);
2523 else
2524 {
2525 if(member->value.IsObject())
2526 {
2527 GValue errors(kArrayType);
2528 errors.PushBack(member->value, *allocator_);
2529 member->value = errors;
2530 }
2531 member->value.PushBack(error, *allocator_);
2532 }
2533 }
2534
2535 void AddCurrentError(const SchemaErrorCode code, const PointerType& location)
2536 {
2537 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2538 currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2539 AddErrorInstanceLocation(currentError_, location);
2540 AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2541 }
2542
2543#define RAPIDJSON_STRING_(name, ...) \
2544 static const StringRefType& Get##name##String() \
2545 { \
2546 static const Ch s[] = {__VA_ARGS__, '\0'}; \
2547 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2548 return v; \
2549 }
2550
2551 RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2552 RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2553 RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
2554 RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
2555
2556 RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
2557 RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2558 RAPIDJSON_STRING_(
2559 SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
2560 RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
2561 RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2562 RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
2563 RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2564 RAPIDJSON_STRING_(RefPointerInvalid,
2565 'R',
2566 'e',
2567 'f',
2568 'P',
2569 'o',
2570 'i',
2571 'n',
2572 't',
2573 'e',
2574 'r',
2575 'I',
2576 'n',
2577 'v',
2578 'a',
2579 'l',
2580 'i',
2581 'd')
2582 RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2583 RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
2584 RAPIDJSON_STRING_(RefNoRemoteProvider,
2585 'R',
2586 'e',
2587 'f',
2588 'N',
2589 'o',
2590 'R',
2591 'e',
2592 'm',
2593 'o',
2594 't',
2595 'e',
2596 'P',
2597 'r',
2598 'o',
2599 'v',
2600 'i',
2601 'd',
2602 'e',
2603 'r')
2604 RAPIDJSON_STRING_(RefNoRemoteSchema,
2605 'R',
2606 'e',
2607 'f',
2608 'N',
2609 'o',
2610 'R',
2611 'e',
2612 'm',
2613 'o',
2614 't',
2615 'e',
2616 'S',
2617 'c',
2618 'h',
2619 'e',
2620 'm',
2621 'a')
2622 RAPIDJSON_STRING_(ReadOnlyAndWriteOnly,
2623 'R',
2624 'e',
2625 'a',
2626 'd',
2627 'O',
2628 'n',
2629 'l',
2630 'y',
2631 'A',
2632 'n',
2633 'd',
2634 'W',
2635 'r',
2636 'i',
2637 't',
2638 'e',
2639 'O',
2640 'n',
2641 'l',
2642 'y')
2643 RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2644
2645#undef RAPIDJSON_STRING_
2646
2647 // Static method to get schema draft of any schema document
2648 static SchemaDraft GetSchemaDraft(const ValueType& document)
2649 {
2650 static const Ch kDraft03String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2651 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2652 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2653 '3', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2654 static const Ch kDraft04String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2655 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2656 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2657 '4', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2658 static const Ch kDraft05String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2659 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2660 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2661 '5', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2662 static const Ch kDraft06String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2663 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2664 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2665 '6', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2666 static const Ch kDraft07String[] = {'h', 't', 't', 'p', ':', '/', '/', 'j', 's', 'o',
2667 'n', '-', 's', 'c', 'h', 'e', 'm', 'a', '.', 'o',
2668 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '-', '0',
2669 '7', '/', 's', 'c', 'h', 'e', 'm', 'a', '#', '\0'};
2670 static const Ch kDraft2019_09String[] = {
2671 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c',
2672 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/',
2673 '2', '0', '1', '9', '-', '0', '9', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0'};
2674 static const Ch kDraft2020_12String[] = {
2675 'h', 't', 't', 'p', 's', ':', '/', '/', 'j', 's', 'o', 'n', '-', 's', 'c',
2676 'h', 'e', 'm', 'a', '.', 'o', 'r', 'g', '/', 'd', 'r', 'a', 'f', 't', '/',
2677 '2', '0', '2', '0', '-', '1', '2', '/', 's', 'c', 'h', 'e', 'm', 'a', '\0'};
2678
2679 if(!document.IsObject())
2680 {
2681 return kDraftNone;
2682 }
2683
2684 // Get the schema draft from the $schema keyword at the supplied location
2685 typename ValueType::ConstMemberIterator itr =
2686 document.FindMember(SchemaType::GetSchemaString());
2687 if(itr != document.MemberEnd())
2688 {
2689 if(!itr->value.IsString())
2690 return kDraftUnknown;
2691 const UriType draftUri(itr->value);
2692 // Check base uri for match
2693 if(draftUri.Match(UriType(kDraft04String), false))
2694 return kDraft04;
2695 if(draftUri.Match(UriType(kDraft05String), false))
2696 return kDraft05;
2697 if(draftUri.Match(UriType(kDraft06String), false))
2698 return kDraft06;
2699 if(draftUri.Match(UriType(kDraft07String), false))
2700 return kDraft07;
2701 if(draftUri.Match(UriType(kDraft03String), false))
2702 return kDraft03;
2703 if(draftUri.Match(UriType(kDraft2019_09String), false))
2704 return kDraft2019_09;
2705 if(draftUri.Match(UriType(kDraft2020_12String), false))
2706 return kDraft2020_12;
2707 return kDraftUnknown;
2708 }
2709 // $schema not found
2710 return kDraftNone;
2711 }
2712
2713 // Get open api version of any schema document
2714 static OpenApiVersion GetOpenApiVersion(const ValueType& document)
2715 {
2716 static const Ch kVersion20String[] = {'2', '.', '0', '\0'};
2717 static const Ch kVersion30String[] = {'3', '.', '0', '.', '\0'}; // ignore patch level
2718 static const Ch kVersion31String[] = {'3', '.', '1', '.', '\0'}; // ignore patch level
2719 static SizeType len = internal::StrLen<Ch>(kVersion30String);
2720
2721 if(!document.IsObject())
2722 {
2723 return kVersionNone;
2724 }
2725
2726 // Get the open api version from the swagger / openapi keyword at the supplied location
2727 typename ValueType::ConstMemberIterator itr =
2728 document.FindMember(SchemaType::GetSwaggerString());
2729 if(itr == document.MemberEnd())
2730 itr = document.FindMember(SchemaType::GetOpenApiString());
2731 if(itr != document.MemberEnd())
2732 {
2733 if(!itr->value.IsString())
2734 return kVersionUnknown;
2735 const ValueType kVersion20Value(kVersion20String);
2736 if(kVersion20Value == itr->value)
2737 return kVersion20; // must match 2.0 exactly
2738 const ValueType kVersion30Value(kVersion30String);
2739 if(itr->value.GetStringLength() > len &&
2740 kVersion30Value == ValueType(itr->value.GetString(), len))
2741 return kVersion30; // must match 3.0.x
2742 const ValueType kVersion31Value(kVersion31String);
2743 if(itr->value.GetStringLength() > len &&
2744 kVersion31Value == ValueType(itr->value.GetString(), len))
2745 return kVersion31; // must match 3.1.x
2746 return kVersionUnknown;
2747 }
2748 // swagger or openapi not found
2749 return kVersionNone;
2750 }
2751
2752 // Get the draft of the schema or the open api version (which implies the draft).
2753 // Report an error if schema draft or open api version not supported or not recognized, or both
2754 // in document, and carry on.
2755 void SetSchemaSpecification(const ValueType& document)
2756 {
2757 // Look for '$schema', 'swagger' or 'openapi' keyword at document root
2758 SchemaDraft docDraft = GetSchemaDraft(document);
2759 OpenApiVersion docOapi = GetOpenApiVersion(document);
2760 // Error if both in document
2761 if(docDraft != kDraftNone && docOapi != kVersionNone)
2763 // Use document draft or open api version if present or use spec from constructor
2764 if(docDraft != kDraftNone)
2765 spec_ = Specification(docDraft);
2766 else if(docOapi != kVersionNone)
2767 spec_ = Specification(docOapi);
2768 // Error if draft or version unknown
2769 if(spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2771 else if(!spec_.IsSupported())
2773 }
2774
2775 // Changed by PR #1393
2776 void CreateSchemaRecursive(const SchemaType** schema,
2777 const PointerType& pointer,
2778 const ValueType& v,
2779 const ValueType& document,
2780 const UriType& id)
2781 {
2782 if(v.GetType() == kObjectType)
2783 {
2784 UriType newid = UriType(CreateSchema(schema, pointer, v, document, id), allocator_);
2785
2786 for(typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd();
2787 ++itr)
2788 CreateSchemaRecursive(
2789 0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2790 }
2791 else if(v.GetType() == kArrayType)
2792 for(SizeType i = 0; i < v.Size(); i++)
2793 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
2794 }
2795
2796 // Changed by PR #1393
2797 const UriType& CreateSchema(const SchemaType** schema,
2798 const PointerType& pointer,
2799 const ValueType& v,
2800 const ValueType& document,
2801 const UriType& id)
2802 {
2803 RAPIDJSON_ASSERT(pointer.IsValid());
2804 GenericStringBuffer<EncodingType> sb;
2805 pointer.StringifyUriFragment(sb);
2807 Method, "GenericSchemaDocument::CreateSchema", sb.GetString(), id.GetString());
2808 if(v.IsObject())
2809 {
2810 if(const SchemaType* sc = GetSchema(pointer))
2811 {
2812 if(schema)
2813 *schema = sc;
2814 AddSchemaRefs(const_cast<SchemaType*>(sc));
2815 }
2816 else if(!HandleRefSchema(pointer, schema, v, document, id))
2817 {
2818 // The new schema constructor adds itself and its $ref(s) to schemaMap_
2819 SchemaType* s = new(allocator_->Malloc(sizeof(SchemaType)))
2820 SchemaType(this, pointer, v, document, allocator_, id);
2821 if(schema)
2822 *schema = s;
2823 return s->GetId();
2824 }
2825 }
2826 else
2827 {
2828 if(schema)
2829 *schema = typeless_;
2830 AddSchemaRefs(typeless_);
2831 }
2832 return id;
2833 }
2834
2835 // Changed by PR #1393
2836 // TODO should this return a UriType& ?
2837 bool HandleRefSchema(const PointerType& source,
2838 const SchemaType** schema,
2839 const ValueType& v,
2840 const ValueType& document,
2841 const UriType& id)
2842 {
2843 typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2844 if(itr == v.MemberEnd())
2845 return false;
2846
2847 GenericStringBuffer<EncodingType> sb;
2848 source.StringifyUriFragment(sb);
2850 Method, "GenericSchemaDocument::HandleRefSchema", sb.GetString(), id.GetString());
2851 // Resolve the source pointer to the $ref'ed schema (finally)
2852 new(schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2853
2854 if(itr->value.IsString())
2855 {
2856 SizeType len = itr->value.GetStringLength();
2857 if(len == 0)
2859 else
2860 {
2861 // First resolve $ref against the in-scope id
2862 UriType scopeId = UriType(id, allocator_);
2863 UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2865 SchemaIds, id.GetString(), itr->value.GetString(), ref.GetString());
2866 // See if the resolved $ref minus the fragment matches a resolved id in this
2867 // document Search from the root. Returns the subschema in the document and its
2868 // absolute JSON pointer.
2869 PointerType basePointer = PointerType();
2870 const ValueType* base = FindId(document, ref, basePointer, docId_, false);
2871 if(!base)
2872 {
2873 // Remote reference - call the remote document provider
2874 if(!remoteProvider_)
2876 else
2877 {
2878 if(const GenericSchemaDocument* remoteDocument =
2879 remoteProvider_->GetRemoteDocument(ref, spec_))
2880 {
2881 const Ch* s = ref.GetFragString();
2882 len = ref.GetFragStringLength();
2883 if(len <= 1 || s[1] == '/')
2884 {
2885 // JSON pointer fragment, absolute in the remote schema
2886 const PointerType pointer(s, len, allocator_);
2887 if(!pointer.IsValid())
2890 else
2891 {
2892 // Get the subschema
2893 if(const SchemaType* sc = remoteDocument->GetSchema(pointer))
2894 {
2895 if(schema)
2896 *schema = sc;
2897 AddSchemaRefs(const_cast<SchemaType*>(sc));
2898 return true;
2899 }
2900 else
2902 source,
2903 ref.GetString(),
2904 ref.GetStringLength());
2905 }
2906 }
2907 else
2908 // Plain name fragment, not allowed in remote schema
2910 }
2911 else
2913 source,
2914 ref.GetString(),
2915 ref.GetStringLength());
2916 }
2917 }
2918 else
2919 { // Local reference
2920 const Ch* s = ref.GetFragString();
2921 len = ref.GetFragStringLength();
2922 if(len <= 1 || s[1] == '/')
2923 {
2924 // JSON pointer fragment, relative to the resolved URI
2925 const PointerType relPointer(s, len, allocator_);
2926 if(!relPointer.IsValid())
2928 kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
2929 else
2930 {
2931 // Get the subschema
2932 if(const ValueType* pv = relPointer.Get(*base))
2933 {
2934 // Now get the absolute JSON pointer by adding relative to base
2935 PointerType pointer(basePointer, allocator_);
2936 for(SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2937 pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2938 if(IsCyclicRef(pointer))
2940 source,
2941 ref.GetString(),
2942 ref.GetStringLength());
2943 else
2944 {
2945 // Call CreateSchema recursively, but first compute the in-scope
2946 // id for the $ref target as we have jumped there
2947 // TODO: cache pointer <-> id mapping
2948 size_t unresolvedTokenIndex;
2949 scopeId = pointer.GetUri(
2950 document, docId_, &unresolvedTokenIndex, allocator_);
2951 CreateSchema(schema, pointer, *pv, document, scopeId);
2952 return true;
2953 }
2954 }
2955 else
2957 source,
2958 ref.GetString(),
2959 ref.GetStringLength());
2960 }
2961 }
2962 else
2963 {
2964 // Plain name fragment, relative to the resolved URI
2965 // Not supported in open api 2.0 and 3.0
2966 PointerType pointer(allocator_);
2967 if(spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2969 // See if the fragment matches an id in this document.
2970 // Search from the base we just established. Returns the subschema in the
2971 // document and its absolute JSON pointer.
2972 else if(const ValueType* pv = FindId(*base,
2973 ref,
2974 pointer,
2975 UriType(ref.GetBaseString(),
2976 ref.GetBaseStringLength(),
2977 allocator_),
2978 true,
2979 basePointer))
2980 {
2981 if(IsCyclicRef(pointer))
2983 source,
2984 ref.GetString(),
2985 ref.GetStringLength());
2986 else
2987 {
2988 // Call CreateSchema recursively, but first compute the in-scope id
2989 // for the $ref target as we have jumped there
2990 // TODO: cache pointer <-> id mapping
2991 size_t unresolvedTokenIndex;
2992 scopeId = pointer.GetUri(
2993 document, docId_, &unresolvedTokenIndex, allocator_);
2994 CreateSchema(schema, pointer, *pv, document, scopeId);
2995 return true;
2996 }
2997 }
2998 else
3000 source,
3001 ref.GetString(),
3002 ref.GetStringLength());
3003 }
3004 }
3005 }
3006 }
3007
3008 // Invalid/Unknown $ref
3009 if(schema)
3010 *schema = typeless_;
3011 AddSchemaRefs(typeless_);
3012 return true;
3013 }
3014
3016 // If full specified use all URI else ignore fragment.
3017 // If found, return a pointer to the subschema and its JSON pointer.
3018 // TODO cache pointer <-> id mapping
3019 ValueType* FindId(const ValueType& doc,
3020 const UriType& finduri,
3021 PointerType& resptr,
3022 const UriType& baseuri,
3023 bool full,
3024 const PointerType& here = PointerType()) const
3025 {
3026 SizeType i = 0;
3027 ValueType* resval = 0;
3028 UriType tempuri = UriType(finduri, allocator_);
3029 UriType localuri = UriType(baseuri, allocator_);
3030 if(doc.GetType() == kObjectType)
3031 {
3032 // Establish the base URI of this object
3033 typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
3034 if(m != doc.MemberEnd() && m->value.GetType() == kStringType)
3035 {
3036 localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
3037 }
3038 // See if it matches
3039 if(localuri.Match(finduri, full))
3040 {
3042 "GenericSchemaDocument::FindId (match)",
3043 full ? localuri.GetString() : localuri.GetBaseString());
3044 resval = const_cast<ValueType*>(&doc);
3045 resptr = here;
3046 return resval;
3047 }
3048 // No match, continue looking
3049 for(m = doc.MemberBegin(); m != doc.MemberEnd(); ++m)
3050 {
3051 if(m->value.GetType() == kObjectType || m->value.GetType() == kArrayType)
3052 {
3053 resval = FindId(
3054 m->value,
3055 finduri,
3056 resptr,
3057 localuri,
3058 full,
3059 here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
3060 }
3061 if(resval)
3062 break;
3063 }
3064 }
3065 else if(doc.GetType() == kArrayType)
3066 {
3067 // Continue looking
3068 for(typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v)
3069 {
3070 if(v->GetType() == kObjectType || v->GetType() == kArrayType)
3071 {
3072 resval =
3073 FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
3074 }
3075 if(resval)
3076 break;
3077 i++;
3078 }
3079 }
3080 return resval;
3081 }
3082
3083 // Added by PR #1393
3084 void AddSchemaRefs(SchemaType* schema)
3085 {
3086 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaDocument::AddSchemaRefs");
3087 while(!schemaRef_.Empty())
3088 {
3089 SchemaRefPtr* ref = schemaRef_.template Pop<SchemaRefPtr>(1);
3090 SchemaEntry* entry = schemaMap_.template Push<SchemaEntry>();
3091 new(entry) SchemaEntry(**ref, schema, false, allocator_);
3092 }
3093 }
3094
3095 // Added by PR #1393
3096 bool IsCyclicRef(const PointerType& pointer) const
3097 {
3098 for(const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>();
3099 ref != schemaRef_.template End<SchemaRefPtr>();
3100 ++ref)
3101 if(pointer == **ref)
3102 return true;
3103 return false;
3104 }
3105
3106 const SchemaType* GetSchema(const PointerType& pointer) const
3107 {
3108 for(const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
3109 target != schemaMap_.template End<SchemaEntry>();
3110 ++target)
3111 if(pointer == target->pointer)
3112 return target->schema;
3113 return 0;
3114 }
3115
3116 PointerType GetPointer(const SchemaType* schema) const
3117 {
3118 for(const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
3119 target != schemaMap_.template End<SchemaEntry>();
3120 ++target)
3121 if(schema == target->schema)
3122 return target->pointer;
3123 return PointerType();
3124 }
3125
3126 const SchemaType* GetTypeless() const { return typeless_; }
3127
3128 static const size_t kInitialSchemaMapSize = 64;
3129 static const size_t kInitialSchemaRefSize = 64;
3130
3131 IRemoteSchemaDocumentProviderType* remoteProvider_;
3132 Allocator* allocator_;
3133 Allocator* ownAllocator_;
3134 const SchemaType* root_;
3135 SchemaType* typeless_;
3136 internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
3137 internal::Stack<Allocator> schemaRef_; // Stores Pointer(s) from $ref(s) until resolved
3138 GValue uri_; // Schema document URI
3139 UriType docId_;
3140 Specification spec_;
3141 GValue error_;
3142 GValue currentError_;
3143};
3144
3149
3151// GenericSchemaValidator
3152
3154
3165template <typename SchemaDocumentType,
3166 typename OutputHandler =
3168 typename StateAllocator = CrtAllocator>
3170 : public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
3172 public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
3173{
3174 public:
3175 typedef typename SchemaDocumentType::SchemaType SchemaType;
3176 typedef typename SchemaDocumentType::PointerType PointerType;
3178 typedef typename SchemaType::SValue SValue;
3179 typedef typename EncodingType::Ch Ch;
3182
3184
3190 GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3191 StateAllocator* allocator = 0,
3192 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3193 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3194 : schemaDocument_(&schemaDocument),
3195 root_(schemaDocument.GetRoot()),
3196 stateAllocator_(allocator),
3197 ownStateAllocator_(0),
3198 schemaStack_(allocator, schemaStackCapacity),
3199 documentStack_(allocator, documentStackCapacity),
3200 outputHandler_(0),
3201 error_(kObjectType),
3202 currentError_(),
3203 missingDependents_(),
3204 valid_(true),
3205 flags_(kValidateDefaultFlags),
3206 depth_(0)
3207 {
3208 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::GenericSchemaValidator");
3209 }
3210
3212
3218 GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3219 OutputHandler& outputHandler,
3220 StateAllocator* allocator = 0,
3221 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3222 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3223 : schemaDocument_(&schemaDocument),
3224 root_(schemaDocument.GetRoot()),
3225 stateAllocator_(allocator),
3226 ownStateAllocator_(0),
3227 schemaStack_(allocator, schemaStackCapacity),
3228 documentStack_(allocator, documentStackCapacity),
3229 outputHandler_(&outputHandler),
3230 error_(kObjectType),
3231 currentError_(),
3232 missingDependents_(),
3233 valid_(true),
3234 flags_(kValidateDefaultFlags),
3235 depth_(0)
3236 {
3238 "GenericSchemaValidator::GenericSchemaValidator (output handler)");
3239 }
3240
3243 {
3244 Reset();
3245 RAPIDJSON_DELETE(ownStateAllocator_);
3246 }
3247
3249 void Reset()
3250 {
3251 while(!schemaStack_.Empty())
3252 PopSchema();
3253 documentStack_.Clear();
3254 ResetError();
3255 }
3256
3259 {
3260 error_.SetObject();
3261 currentError_.SetNull();
3262 missingDependents_.SetNull();
3263 valid_ = true;
3264 }
3265
3267 void SetValidateFlags(unsigned flags) { flags_ = flags; }
3268 virtual unsigned GetValidateFlags() const { return flags_; }
3269
3270 virtual bool IsValid() const
3271 {
3272 if(!valid_)
3273 return false;
3274 if(GetContinueOnErrors() && !error_.ObjectEmpty())
3275 return false;
3276 return true;
3277 }
3278
3279
3281 ValueType& GetError() { return error_; }
3282 const ValueType& GetError() const { return error_; }
3283
3285 // If reporting all errors, the stack will be empty.
3287 {
3288 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
3289 }
3290
3292 // If reporting all errors, the stack will be empty, so return "errors".
3294 {
3295 if(!schemaStack_.Empty())
3296 return CurrentContext().invalidKeyword;
3297 if(GetContinueOnErrors() && !error_.ObjectEmpty())
3298 return static_cast<const Ch*>(GetErrorsString());
3299 return 0;
3300 }
3301
3303 // If reporting all errors, the stack will be empty, so return kValidateErrors.
3305 {
3306 if(!schemaStack_.Empty())
3307 return CurrentContext().invalidCode;
3308 if(GetContinueOnErrors() && !error_.ObjectEmpty())
3309 return kValidateErrors;
3310 return kValidateErrorNone;
3311 }
3312
3314 // If reporting all errors, the stack will be empty.
3316 {
3317 if(documentStack_.Empty())
3318 {
3319 return PointerType();
3320 }
3321 else
3322 {
3323 return PointerType(documentStack_.template Bottom<Ch>(),
3324 documentStack_.GetSize() / sizeof(Ch));
3325 }
3326 }
3327
3328 void NotMultipleOf(int64_t actual, const SValue& expected)
3329 {
3330 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3331 }
3332 void NotMultipleOf(uint64_t actual, const SValue& expected)
3333 {
3334 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3335 }
3336 void NotMultipleOf(double actual, const SValue& expected)
3337 {
3338 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
3339 }
3340 void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive)
3341 {
3342 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3343 ValueType(actual).Move(),
3344 expected,
3345 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3346 }
3347 void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive)
3348 {
3349 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3350 ValueType(actual).Move(),
3351 expected,
3352 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3353 }
3354 void AboveMaximum(double actual, const SValue& expected, bool exclusive)
3355 {
3356 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum : kValidateErrorMaximum,
3357 ValueType(actual).Move(),
3358 expected,
3359 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
3360 }
3361 void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive)
3362 {
3363 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3364 ValueType(actual).Move(),
3365 expected,
3366 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3367 }
3368 void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive)
3369 {
3370 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3371 ValueType(actual).Move(),
3372 expected,
3373 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3374 }
3375 void BelowMinimum(double actual, const SValue& expected, bool exclusive)
3376 {
3377 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum : kValidateErrorMinimum,
3378 ValueType(actual).Move(),
3379 expected,
3380 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
3381 }
3382
3383 void TooLong(const Ch* str, SizeType length, SizeType expected)
3384 {
3385 AddNumberError(kValidateErrorMaxLength,
3386 ValueType(str, length, GetStateAllocator()).Move(),
3387 SValue(expected).Move());
3388 }
3389 void TooShort(const Ch* str, SizeType length, SizeType expected)
3390 {
3391 AddNumberError(kValidateErrorMinLength,
3392 ValueType(str, length, GetStateAllocator()).Move(),
3393 SValue(expected).Move());
3394 }
3395 void DoesNotMatch(const Ch* str, SizeType length)
3396 {
3397 currentError_.SetObject();
3398 currentError_.AddMember(GetActualString(),
3399 ValueType(str, length, GetStateAllocator()).Move(),
3400 GetStateAllocator());
3401 AddCurrentError(kValidateErrorPattern);
3402 }
3403
3405 {
3406 currentError_.SetObject();
3407 currentError_.AddMember(
3408 GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
3409 AddCurrentError(kValidateErrorAdditionalItems, true);
3410 }
3411 void TooFewItems(SizeType actualCount, SizeType expectedCount)
3412 {
3413 AddNumberError(
3414 kValidateErrorMinItems, ValueType(actualCount).Move(), SValue(expectedCount).Move());
3415 }
3416 void TooManyItems(SizeType actualCount, SizeType expectedCount)
3417 {
3418 AddNumberError(
3419 kValidateErrorMaxItems, ValueType(actualCount).Move(), SValue(expectedCount).Move());
3420 }
3421 void DuplicateItems(SizeType index1, SizeType index2)
3422 {
3423 ValueType duplicates(kArrayType);
3424 duplicates.PushBack(index1, GetStateAllocator());
3425 duplicates.PushBack(index2, GetStateAllocator());
3426 currentError_.SetObject();
3427 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
3428 AddCurrentError(kValidateErrorUniqueItems, true);
3429 }
3430
3431 void TooManyProperties(SizeType actualCount, SizeType expectedCount)
3432 {
3433 AddNumberError(kValidateErrorMaxProperties,
3434 ValueType(actualCount).Move(),
3435 SValue(expectedCount).Move());
3436 }
3437 void TooFewProperties(SizeType actualCount, SizeType expectedCount)
3438 {
3439 AddNumberError(kValidateErrorMinProperties,
3440 ValueType(actualCount).Move(),
3441 SValue(expectedCount).Move());
3442 }
3443 void StartMissingProperties() { currentError_.SetArray(); }
3444 void AddMissingProperty(const SValue& name)
3445 {
3446 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
3447 }
3449 {
3450 if(currentError_.Empty())
3451 return false;
3452 ValueType error(kObjectType);
3453 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
3454 currentError_ = error;
3455 AddCurrentError(kValidateErrorRequired);
3456 return true;
3457 }
3458 void PropertyViolations(ISchemaValidator** subvalidators, SizeType count)
3459 {
3460 for(SizeType i = 0; i < count; ++i)
3461 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
3462 }
3463 void DisallowedProperty(const Ch* name, SizeType length)
3464 {
3465 currentError_.SetObject();
3466 currentError_.AddMember(GetDisallowedString(),
3467 ValueType(name, length, GetStateAllocator()).Move(),
3468 GetStateAllocator());
3469 AddCurrentError(kValidateErrorAdditionalProperties, true);
3470 }
3471
3472 void StartDependencyErrors() { currentError_.SetObject(); }
3473 void StartMissingDependentProperties() { missingDependents_.SetArray(); }
3474 void AddMissingDependentProperty(const SValue& targetName)
3475 {
3476 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(),
3477 GetStateAllocator());
3478 }
3480 {
3481 if(!missingDependents_.Empty())
3482 {
3483 // Create equivalent 'required' error
3484 ValueType error(kObjectType);
3486 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
3487 AddErrorCode(error, code);
3488 AddErrorInstanceLocation(error, false);
3489 // When appending to a pointer ensure its allocator is used
3490 PointerType schemaRef = GetInvalidSchemaPointer().Append(
3492 &GetInvalidSchemaPointer().GetAllocator());
3493 AddErrorSchemaLocation(error,
3494 schemaRef.Append(sourceName.GetString(),
3495 sourceName.GetStringLength(),
3496 &GetInvalidSchemaPointer().GetAllocator()));
3497 ValueType wrapper(kObjectType);
3498 wrapper.AddMember(
3499 ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(),
3500 error,
3501 GetStateAllocator());
3502 currentError_.AddMember(
3503 ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
3504 }
3505 }
3506 void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator)
3507 {
3508 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
3509 static_cast<GenericSchemaValidator*>(subvalidator)->GetError(),
3510 GetStateAllocator());
3511 }
3513 {
3514 if(currentError_.ObjectEmpty())
3515 return false;
3516 ValueType error(kObjectType);
3517 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
3518 currentError_ = error;
3519 AddCurrentError(kValidateErrorDependencies);
3520 return true;
3521 }
3522
3524 {
3525 currentError_.SetObject();
3526 AddCurrentError(code);
3527 }
3528 void StartDisallowedType() { currentError_.SetArray(); }
3529 void AddExpectedType(const typename SchemaType::ValueType& expectedType)
3530 {
3531 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(),
3532 GetStateAllocator());
3533 }
3534 void EndDisallowedType(const typename SchemaType::ValueType& actualType)
3535 {
3536 ValueType error(kObjectType);
3537 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
3538 error.AddMember(GetActualString(),
3539 ValueType(actualType, GetStateAllocator()).Move(),
3540 GetStateAllocator());
3541 currentError_ = error;
3542 AddCurrentError(kValidateErrorType);
3543 }
3544 void NotAllOf(ISchemaValidator** subvalidators, SizeType count)
3545 {
3546 // Treat allOf like oneOf and anyOf to match
3547 // https://rapidjson.org/md_doc_schema.html#allOf-anyOf-oneOf
3548 AddErrorArray(kValidateErrorAllOf, subvalidators, count);
3549 // for (SizeType i = 0; i < count; ++i) {
3550 // MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
3551 // }
3552 }
3553 void NoneOf(ISchemaValidator** subvalidators, SizeType count)
3554 {
3555 AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
3556 }
3557 void NotOneOf(ISchemaValidator** subvalidators, SizeType count)
3558 {
3559 AddErrorArray(kValidateErrorOneOf, subvalidators, count);
3560 }
3561 void MultipleOneOf(SizeType index1, SizeType index2)
3562 {
3563 ValueType matches(kArrayType);
3564 matches.PushBack(index1, GetStateAllocator());
3565 matches.PushBack(index2, GetStateAllocator());
3566 currentError_.SetObject();
3567 currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
3568 AddCurrentError(kValidateErrorOneOfMatch);
3569 }
3571 {
3572 currentError_.SetObject();
3573 AddCurrentError(kValidateErrorNot);
3574 }
3576 {
3577 currentError_.SetObject();
3578 AddCurrentError(kValidateErrorReadOnly);
3579 }
3581 {
3582 currentError_.SetObject();
3583 AddCurrentError(kValidateErrorWriteOnly);
3584 }
3585
3586#define RAPIDJSON_STRING_(name, ...) \
3587 static const StringRefType& Get##name##String() \
3588 { \
3589 static const Ch s[] = {__VA_ARGS__, '\0'}; \
3590 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
3591 return v; \
3592 }
3593
3594 RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
3595 RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
3596 RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
3597 RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
3598 RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
3599 RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
3600 RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
3601 RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
3602 RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
3603 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
3604 RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
3605
3606#undef RAPIDJSON_STRING_
3607
3608#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1) \
3609 if(!valid_) \
3610 return false; \
3611 if((!BeginValue() && !GetContinueOnErrors()) || \
3612 (!CurrentSchema().method arg1 && !GetContinueOnErrors())) \
3613 { \
3614 *documentStack_.template Push<Ch>() = '\0'; \
3615 documentStack_.template Pop<Ch>(1); \
3616 RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>()); \
3617 valid_ = false; \
3618 return valid_; \
3619 }
3620
3621#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2) \
3622 for(Context* context = schemaStack_.template Bottom<Context>(); \
3623 context != schemaStack_.template End<Context>(); \
3624 context++) \
3625 { \
3626 if(context->hasher) \
3627 static_cast<HasherType*>(context->hasher)->method arg2; \
3628 if(context->validators) \
3629 for(SizeType i_ = 0; i_ < context->validatorCount; i_++) \
3630 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2; \
3631 if(context->patternPropertiesValidators) \
3632 for(SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++) \
3633 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_]) \
3634 ->method arg2; \
3635 }
3636
3637#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2) \
3638 valid_ = \
3639 (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2); \
3640 return valid_;
3641
3642#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
3643 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1); \
3644 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2); \
3645 RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
3646
3647 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ()); }
3648 bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
3649 bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
3650 bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
3651 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
3652 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
3653 bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
3654 bool RawNumber(const Ch* str, SizeType length, bool copy)
3655 {
3657 String, (CurrentContext(), str, length, copy), (str, length, copy));
3658 }
3659 bool String(const Ch* str, SizeType length, bool copy)
3660 {
3662 String, (CurrentContext(), str, length, copy), (str, length, copy));
3663 }
3664
3666 {
3667 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartObject");
3668 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
3670 valid_ = !outputHandler_ || outputHandler_->StartObject();
3671 return valid_;
3672 }
3673
3674 bool Key(const Ch* str, SizeType len, bool copy)
3675 {
3676 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::Key", str);
3677 if(!valid_)
3678 return false;
3679 AppendToken(str, len);
3680 if(!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors())
3681 {
3682 valid_ = false;
3683 return valid_;
3684 }
3686 valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
3687 return valid_;
3688 }
3689
3690 bool EndObject(SizeType memberCount)
3691 {
3692 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndObject");
3693 if(!valid_)
3694 return false;
3696 if(!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors())
3697 {
3698 valid_ = false;
3699 return valid_;
3700 }
3702 }
3703
3705 {
3706 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::StartArray");
3707 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
3709 valid_ = !outputHandler_ || outputHandler_->StartArray();
3710 return valid_;
3711 }
3712
3713 bool EndArray(SizeType elementCount)
3714 {
3715 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndArray");
3716 if(!valid_)
3717 return false;
3719 if(!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors())
3720 {
3721 valid_ = false;
3722 return valid_;
3723 }
3724 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
3725 }
3726
3727#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
3728#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
3729#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
3730
3731 // Implementation of ISchemaStateFactory<SchemaType>
3732 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root,
3733 const bool inheritContinueOnErrors)
3734 {
3735 *documentStack_.template Push<Ch>() = '\0';
3736 documentStack_.template Pop<Ch>(1);
3737 ISchemaValidator* sv = new(GetStateAllocator().Malloc(sizeof(GenericSchemaValidator)))
3738 GenericSchemaValidator(*schemaDocument_,
3739 root,
3740 documentStack_.template Bottom<char>(),
3741 documentStack_.GetSize(),
3742 depth_ + 1,
3743 &GetStateAllocator());
3744 sv->SetValidateFlags(inheritContinueOnErrors
3746 : GetValidateFlags() &
3747 ~static_cast<unsigned>(kValidateContinueOnErrorFlag));
3748 return sv;
3749 }
3750
3751 virtual void DestroySchemaValidator(ISchemaValidator* validator)
3752 {
3753 GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
3755 StateAllocator::Free(v);
3756 }
3757
3758 virtual void* CreateHasher()
3759 {
3760 return new(GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
3761 }
3762
3763 virtual uint64_t GetHashCode(void* hasher)
3764 {
3765 return static_cast<HasherType*>(hasher)->GetHashCode();
3766 }
3767
3768 virtual void DestroryHasher(void* hasher)
3769 {
3770 HasherType* h = static_cast<HasherType*>(hasher);
3771 h->~HasherType();
3772 StateAllocator::Free(h);
3773 }
3774
3775 virtual void* MallocState(size_t size) { return GetStateAllocator().Malloc(size); }
3776
3777 virtual void FreeState(void* p) { StateAllocator::Free(p); }
3778 // End of implementation of ISchemaStateFactory<SchemaType>
3779
3780 private:
3781 typedef typename SchemaType::Context Context;
3782 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
3784
3785 GenericSchemaValidator(const SchemaDocumentType& schemaDocument,
3786 const SchemaType& root,
3787 const char* basePath,
3788 size_t basePathSize,
3789 unsigned depth,
3790 StateAllocator* allocator = 0,
3791 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
3792 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
3793 : schemaDocument_(&schemaDocument),
3794 root_(root),
3795 stateAllocator_(allocator),
3796 ownStateAllocator_(0),
3797 schemaStack_(allocator, schemaStackCapacity),
3798 documentStack_(allocator, documentStackCapacity),
3799 outputHandler_(0),
3800 error_(kObjectType),
3801 currentError_(),
3802 missingDependents_(),
3803 valid_(true),
3804 flags_(kValidateDefaultFlags),
3805 depth_(depth)
3806 {
3808 "GenericSchemaValidator::GenericSchemaValidator (internal)",
3809 basePath && basePathSize ? basePath : "");
3810 if(basePath && basePathSize)
3811 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
3812 }
3813
3814 StateAllocator& GetStateAllocator()
3815 {
3816 if(!stateAllocator_)
3817 stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)();
3818 return *stateAllocator_;
3819 }
3820
3821 bool GetContinueOnErrors() const { return flags_ & kValidateContinueOnErrorFlag; }
3822
3823 bool BeginValue()
3824 {
3825 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::BeginValue");
3826 if(schemaStack_.Empty())
3827 PushSchema(root_);
3828 else
3829 {
3830 if(CurrentContext().inArray)
3831 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(
3832 documentStack_, CurrentContext().arrayElementIndex);
3833
3834 if(!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
3835 return false;
3836
3837 SizeType count = CurrentContext().patternPropertiesSchemaCount;
3838 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
3839 typename Context::PatternValidatorType patternValidatorType =
3840 CurrentContext().valuePatternValidatorType;
3841 bool valueUniqueness = CurrentContext().valueUniqueness;
3842 RAPIDJSON_ASSERT(CurrentContext().valueSchema);
3843 PushSchema(*CurrentContext().valueSchema);
3844
3845 if(count > 0)
3846 {
3847 CurrentContext().objectPatternValidatorType = patternValidatorType;
3848 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3849 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3850 va =
3851 static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
3852 std::memset(va, 0, sizeof(ISchemaValidator*) * count);
3853 for(SizeType i = 0; i < count; i++)
3854 va[validatorCount++] =
3855 CreateSchemaValidator(*sa[i], true); // Inherit continueOnError
3856 }
3857
3858 CurrentContext().arrayUniqueness = valueUniqueness;
3859 }
3860 return true;
3861 }
3862
3863 bool EndValue()
3864 {
3865 RAPIDJSON_SCHEMA_PRINT(Method, "GenericSchemaValidator::EndValue");
3866 if(!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3867 return false;
3868
3869 GenericStringBuffer<EncodingType> sb;
3870 schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3871 *documentStack_.template Push<Ch>() = '\0';
3872 documentStack_.template Pop<Ch>(1);
3874 ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3875 void* hasher = CurrentContext().hasher;
3876 uint64_t h = hasher && CurrentContext().arrayUniqueness
3877 ? static_cast<HasherType*>(hasher)->GetHashCode()
3878 : 0;
3879
3880 PopSchema();
3881
3882 if(!schemaStack_.Empty())
3883 {
3884 Context& context = CurrentContext();
3885 // Only check uniqueness if there is a hasher
3886 if(hasher && context.valueUniqueness)
3887 {
3888 HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
3889 if(!a)
3890 CurrentContext().arrayElementHashCodes = a =
3891 new(GetStateAllocator().Malloc(sizeof(HashCodeArray)))
3892 HashCodeArray(kArrayType);
3893 for(typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End();
3894 ++itr)
3895 if(itr->GetUint64() == h)
3896 {
3897 DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
3898 // Cleanup before returning if continuing
3899 if(GetContinueOnErrors())
3900 {
3901 a->PushBack(h, GetStateAllocator());
3902 while(!documentStack_.Empty() &&
3903 *documentStack_.template Pop<Ch>(1) != '/')
3904 ;
3905 }
3907 }
3908 a->PushBack(h, GetStateAllocator());
3909 }
3910 }
3911
3912 // Remove the last token of document pointer
3913 while(!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
3914 ;
3915
3916 return true;
3917 }
3918
3919 void AppendToken(const Ch* str, SizeType len)
3920 {
3921 documentStack_.template Reserve<Ch>(
3922 1 + len * 2); // worst case all characters are escaped as two characters
3923 *documentStack_.template PushUnsafe<Ch>() = '/';
3924 for(SizeType i = 0; i < len; i++)
3925 {
3926 if(str[i] == '~')
3927 {
3928 *documentStack_.template PushUnsafe<Ch>() = '~';
3929 *documentStack_.template PushUnsafe<Ch>() = '0';
3930 }
3931 else if(str[i] == '/')
3932 {
3933 *documentStack_.template PushUnsafe<Ch>() = '~';
3934 *documentStack_.template PushUnsafe<Ch>() = '1';
3935 }
3936 else
3937 *documentStack_.template PushUnsafe<Ch>() = str[i];
3938 }
3939 }
3940
3941 RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema)
3942 {
3943 new(schemaStack_.template Push<Context>()) Context(*this, *this, &schema, flags_);
3944 }
3945
3946 RAPIDJSON_FORCEINLINE void PopSchema()
3947 {
3948 Context* c = schemaStack_.template Pop<Context>(1);
3949 if(HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes))
3950 {
3951 a->~HashCodeArray();
3952 StateAllocator::Free(a);
3953 }
3954 c->~Context();
3955 }
3956
3957 void AddErrorInstanceLocation(ValueType& result, bool parent)
3958 {
3959 GenericStringBuffer<EncodingType> sb;
3960 PointerType instancePointer = GetInvalidDocumentPointer();
3961 ((parent && instancePointer.GetTokenCount() > 0)
3962 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3963 : instancePointer)
3964 .StringifyUriFragment(sb);
3965 ValueType instanceRef(
3966 sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator());
3967 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3968 }
3969
3970 void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType())
3971 {
3972 GenericStringBuffer<EncodingType> sb;
3973 SizeType len = CurrentSchema().GetURI().GetStringLength();
3974 if(len)
3975 memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len * sizeof(Ch));
3976 if(schema.GetTokenCount())
3977 schema.StringifyUriFragment(sb);
3978 else
3979 GetInvalidSchemaPointer().StringifyUriFragment(sb);
3980 ValueType schemaRef(
3981 sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)), GetStateAllocator());
3982 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3983 }
3984
3985 void AddErrorCode(ValueType& result, const ValidateErrorCode code)
3986 {
3987 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3988 }
3989
3990 void AddError(ValueType& keyword, ValueType& error)
3991 {
3992 typename ValueType::MemberIterator member = error_.FindMember(keyword);
3993 if(member == error_.MemberEnd())
3994 error_.AddMember(keyword, error, GetStateAllocator());
3995 else
3996 {
3997 if(member->value.IsObject())
3998 {
3999 ValueType errors(kArrayType);
4000 errors.PushBack(member->value, GetStateAllocator());
4001 member->value = errors;
4002 }
4003 member->value.PushBack(error, GetStateAllocator());
4004 }
4005 }
4006
4007 void AddCurrentError(const ValidateErrorCode code, bool parent = false)
4008 {
4009 AddErrorCode(currentError_, code);
4010 AddErrorInstanceLocation(currentError_, parent);
4011 AddErrorSchemaLocation(currentError_);
4012 AddError(
4013 ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(), false).Move(),
4014 currentError_);
4015 }
4016
4017 void MergeError(ValueType& other)
4018 {
4019 for(typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd();
4020 it != end;
4021 ++it)
4022 {
4023 AddError(it->name, it->value);
4024 }
4025 }
4026
4027 void AddNumberError(const ValidateErrorCode code,
4028 ValueType& actual,
4029 const SValue& expected,
4030 const typename SchemaType::ValueType& (*exclusive)() = 0)
4031 {
4032 currentError_.SetObject();
4033 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
4034 currentError_.AddMember(GetExpectedString(),
4035 ValueType(expected, GetStateAllocator()).Move(),
4036 GetStateAllocator());
4037 if(exclusive)
4038 currentError_.AddMember(
4039 ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
4040 AddCurrentError(code);
4041 }
4042
4043 void
4044 AddErrorArray(const ValidateErrorCode code, ISchemaValidator** subvalidators, SizeType count)
4045 {
4046 ValueType errors(kArrayType);
4047 for(SizeType i = 0; i < count; ++i)
4048 errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(),
4049 GetStateAllocator());
4050 currentError_.SetObject();
4051 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
4052 AddCurrentError(code);
4053 }
4054
4055 const SchemaType& CurrentSchema() const
4056 {
4057 return *schemaStack_.template Top<Context>()->schema;
4058 }
4059 Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
4060 const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
4061
4062 static const size_t kDefaultSchemaStackCapacity = 1024;
4063 static const size_t kDefaultDocumentStackCapacity = 256;
4064 const SchemaDocumentType* schemaDocument_;
4065 const SchemaType& root_;
4066 StateAllocator* stateAllocator_;
4067 StateAllocator* ownStateAllocator_;
4068 internal::Stack<StateAllocator>
4069 schemaStack_;
4070 internal::Stack<StateAllocator>
4071 documentStack_;
4072 OutputHandler* outputHandler_;
4073 ValueType error_;
4074 ValueType currentError_;
4075 ValueType missingDependents_;
4076 bool valid_;
4077 unsigned flags_;
4078 unsigned depth_;
4079};
4080
4082
4084// SchemaValidatingReader
4085
4087
4096template <unsigned parseFlags,
4097 typename InputStream,
4098 typename SourceEncoding,
4099 typename SchemaDocumentType = SchemaDocument,
4100 typename StackAllocator = CrtAllocator>
4102{
4103 public:
4104 typedef typename SchemaDocumentType::PointerType PointerType;
4105 typedef typename InputStream::Ch Ch;
4107
4109
4113 SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd)
4114 : is_(is),
4115 sd_(sd),
4116 invalidSchemaKeyword_(),
4117 invalidSchemaCode_(kValidateErrorNone),
4118 error_(kObjectType),
4119 isValid_(true)
4120 {
4121 }
4122
4123 template <typename Handler>
4124 bool operator()(Handler& handler)
4125 {
4127 reader;
4129 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
4130
4131 isValid_ = validator.IsValid();
4132 if(isValid_)
4133 {
4134 invalidSchemaPointer_ = PointerType();
4135 invalidSchemaKeyword_ = 0;
4136 invalidDocumentPointer_ = PointerType();
4137 error_.SetObject();
4138 }
4139 else
4140 {
4141 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
4142 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
4143 invalidSchemaCode_ = validator.GetInvalidSchemaCode();
4144 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
4145 error_.CopyFrom(validator.GetError(), allocator_);
4146 }
4147
4148 return parseResult_;
4149 }
4150
4151 const ParseResult& GetParseResult() const { return parseResult_; }
4152 bool IsValid() const { return isValid_; }
4153 const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
4154 const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
4155 const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
4156 const ValueType& GetError() const { return error_; }
4157 ValidateErrorCode GetInvalidSchemaCode() const { return invalidSchemaCode_; }
4158
4159 private:
4160 InputStream& is_;
4161 const SchemaDocumentType& sd_;
4162
4163 ParseResult parseResult_;
4164 PointerType invalidSchemaPointer_;
4165 const Ch* invalidSchemaKeyword_;
4166 PointerType invalidDocumentPointer_;
4167 ValidateErrorCode invalidSchemaCode_;
4168 StackAllocator allocator_;
4169 ValueType error_;
4170 bool isValid_;
4171};
4172
4174RAPIDJSON_DIAG_POP
4175
4176#endif // RAPIDJSON_SCHEMA_H_
C-runtime library allocator.
Definition allocators.h:83
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition pointer.h:76
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition pointer.h:309
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition reader.h:604
JSON schema document.
Definition schema.h:2260
GenericSchemaDocument(const ValueType &document, const Ch *uri=0, SizeType uriLength=0, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0, const PointerType &pointer=PointerType(), const Specification &spec=Specification(kDraft04))
Constructor.
Definition schema.h:2290
static const StringRefType & GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode)
Definition schema.h:2426
const GValue & GetURI() const
Definition schema.h:2398
const SchemaType & GetRoot() const
Get the root schema.
Definition schema.h:2420
~GenericSchemaDocument()
Destructor.
Definition schema.h:2379
GenericValue< EncodingType, AllocatorType > GValue
Definition schema.h:2270
void SchemaError(const SchemaErrorCode code, const PointerType &location)
Default error method.
Definition schema.h:2448
const Specification & GetSpecification() const
Definition schema.h:2400
const GValue & GetError() const
Definition schema.h:2424
void SchemaErrorValue(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length)
Method for error with single string value insert.
Definition schema.h:2455
static const Specification GetSpecification(const ValueType &document)
Static method to get the specification of any schema document.
Definition schema.h:2405
IGenericRemoteSchemaDocumentProvider< GenericSchemaDocument > IRemoteSchemaDocumentProviderType
Definition schema.h:2264
EncodingType::Ch Ch
Definition schema.h:2267
GValue & GetError()
Gets the error object.
Definition schema.h:2423
CrtAllocator AllocatorType
Definition schema.h:2265
internal::Schema< GenericSchemaDocument > SchemaType
Definition schema.h:2268
ValueType::EncodingType EncodingType
Definition schema.h:2266
bool IsSupportedSpecification() const
Definition schema.h:2401
GenericStringRef< Ch > StringRefType
Definition schema.h:2272
Value ValueType
Definition schema.h:2262
GenericPointer< ValueType, CrtAllocator > PointerType
Definition schema.h:2269
friend class GenericSchemaValidator
Definition schema.h:2275
GenericUri< ValueType, CrtAllocator > UriType
Definition schema.h:2271
void SchemaErrorPointer(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length, const PointerType &pointer)
Method for error with invalid pointer.
Definition schema.h:2467
JSON Schema Validator.
Definition schema.h:3173
virtual void DestroryHasher(void *hasher)
Definition schema.h:3768
void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)
Definition schema.h:3361
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition schema.h:3190
ValueType & GetError()
End of Implementation of ISchemaValidator.
Definition schema.h:3281
void TooLong(const Ch *str, SizeType length, SizeType expected)
Definition schema.h:3383
void AddDependencySchemaError(const SValue &sourceName, ISchemaValidator *subvalidator)
Definition schema.h:3506
void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)
Definition schema.h:3458
void DisallowedItem(SizeType index)
Definition schema.h:3404
virtual unsigned GetValidateFlags() const
Definition schema.h:3268
bool String(const Ch *str, SizeType length, bool copy)
Definition schema.h:3659
~GenericSchemaValidator()
Destructor.
Definition schema.h:3242
void StartMissingProperties()
Definition schema.h:3443
void NotAllOf(ISchemaValidator **subvalidators, SizeType count)
Definition schema.h:3544
GenericValue< EncodingType, CrtAllocator > ValueType
Definition schema.h:3181
void DisallowedProperty(const Ch *name, SizeType length)
Definition schema.h:3463
virtual void * CreateHasher()
Definition schema.h:3758
void Reset()
Reset the internal states.
Definition schema.h:3249
void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)
Definition schema.h:3340
virtual void FreeState(void *p)
Definition schema.h:3777
void MultipleOneOf(SizeType index1, SizeType index2)
Definition schema.h:3561
bool EndMissingProperties()
Definition schema.h:3448
bool StartObject()
Definition schema.h:3665
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition schema.h:3286
void NotMultipleOf(uint64_t actual, const SValue &expected)
Definition schema.h:3332
bool EndArray(SizeType elementCount)
Definition schema.h:3713
void AddExpectedType(const typename SchemaType::ValueType &expectedType)
Definition schema.h:3529
bool Key(const Ch *str, SizeType len, bool copy)
Definition schema.h:3674
bool Null()
Definition schema.h:3647
void StartDependencyErrors()
Definition schema.h:3472
void TooShort(const Ch *str, SizeType length, SizeType expected)
Definition schema.h:3389
void TooManyItems(SizeType actualCount, SizeType expectedCount)
Definition schema.h:3416
void DuplicateItems(SizeType index1, SizeType index2)
Definition schema.h:3421
void ResetError()
Reset the error state.
Definition schema.h:3258
void AddMissingDependentProperty(const SValue &targetName)
Definition schema.h:3474
void AddMissingProperty(const SValue &name)
Definition schema.h:3444
virtual bool IsValid() const
Definition schema.h:3270
void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)
Definition schema.h:3347
void StartDisallowedType()
Definition schema.h:3528
virtual void * MallocState(size_t size)
Definition schema.h:3775
bool Bool(bool b)
Definition schema.h:3648
void DisallowedWhenWriting()
Definition schema.h:3575
bool Uint(unsigned u)
Definition schema.h:3650
bool EndObject(SizeType memberCount)
Definition schema.h:3690
void DisallowedWhenReading()
Definition schema.h:3580
void NoneOf(ISchemaValidator **subvalidators, SizeType count)
Definition schema.h:3553
void TooFewProperties(SizeType actualCount, SizeType expectedCount)
Definition schema.h:3437
void NotMultipleOf(int64_t actual, const SValue &expected)
Definition schema.h:3328
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition schema.h:3293
bool EndDependencyErrors()
Definition schema.h:3512
bool StartArray()
Definition schema.h:3704
void AboveMaximum(double actual, const SValue &expected, bool exclusive)
Definition schema.h:3354
bool Uint64(uint64_t u)
Definition schema.h:3652
virtual uint64_t GetHashCode(void *hasher)
Definition schema.h:3763
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition schema.h:3315
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition schema.h:3218
void StartMissingDependentProperties()
Definition schema.h:3473
bool Int64(int64_t i)
Definition schema.h:3651
void Disallowed()
Definition schema.h:3570
void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)
Definition schema.h:3368
void NotOneOf(ISchemaValidator **subvalidators, SizeType count)
Definition schema.h:3557
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &root, const bool inheritContinueOnErrors)
Definition schema.h:3732
const ValueType & GetError() const
Definition schema.h:3282
void TooManyProperties(SizeType actualCount, SizeType expectedCount)
Definition schema.h:3431
bool Int(int i)
Definition schema.h:3649
void EndDisallowedType(const typename SchemaType::ValueType &actualType)
Definition schema.h:3534
virtual void DestroySchemaValidator(ISchemaValidator *validator)
Definition schema.h:3751
bool RawNumber(const Ch *str, SizeType length, bool copy)
Definition schema.h:3654
void NotMultipleOf(double actual, const SValue &expected)
Definition schema.h:3336
ValidateErrorCode GetInvalidSchemaCode() const
Gets the error code of invalid schema.
Definition schema.h:3304
bool Double(double d)
Definition schema.h:3653
void DoesNotMatch(const Ch *str, SizeType length)
Definition schema.h:3395
void TooFewItems(SizeType actualCount, SizeType expectedCount)
Definition schema.h:3411
void SetValidateFlags(unsigned flags)
Implementation of ISchemaValidator.
Definition schema.h:3267
void DisallowedValue(const ValidateErrorCode code=kValidateErrorEnum)
Definition schema.h:3523
void EndMissingDependentProperties(const SValue &sourceName)
Definition schema.h:3479
void BelowMinimum(double actual, const SValue &expected, bool exclusive)
Definition schema.h:3375
Represents an in-memory output stream.
Definition stringbuffer.h:42
const Ch * GetString() const
Definition stringbuffer.h:79
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition stringbuffer.h:89
Ch * Push(size_t count)
Definition stringbuffer.h:75
Definition uri.h:34
GenericUri Resolve(const GenericUri &baseuri, Allocator *allocator=0)
Resolve this URI against another (base) URI in accordance with URI resolution rules.
Definition uri.h:259
SizeType GetBaseStringLength() const
Definition uri.h:183
const Ch * GetBaseString() const
Definition uri.h:182
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition document.h:822
UTF8<> EncodingType
Definition document.h:826
GenericMemberIterator< false, EncodingType, AllocatorType >::Iterator MemberIterator
Definition document.h:831
const GenericValue * ConstValueIterator
Definition document.h:836
Definition schema.h:2227
SchemaDocument::AllocatorType AllocatorType
Definition schema.h:2231
virtual ~IGenericRemoteSchemaDocumentProvider()
Definition schema.h:2233
SchemaDocument::Ch Ch
Definition schema.h:2229
SchemaDocument::ValueType ValueType
Definition schema.h:2230
virtual const SchemaDocumentType * GetRemoteDocument(const Ch *uri, SizeType length)=0
virtual const SchemaDocumentType * GetRemoteDocument(const GenericUri< ValueType, AllocatorType > uri, Specification &spec)
Definition schema.h:2236
Default memory allocator used by the parser and DOM.
Definition allocators.h:130
const PointerType & GetInvalidDocumentPointer() const
Definition schema.h:4155
SchemaDocumentType::PointerType PointerType
Definition schema.h:4104
bool IsValid() const
Definition schema.h:4152
const PointerType & GetInvalidSchemaPointer() const
Definition schema.h:4153
ValidateErrorCode GetInvalidSchemaCode() const
Definition schema.h:4157
InputStream::Ch Ch
Definition schema.h:4105
bool operator()(Handler &handler)
Definition schema.h:4124
const Ch * GetInvalidSchemaKeyword() const
Definition schema.h:4154
const ParseResult & GetParseResult() const
Definition schema.h:4151
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition schema.h:4113
const ValueType & GetError() const
Definition schema.h:4156
GenericValue< SourceEncoding, StackAllocator > ValueType
Definition schema.h:4106
Regular expression engine with subset of ECMAscript grammar.
Definition regex.h:115
Definition schema.h:364
bool Bool(bool b)
Definition schema.h:374
bool Uint64(uint64_t u)
Definition schema.h:396
bool StartObject()
Definition schema.h:426
bool Key(const Ch *str, SizeType len, bool copy)
Definition schema.h:427
bool StartArray()
Definition schema.h:441
Encoding::Ch Ch
Definition schema.h:366
bool Uint(unsigned u)
Definition schema.h:382
bool Null()
Definition schema.h:373
bool EndObject(SizeType memberCount)
Definition schema.h:428
Hasher(Allocator *allocator=0, size_t stackCapacity=kDefaultSize)
Definition schema.h:368
bool Double(double d)
Definition schema.h:403
bool String(const Ch *str, SizeType len, bool)
Definition schema.h:420
bool Int(int i)
Definition schema.h:375
uint64_t GetHashCode() const
Definition schema.h:454
bool EndArray(SizeType elementCount)
Definition schema.h:442
bool Int64(int64_t i)
Definition schema.h:389
bool IsValid() const
Definition schema.h:452
bool RawNumber(const Ch *str, SizeType len, bool)
Definition schema.h:414
Definition schema.h:285
virtual void DestroySchemaValidator(ISchemaValidator *validator)=0
virtual void FreeState(void *p)=0
virtual void DestroryHasher(void *hasher)=0
virtual void * CreateHasher()=0
virtual void * MallocState(size_t size)=0
virtual ISchemaValidator * CreateSchemaValidator(const SchemaType &, const bool inheritContinueOnErrors)=0
virtual uint64_t GetHashCode(void *hasher)=0
virtual ~ISchemaStateFactory()
Definition schema.h:287
Definition schema.h:272
virtual void SetValidateFlags(unsigned flags)=0
virtual bool IsValid() const =0
virtual unsigned GetValidateFlags() const =0
virtual ~ISchemaValidator()
Definition schema.h:274
Definition schema.h:303
virtual void EndMissingDependentProperties(const SValue &sourceName)=0
virtual void DisallowedItem(SizeType index)=0
virtual void NotMultipleOf(int64_t actual, const SValue &expected)=0
virtual void DisallowedWhenWriting()=0
SchemaType::Ch Ch
Definition schema.h:305
SchemaType::SValue SValue
Definition schema.h:306
virtual void AddMissingDependentProperty(const SValue &targetName)=0
virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount)=0
virtual bool EndMissingProperties()=0
virtual void DuplicateItems(SizeType index1, SizeType index2)=0
virtual void AddMissingProperty(const SValue &name)=0
virtual void NotAllOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AddDependencySchemaError(const SValue &souceName, ISchemaValidator *subvalidator)=0
virtual void TooShort(const Ch *str, SizeType length, SizeType expected)=0
virtual void BelowMinimum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual void AboveMaximum(double actual, const SValue &expected, bool exclusive)=0
virtual void AddExpectedType(const typename SchemaType::ValueType &expectedType)=0
virtual void DisallowedValue(const ValidateErrorCode code)=0
virtual void DisallowedProperty(const Ch *name, SizeType length)=0
virtual void NoneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void NotOneOf(ISchemaValidator **subvalidators, SizeType count)=0
virtual void AboveMaximum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual ~IValidationErrorHandler()
Definition schema.h:308
virtual void AboveMaximum(int64_t actual, const SValue &expected, bool exclusive)=0
virtual bool EndDependencyErrors()=0
virtual void BelowMinimum(double actual, const SValue &expected, bool exclusive)=0
virtual void TooManyItems(SizeType actualCount, SizeType expectedCount)=0
virtual void DoesNotMatch(const Ch *str, SizeType length)=0
virtual void StartDisallowedType()=0
virtual void BelowMinimum(uint64_t actual, const SValue &expected, bool exclusive)=0
virtual void StartDependencyErrors()=0
virtual void PropertyViolations(ISchemaValidator **subvalidators, SizeType count)=0
virtual void StartMissingProperties()=0
virtual void DisallowedWhenReading()=0
virtual void EndDisallowedType(const typename SchemaType::ValueType &actualType)=0
virtual void NotMultipleOf(uint64_t actual, const SValue &expected)=0
virtual void NotMultipleOf(double actual, const SValue &expected)=0
virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount)=0
virtual void TooLong(const Ch *str, SizeType length, SizeType expected)=0
virtual void StartMissingDependentProperties()=0
virtual void MultipleOneOf(SizeType index1, SizeType index2)=0
virtual void TooFewItems(SizeType actualCount, SizeType expectedCount)=0
Definition schema.h:605
bool Int64(Context &context, int64_t i) const
Definition schema.h:1214
bool exclusiveMaximum_
Definition schema.h:2174
SizeType notValidatorIndex_
Definition schema.h:2143
bool StartArray(Context &context) const
Definition schema.h:1444
bool CheckUint(Context &context, uint64_t i) const
Definition schema.h:1968
RegexType * CreatePattern(const ValueType &)
Definition schema.h:1788
bool nullable_
Definition schema.h:2180
bool StartObject(Context &context) const
Definition schema.h:1287
SchemaDocumentType::PointerType PointerType
Definition schema.h:609
bool additionalProperties_
Definition schema.h:2152
bool exclusiveMinimum_
Definition schema.h:2173
bool Int(Context &context, int i) const
Definition schema.h:1198
bool Uint64(Context &context, uint64_t u) const
Definition schema.h:1222
bool uniqueItems_
Definition schema.h:2164
SizeType maxLength_
Definition schema.h:2168
bool FindPropertyIndex(const ValueType &name, SizeType *outIndex) const
Definition schema.h:1879
AllocatorType * allocator_
Definition schema.h:2129
static void AssignIfExist(SizeType &out, const ValueType &value, const ValueType &name)
Definition schema.h:1700
IValidationErrorHandler< Schema > ErrorHandler
Definition schema.h:615
RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(AdditionalProperties
SizeType validatorCount_
Definition schema.h:2142
bool readOnly_
Definition schema.h:2178
SValue maximum_
Definition schema.h:2171
bool CheckDoubleMultipleOf(Context &context, double d) const
Definition schema.h:2054
SchemaArray oneOf_
Definition schema.h:2139
GenericUri< ValueType, AllocatorType > UriType
Definition schema.h:616
SizeType minItems_
Definition schema.h:2161
~Schema()
Definition schema.h:995
static void AssignIfExist(bool &out, const ValueType &value, const ValueType &name)
Definition schema.h:1693
void AddType(const ValueType &type)
Definition schema.h:1796
bool additionalItems_
Definition schema.h:2163
bool CheckDoubleMinimum(Context &context, double d) const
Definition schema.h:2032
bool EndObject(Context &context, SizeType memberCount) const
Definition schema.h:1383
const UriType & GetId() const
Definition schema.h:1022
Specification spec_
Definition schema.h:2132
SizeType maxProperties_
Definition schema.h:2151
Property * properties_
Definition schema.h:2145
void DisallowedType(Context &context, const ValueType &actualType) const
Definition schema.h:2071
bool CheckInt(Context &context, int64_t i) const
Definition schema.h:1903
bool CheckBool(Context &context, bool) const
Definition schema.h:1893
Schema(SchemaDocumentType *schemaDocument, const PointerType &p, const ValueType &value, const ValueType &document, AllocatorType *allocator, const UriType &id=UriType())
Definition schema.h:619
const SchemaType * typeless_
Definition schema.h:2134
SchemaDocumentType::AllocatorType AllocatorType
Definition schema.h:608
bool EndArray(Context &context, SizeType elementCount) const
Definition schema.h:1459
const SchemaType * additionalPropertiesSchema_
Definition schema.h:2146
SizeType defaultValueLength_
Definition schema.h:2176
bool Double(Context &context, double d) const
Definition schema.h:1230
bool CreateParallelValidator(Context &context) const
Definition schema.h:1817
SchemaDocumentType::ValueType ValueType
Definition schema.h:607
const SchemaType * additionalItemsSchema_
Definition schema.h:2157
e
Definition schema.h:1579
unsigned type_
Definition schema.h:2141
const PointerType & GetPointer() const
Definition schema.h:1026
bool String(Context &context, const Ch *str, SizeType length, bool) const
Definition schema.h:1251
static bool IsPatternMatch(const RegexType *, const Ch *, SizeType)
Definition schema.h:1793
bool CheckDoubleMaximum(Context &context, double d) const
Definition schema.h:2043
void AddUniqueElement(V1 &a, const V2 &v)
Definition schema.h:1678
SizeType enumCount_
Definition schema.h:2136
EncodingType::Ch Ch
Definition schema.h:611
SValue minimum_
Definition schema.h:2170
PatternProperty * patternProperties_
Definition schema.h:2147
ValueType::EncodingType EncodingType
Definition schema.h:610
static const ValueType * GetMember(const ValueType &value, const ValueType &name)
Definition schema.h:1687
SchemaArray allOf_
Definition schema.h:2137
UriType id_
Definition schema.h:2131
SizeType minProperties_
Definition schema.h:2150
bool hasSchemaDependencies_
Definition schema.h:2155
GenericValue< EncodingType, AllocatorType > SValue
Definition schema.h:614
const SchemaType ** itemsTuple_
Definition schema.h:2159
const SchemaType * not_
Definition schema.h:2140
void CreateSchemaValidators(Context &context, const SchemaArray &schemas, const bool inheritContinueOnErrors) const
Definition schema.h:1869
SizeType minLength_
Definition schema.h:2167
bool Uint(Context &context, unsigned u) const
Definition schema.h:1206
bool Key(Context &context, const Ch *str, SizeType len, bool) const
Definition schema.h:1315
static const ValueType & GetValidateErrorKeyword(ValidateErrorCode validateErrorCode)
Definition schema.h:1479
PointerType pointer_
Definition schema.h:2133
SizeType maxItems_
Definition schema.h:2162
Schema< SchemaDocumentType > SchemaType
Definition schema.h:613
SchemaValidationContext< SchemaDocumentType > Context
Definition schema.h:612
s s c
Definition schema.h:1603
SValue uri_
Definition schema.h:2130
bool Null(Context &context) const
Definition schema.h:1179
const SValue & GetURI() const
Definition schema.h:1020
SizeType itemsTupleCount_
Definition schema.h:2160
SizeType patternPropertyCount_
Definition schema.h:2148
bool hasRequired_
Definition schema.h:2154
SizeType propertyCount_
Definition schema.h:2149
const Specification & GetSpecification() const
Definition schema.h:1024
RegexType * pattern_
Definition schema.h:2166
bool Bool(Context &context, bool b) const
Definition schema.h:1190
bool hasDependencies_
Definition schema.h:2153
bool BeginValue(Context &context) const
Definition schema.h:1028
uint64_t * enum_
Definition schema.h:2135
void AssignIfExist(SchemaArray &out, SchemaDocumentType &schemaDocument, const PointerType &p, const ValueType &value, const ValueType &name, const ValueType &document)
Definition schema.h:1707
s s m RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') private typedef char RegexType
Definition schema.h:1617
SValue multipleOf_
Definition schema.h:2172
const SchemaType * itemsList_
Definition schema.h:2158
RAPIDJSON_FORCEINLINE bool EndValue(Context &context) const
Definition schema.h:1065
bool writeOnly_
Definition schema.h:2179
SchemaArray anyOf_
Definition schema.h:2138
A type-unsafe stack for storing different types of data.
Definition stack.h:38
Concept for allocating, resizing and freeing memory block.
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
__device__ void copy(const SrcTensorType &src_tensor, DstTensorType &dst_tensor)
Perform optimized copy between two tensors partitions (threadwise copy). Tensors must have the same s...
Definition copy.hpp:36
GenericValue< UTF8<> > Value
GenericValue with UTF8 encoding.
Definition document.h:3124
GenericSchemaDocument< Value, CrtAllocator > SchemaDocument
Definition fwd.h:155
GenericSchemaValidator< SchemaDocument, BaseReaderHandler< UTF8< char >, void >, CrtAllocator > SchemaValidator
Definition fwd.h:162
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
Definition fwd.h:156
#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS
User-defined kValidateDefaultFlags definition.
Definition schema.h:190
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:451
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition rapidjson.h:121
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition rapidjson.h:124
ValidateErrorCode
Error codes when validating.
Definition error.h:173
SchemaErrorCode
Error codes when validating.
Definition error.h:237
@ kValidateErrorMinProperties
Object has less members than 'minProperties' value.
Definition error.h:194
@ kValidateErrorExclusiveMinimum
Number is less than or equal to the 'minimum' value.
Definition error.h:181
@ kValidateErrorAdditionalItems
Definition error.h:190
@ kValidateErrorMaxProperties
Object has more members than 'maxProperties' value.
Definition error.h:193
@ kValidateErrorOneOfMatch
Definition error.h:205
@ kValidateErrorRequired
Object is missing one or more members required by the schema.
Definition error.h:195
@ kValidateErrorDependencies
Object has missing property or schema dependencies.
Definition error.h:199
@ kValidateErrorUniqueItems
Array has duplicate items but 'uniqueItems' is true.
Definition error.h:189
@ kValidateErrorReadOnly
Definition error.h:211
@ kValidateErrorEnum
Property has a value that is not one of its allowed enumerated values.
Definition error.h:201
@ kValidateErrorExclusiveMaximum
Number is greater than or equal to the 'maximum' value.
Definition error.h:179
@ kValidateErrorType
Property has a type that is not allowed by the schema.
Definition error.h:202
@ kValidateErrorOneOf
Property did not match any of the sub-schemas specified by 'oneOf'.
Definition error.h:204
@ kValidateErrorMinLength
String is longer than the 'maxLength' value.
Definition error.h:184
@ kValidateErrors
Top level error code when kValidateContinueOnErrorsFlag set.
Definition error.h:174
@ kValidateErrorMaxLength
String is longer than the 'maxLength' value.
Definition error.h:183
@ kValidateErrorWriteOnly
Definition error.h:213
@ kValidateErrorAnyOf
Property did not match any of the sub-schemas specified by 'anyOf'.
Definition error.h:208
@ kValidateErrorPattern
String does not match the 'pattern' regular expression.
Definition error.h:185
@ kValidateErrorMaximum
Number is greater than the 'maximum' value.
Definition error.h:178
@ kValidateErrorMaxItems
Array is longer than the 'maxItems' value.
Definition error.h:187
@ kValidateErrorMinimum
Number is less than the 'minimum' value.
Definition error.h:180
@ kValidateErrorMultipleOf
Number is not a multiple of the 'multipleOf' value.
Definition error.h:177
@ kValidateErrorNone
No error.
Definition error.h:175
@ kValidateErrorMinItems
Array is shorter than the 'minItems' value.
Definition error.h:188
@ kValidateErrorNot
Property matched the sub-schema specified by 'not'.
Definition error.h:209
@ kValidateErrorAdditionalProperties
Definition error.h:196
@ kValidateErrorPatternProperties
See other errors.
Definition error.h:198
@ kValidateErrorAllOf
Property did not match all of the sub-schemas specified by 'allOf'.
Definition error.h:207
@ kSchemaErrorStartUnknown
Definition error.h:240
@ kSchemaErrorSpecIllegal
Both JSON schema draft and OpenAPI version found in document.
Definition error.h:253
@ kSchemaErrorSpecUnsupported
JSON schema draft or OpenAPI version is not supported.
Definition error.h:252
@ kSchemaErrorRefPlainName
$ref fragment must be a JSON pointer
Definition error.h:242
@ kSchemaErrorRefNoRemoteProvider
$ref is remote but there is no remote provider
Definition error.h:247
@ kSchemaErrorSpecUnknown
JSON schema draft or OpenAPI version is not recognized.
Definition error.h:251
@ kSchemaErrorRefUnknown
$ref does not resolve to a location in the target document
Definition error.h:245
@ kSchemaErrorRefPointerInvalid
$ref fragment is not a valid JSON pointer at offset
Definition error.h:244
@ kSchemaErrorRefNoRemoteSchema
Definition error.h:248
@ kSchemaErrorRefCyclical
$ref is cyclical
Definition error.h:246
@ kSchemaErrorRefInvalid
$ref must not be an empty string
Definition error.h:243
@ kSchemaErrorRegexInvalid
Invalid regular expression in 'pattern' or 'patternProperties'.
Definition error.h:250
@ kSchemaErrorReadOnlyAndWriteOnly
Property must not be both 'readOnly' and 'writeOnly'.
Definition error.h:254
#define PRIu64
Definition inttypes.h:143
#define PRId64
Definition inttypes.h:89
__host__ __device__ constexpr auto depth(const Layout< Shape, UnrolledDescriptorType > &layout)
Get depth of the layout shape (return 0 if scalar).
Definition layout_utils.hpp:371
Definition allocators.h:459
char * u64toa(uint64_t value, char *buffer)
Definition itoa.h:135
SizeType StrLen(const Ch *s)
Custom strlen() which works on different character types.
Definition strfunc.h:32
bool CountStringCodePoint(const typename Encoding::Ch *s, SizeType length, SizeType *outCount)
Returns number of code points in a encoded string.
Definition strfunc.h:76
char * u32toa(uint32_t value, char *buffer)
Definition itoa.h:41
const GenericPointer< typename T::ValueType > T2 value
Definition pointer.h:1697
#define RAPIDJSON_IF_CONSTEXPR
Definition pointer.h:34
const GenericPointer< typename T::ValueType > & pointer
Definition pointer.h:1514
const CharType(& source)[N]
Definition pointer.h:1559
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1517
Type
Type of JSON value.
Definition rapidjson.h:760
@ kFalseType
false
Definition rapidjson.h:762
@ kObjectType
object
Definition rapidjson.h:764
@ kTrueType
true
Definition rapidjson.h:763
@ kStringType
string
Definition rapidjson.h:766
@ kNullType
null
Definition rapidjson.h:761
@ kArrayType
array
Definition rapidjson.h:765
@ kNumberType
number
Definition rapidjson.h:767
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:746
RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.).
Definition rapidjson.h:429
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition rapidjson.h:326
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:742
#define RAPIDJSON_SCHEMA_PRINT(name,...)
Definition schema.h:165
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)
Definition schema.h:3608
ValidateFlag
Combination of validate flags.
Definition schema.h:195
@ kValidateNoFlags
No flags are set.
Definition schema.h:196
@ kValidateWriteFlag
Validation is for a write semantic.
Definition schema.h:199
@ kValidateDefaultFlags
Definition schema.h:200
@ kValidateReadFlag
Validation is for a read semantic.
Definition schema.h:198
@ kValidateContinueOnErrorFlag
Don't stop after first validation error.
Definition schema.h:197
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2)
Definition schema.h:3642
SchemaDraft
Definition schema.h:208
@ kDraftUnknown
Definition schema.h:209
@ kDraft03
Definition schema.h:211
@ kDraftNone
Definition schema.h:210
@ kDraft2020_12
Definition schema.h:219
@ kDraft07
Definition schema.h:217
@ kDraft06
Definition schema.h:216
@ kDraft2019_09
Definition schema.h:218
@ kDraft04
Definition schema.h:213
@ kDraftMin
Current minimum supported draft.
Definition schema.h:212
@ kDraft05
Definition schema.h:214
@ kDraftMax
Current maximum supported draft.
Definition schema.h:215
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
Definition schema.h:3637
#define RAPIDJSON_STRING_(name,...)
Definition schema.h:1522
#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)
Definition schema.h:172
OpenApiVersion
Definition schema.h:223
@ kVersionMax
Current maximum supported version.
Definition schema.h:229
@ kVersion20
Definition schema.h:227
@ kVersionMin
Current minimum supported version.
Definition schema.h:226
@ kVersionUnknown
Definition schema.h:224
@ kVersion30
Definition schema.h:228
@ kVersion31
Definition schema.h:230
@ kVersionNone
Definition schema.h:225
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)
Definition schema.h:3621
signed __int64 int64_t
Definition stdint.h:135
unsigned __int64 uint64_t
Definition stdint.h:136
Default implementation of Handler.
Definition reader.h:208
Reference to a constant string (not taking a copy).
Definition document.h:417
Result of parsing (wraps ParseErrorCode).
Definition error.h:108
Definition schema.h:234
Specification(OpenApiVersion o)
Definition schema.h:236
SchemaDraft draft
Definition schema.h:253
bool IsSupported() const
Definition schema.h:248
OpenApiVersion oapi
Definition schema.h:254
~Specification()
Definition schema.h:247
Specification(SchemaDraft d)
Definition schema.h:235
CharType Ch
Definition encodings.h:99
~PatternProperty()
Definition schema.h:2117
RegexType * pattern
Definition schema.h:2126
const SchemaType * schema
Definition schema.h:2125
PatternProperty()
Definition schema.h:2116
const SchemaType * dependenciesSchema
Definition schema.h:2108
bool required
Definition schema.h:2111
~Property()
Definition schema.h:2105
const SchemaType * schema
Definition schema.h:2107
SizeType dependenciesValidatorIndex
Definition schema.h:2109
bool * dependencies
Definition schema.h:2110
SValue name
Definition schema.h:2106
Property()
Definition schema.h:2097
SchemaArray()
Definition schema.h:1670
const SchemaType ** schemas
Definition schema.h:1672
~SchemaArray()
Definition schema.h:1671
SizeType count
Definition schema.h:1674
SizeType begin
Definition schema.h:1673
Definition schema.h:503
bool arrayUniqueness
Definition schema.h:597
SizeType validatorCount
Definition schema.h:586
const SchemaType ** patternPropertiesSchemas
Definition schema.h:589
ISchemaValidator ** validators
Definition schema.h:585
SizeType arrayElementIndex
Definition schema.h:593
bool valueUniqueness
Definition schema.h:596
SizeType patternPropertiesValidatorCount
Definition schema.h:588
ISchemaStateFactory< SchemaType > SchemaValidatorFactoryType
Definition schema.h:505
const SchemaType * valueSchema
Definition schema.h:580
bool * propertyExist
Definition schema.h:594
void * hasher
Definition schema.h:583
IValidationErrorHandler< SchemaType > ErrorHandlerType
Definition schema.h:506
PatternValidatorType
Definition schema.h:511
@ kPatternValidatorWithProperty
Definition schema.h:513
@ kPatternValidatorWithAdditionalProperty
Definition schema.h:514
@ kPatternValidatorOnly
Definition schema.h:512
ValidateErrorCode invalidCode
Definition schema.h:582
void * arrayElementHashCodes
Definition schema.h:584
ISchemaValidator ** patternPropertiesValidators
Definition schema.h:587
SizeType patternPropertiesSchemaCount
Definition schema.h:590
Schema< SchemaDocumentType > SchemaType
Definition schema.h:504
SchemaValidationContext(SchemaValidatorFactoryType &f, ErrorHandlerType &eh, const SchemaType *s, unsigned fl=0)
Definition schema.h:517
const Ch * invalidKeyword
Definition schema.h:581
~SchemaValidationContext()
Definition schema.h:544
unsigned flags
Definition schema.h:579
ValueType::Ch Ch
Definition schema.h:508
SchemaType::ValueType ValueType
Definition schema.h:507
PatternValidatorType valuePatternValidatorType
Definition schema.h:591
ErrorHandlerType & error_handler
Definition schema.h:577
PatternValidatorType objectPatternValidatorType
Definition schema.h:592
SchemaValidatorFactoryType & factory
Definition schema.h:576
bool inArray
Definition schema.h:595
const SchemaType * schema
Definition schema.h:578
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition schema.h:2201
Definition schema.h:2185
static RAPIDJSON_FORCEINLINE void AppendIndexToken(Stack &documentStack, SizeType index)
Definition schema.h:2186
Definition schema.h:465
int64_t i
Definition schema.h:467
uint64_t u
Definition schema.h:466