15#ifndef RAPIDJSON_SCHEMA_H_
16#define RAPIDJSON_SCHEMA_H_
20#include "stringbuffer.h"
25#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
26#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
29#if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) || !(__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
30#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
33#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
34#include "internal/regex.h"
35#elif RAPIDJSON_SCHEMA_USE_STDREGEX
39#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
40#define RAPIDJSON_SCHEMA_HAS_REGEX 1
42#define RAPIDJSON_SCHEMA_HAS_REGEX 0
45#ifndef RAPIDJSON_SCHEMA_VERBOSE
46#define RAPIDJSON_SCHEMA_VERBOSE 0
52RAPIDJSON_DIAG_OFF(effc++)
56RAPIDJSON_DIAG_OFF(weak-vtables)
57RAPIDJSON_DIAG_OFF(exit-time-destructors)
58RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
59RAPIDJSON_DIAG_OFF(variadic-macros)
60#elif defined(_MSC_VER)
61RAPIDJSON_DIAG_OFF(4512)
64RAPIDJSON_NAMESPACE_BEGIN
69#if RAPIDJSON_SCHEMA_VERBOSE
73inline void PrintInvalidKeywordData(
const char* keyword) {
74 printf(
" Fail keyword: '%s'\n", keyword);
77inline void PrintInvalidKeywordData(
const wchar_t* keyword) {
78 wprintf(L
" Fail keyword: '%ls'\n", keyword);
81inline void PrintInvalidDocumentData(
const char* document) {
82 printf(
" Fail document: '%s'\n", document);
85inline void PrintInvalidDocumentData(
const wchar_t* document) {
86 wprintf(L
" Fail document: '%ls'\n", document);
89inline void PrintValidatorPointersData(
const char* s,
const char* d,
unsigned depth) {
90 printf(
" Sch: %*s'%s'\n Doc: %*s'%s'\n", depth * 4,
" ", s, depth * 4,
" ", d);
93inline void PrintValidatorPointersData(
const wchar_t* s,
const wchar_t* d,
unsigned depth) {
94 wprintf(L
" Sch: %*ls'%ls'\n Doc: %*ls'%ls'\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
97inline void PrintSchemaIdsData(
const char* base,
const char* local,
const char* resolved) {
98 printf(
" Resolving id: Base: '%s', Local: '%s', Resolved: '%s'\n", base, local, resolved);
101inline void PrintSchemaIdsData(
const wchar_t* base,
const wchar_t* local,
const wchar_t* resolved) {
102 wprintf(L
" Resolving id: Base: '%ls', Local: '%ls', Resolved: '%ls'\n", base, local, resolved);
105inline void PrintMethodData(
const char* method) {
106 printf(
"%s\n", method);
109inline void PrintMethodData(
const char* method,
bool b) {
110 printf(
"%s, Data: '%s'\n", method, b ?
"true" :
"false");
113inline void PrintMethodData(
const char* method, int64_t i) {
114 printf(
"%s, Data: '%" PRId64
"'\n", method, i);
117inline void PrintMethodData(
const char* method, uint64_t u) {
118 printf(
"%s, Data: '%" PRIu64
"'\n", method, u);
121inline void PrintMethodData(
const char* method,
double d) {
122 printf(
"%s, Data: '%lf'\n", method, d);
125inline void PrintMethodData(
const char* method,
const char* s) {
126 printf(
"%s, Data: '%s'\n", method, s);
129inline void PrintMethodData(
const char* method,
const wchar_t* s) {
130 wprintf(L
"%hs, Data: '%ls'\n", method, s);
133inline void PrintMethodData(
const char* method,
const char* s1,
const char* s2) {
134 printf(
"%s, Data: '%s', '%s'\n", method, s1, s2);
137inline void PrintMethodData(
const char* method,
const wchar_t* s1,
const wchar_t* s2) {
138 wprintf(L
"%hs, Data: '%ls', '%ls'\n", method, s1, s2);
145#ifndef RAPIDJSON_SCHEMA_PRINT
146#if RAPIDJSON_SCHEMA_VERBOSE
147#define RAPIDJSON_SCHEMA_PRINT(name, ...) internal::Print##name##Data(__VA_ARGS__)
149#define RAPIDJSON_SCHEMA_PRINT(name, ...)
156#define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
157RAPIDJSON_MULTILINEMACRO_BEGIN\
158 context.invalidCode = code;\
159 context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
160 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, context.invalidKeyword);\
162RAPIDJSON_MULTILINEMACRO_END
173#ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
174#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
203 kVersionUnknown = -1,
215 if (oapi == kVersion20) draft = kDraft04;
216 else if (oapi == kVersion30) draft = kDraft05;
217 else if (oapi == kVersion31) draft = kDraft2020_12;
218 else draft = kDraft04;
221 bool IsSupported()
const {
231template <
typename ValueType,
typename Allocator>
236template <
typename SchemaDocumentType>
242class ISchemaValidator {
244 virtual ~ISchemaValidator() {}
245 virtual bool IsValid()
const = 0;
246 virtual void SetValidateFlags(
unsigned flags) = 0;
247 virtual unsigned GetValidateFlags()
const = 0;
253template <
typename SchemaType>
254class ISchemaStateFactory {
256 virtual ~ISchemaStateFactory() {}
257 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType&,
const bool inheritContinueOnErrors) = 0;
258 virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
259 virtual void* CreateHasher() = 0;
260 virtual uint64_t GetHashCode(
void* hasher) = 0;
261 virtual void DestroryHasher(
void* hasher) = 0;
262 virtual void* MallocState(
size_t size) = 0;
263 virtual void FreeState(
void* p) = 0;
269template <
typename SchemaType>
270class IValidationErrorHandler {
272 typedef typename SchemaType::Ch Ch;
273 typedef typename SchemaType::SValue SValue;
275 virtual ~IValidationErrorHandler() {}
277 virtual void NotMultipleOf(int64_t actual,
const SValue& expected) = 0;
278 virtual void NotMultipleOf(uint64_t actual,
const SValue& expected) = 0;
279 virtual void NotMultipleOf(
double actual,
const SValue& expected) = 0;
280 virtual void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
281 virtual void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
282 virtual void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) = 0;
283 virtual void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) = 0;
284 virtual void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) = 0;
285 virtual void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) = 0;
287 virtual void TooLong(
const Ch* str, SizeType length, SizeType expected) = 0;
288 virtual void TooShort(
const Ch* str, SizeType length, SizeType expected) = 0;
289 virtual void DoesNotMatch(
const Ch* str, SizeType length) = 0;
291 virtual void DisallowedItem(SizeType index) = 0;
292 virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
293 virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
294 virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
296 virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
297 virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
298 virtual void StartMissingProperties() = 0;
299 virtual void AddMissingProperty(
const SValue& name) = 0;
300 virtual bool EndMissingProperties() = 0;
301 virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
302 virtual void DisallowedProperty(
const Ch* name, SizeType length) = 0;
304 virtual void StartDependencyErrors() = 0;
305 virtual void StartMissingDependentProperties() = 0;
306 virtual void AddMissingDependentProperty(
const SValue& targetName) = 0;
307 virtual void EndMissingDependentProperties(
const SValue& sourceName) = 0;
308 virtual void AddDependencySchemaError(
const SValue& souceName, ISchemaValidator* subvalidator) = 0;
309 virtual bool EndDependencyErrors() = 0;
311 virtual void DisallowedValue(
const ValidateErrorCode code) = 0;
312 virtual void StartDisallowedType() = 0;
313 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
314 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
315 virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
316 virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
317 virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
318 virtual void MultipleOneOf(SizeType index1, SizeType index2) = 0;
319 virtual void Disallowed() = 0;
320 virtual void DisallowedWhenWriting() = 0;
321 virtual void DisallowedWhenReading() = 0;
329template<
typename Encoding,
typename Allocator>
332 typedef typename Encoding::Ch Ch;
334 Hasher(
Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
336 bool Null() {
return WriteType(kNullType); }
337 bool Bool(
bool b) {
return WriteType(b ? kTrueType :
kFalseType); }
338 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
339 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
340 bool Int64(int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
341 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
342 bool Double(
double d) {
344 if (d < 0) n.u.i =
static_cast<int64_t
>(d);
345 else n.u.u =
static_cast<uint64_t
>(d);
347 return WriteNumber(n);
350 bool RawNumber(
const Ch* str, SizeType len,
bool) {
351 WriteBuffer(kNumberType, str, len *
sizeof(Ch));
355 bool String(
const Ch* str, SizeType len,
bool) {
356 WriteBuffer(kStringType, str, len *
sizeof(Ch));
360 bool StartObject() {
return true; }
361 bool Key(
const Ch* str, SizeType len,
bool copy) {
return String(str, len, copy); }
362 bool EndObject(SizeType memberCount) {
363 uint64_t h = Hash(0, kObjectType);
364 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
365 for (SizeType i = 0; i < memberCount; i++)
368 h ^= Hash(Hash(0, kv[i * 2]), kv[i * 2 + 1]);
369 *stack_.template Push<uint64_t>() = h;
373 bool StartArray() {
return true; }
374 bool EndArray(SizeType elementCount) {
375 uint64_t h = Hash(0, kArrayType);
376 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
377 for (SizeType i = 0; i < elementCount; i++)
379 *stack_.template Push<uint64_t>() = h;
383 bool IsValid()
const {
return stack_.GetSize() ==
sizeof(uint64_t); }
385 uint64_t GetHashCode()
const {
387 return *stack_.template Top<uint64_t>();
391 static const size_t kDefaultSize = 256;
400 bool WriteType(Type type) {
return WriteBuffer(type, 0, 0); }
402 bool WriteNumber(
const Number& n) {
return WriteBuffer(kNumberType, &n,
sizeof(n)); }
404 bool WriteBuffer(Type type,
const void* data,
size_t len) {
407 const unsigned char* d =
static_cast<const unsigned char*
>(data);
408 for (
size_t i = 0; i < len; i++)
410 *stack_.template Push<uint64_t>() = h;
414 static uint64_t Hash(uint64_t h, uint64_t d) {
421 Stack<Allocator> stack_;
427template <
typename SchemaDocumentType>
428struct SchemaValidationContext {
429 typedef Schema<SchemaDocumentType> SchemaType;
430 typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
431 typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
432 typedef typename SchemaType::ValueType ValueType;
433 typedef typename ValueType::Ch Ch;
435 enum PatternValidatorType {
436 kPatternValidatorOnly,
437 kPatternValidatorWithProperty,
438 kPatternValidatorWithAdditionalProperty
441 SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh,
const SchemaType* s,
unsigned fl = 0) :
450 arrayElementHashCodes(),
453 patternPropertiesValidators(),
454 patternPropertiesValidatorCount(),
455 patternPropertiesSchemas(),
456 patternPropertiesSchemaCount(),
457 valuePatternValidatorType(kPatternValidatorOnly),
460 valueUniqueness(false),
461 arrayUniqueness(false)
465 ~SchemaValidationContext() {
467 factory.DestroryHasher(hasher);
469 for (SizeType i = 0; i < validatorCount; i++) {
471 factory.DestroySchemaValidator(validators[i]);
474 factory.FreeState(validators);
476 if (patternPropertiesValidators) {
477 for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) {
478 if (patternPropertiesValidators[i]) {
479 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
482 factory.FreeState(patternPropertiesValidators);
484 if (patternPropertiesSchemas)
485 factory.FreeState(patternPropertiesSchemas);
487 factory.FreeState(propertyExist);
490 SchemaValidatorFactoryType& factory;
491 ErrorHandlerType& error_handler;
492 const SchemaType* schema;
494 const SchemaType* valueSchema;
495 const Ch* invalidKeyword;
498 void* arrayElementHashCodes;
499 ISchemaValidator** validators;
501 ISchemaValidator** patternPropertiesValidators;
502 SizeType patternPropertiesValidatorCount;
503 const SchemaType** patternPropertiesSchemas;
504 SizeType patternPropertiesSchemaCount;
505 PatternValidatorType valuePatternValidatorType;
506 PatternValidatorType objectPatternValidatorType;
510 bool valueUniqueness;
511 bool arrayUniqueness;
517template <
typename SchemaDocumentType>
520 typedef typename SchemaDocumentType::ValueType ValueType;
521 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
522 typedef typename SchemaDocumentType::PointerType PointerType;
523 typedef typename ValueType::EncodingType EncodingType;
524 typedef typename EncodingType::Ch Ch;
525 typedef SchemaValidationContext<SchemaDocumentType> Context;
526 typedef Schema<SchemaDocumentType> SchemaType;
527 typedef GenericValue<EncodingType, AllocatorType> SValue;
528 typedef IValidationErrorHandler<Schema> ErrorHandler;
529 typedef GenericUri<ValueType, AllocatorType> UriType;
530 friend class GenericSchemaDocument<ValueType, AllocatorType>;
532 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator,
const UriType&
id = UriType()) :
533 allocator_(allocator),
534 uri_(schemaDocument->GetURI(), *allocator),
536 spec_(schemaDocument->GetSpecification()),
537 pointer_(p, allocator),
538 typeless_(schemaDocument->GetTypeless()),
542 type_((1 << kTotalSchemaType) - 1),
544 notValidatorIndex_(),
546 additionalPropertiesSchema_(),
547 patternProperties_(),
548 patternPropertyCount_(),
552 additionalProperties_(true),
555 hasSchemaDependencies_(),
556 additionalItemsSchema_(),
562 additionalItems_(true),
567 exclusiveMinimum_(false),
568 exclusiveMaximum_(false),
569 defaultValueLength_(0),
574 GenericStringBuffer<EncodingType> sb;
575 p.StringifyUriFragment(sb);
576 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Schema", sb.GetString(),
id.GetString());
578 typedef typename ValueType::ConstValueIterator ConstValueIterator;
579 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
585 if (
this != typeless_) {
586 typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
587 SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
588 new (entry) SchemaEntry(pointer_,
this,
true, allocator_);
589 schemaDocument->AddSchemaRefs(
this);
592 if (!value.IsObject())
597 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
598 if (
const ValueType* v = GetMember(value, GetIdString())) {
600 UriType local(*v, allocator);
601 id_ = local.Resolve(id_, allocator);
602 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), v->GetString(), id_.GetString());
606 if (
const ValueType* v = GetMember(value, GetTypeString())) {
610 else if (v->IsArray())
611 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
615 if (
const ValueType* v = GetMember(value, GetEnumString())) {
616 if (v->IsArray() && v->Size() > 0) {
617 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
618 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
619 typedef Hasher<EncodingType, MemoryPoolAllocator<AllocatorType> > EnumHasherType;
620 char buffer[256u + 24];
621 MemoryPoolAllocator<AllocatorType> hasherAllocator(buffer,
sizeof(buffer));
622 EnumHasherType h(&hasherAllocator, 256);
624 enum_[enumCount_++] = h.GetHashCode();
630 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
633 if (schemaDocument && spec_.oapi != kVersion20) {
634 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
635 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
637 if (
const ValueType* v = GetMember(value, GetNotString())) {
638 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
639 notValidatorIndex_ = validatorCount_;
646 const ValueType* properties = GetMember(value, GetPropertiesString());
647 const ValueType* required = GetMember(value, GetRequiredString());
648 const ValueType* dependencies = GetMember(value, GetDependenciesString());
651 SValue allProperties(kArrayType);
653 if (properties && properties->IsObject())
654 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
655 AddUniqueElement(allProperties, itr->name);
657 if (required && required->IsArray())
658 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
660 AddUniqueElement(allProperties, *itr);
663 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
664 if (dependencies && dependencies->IsObject())
665 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
666 AddUniqueElement(allProperties, itr->name);
667 if (itr->value.IsArray())
668 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
670 AddUniqueElement(allProperties, *i);
673 if (allProperties.Size() > 0) {
674 propertyCount_ = allProperties.Size();
675 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
676 for (SizeType i = 0; i < propertyCount_; i++) {
677 new (&properties_[i]) Property();
678 properties_[i].name = allProperties[i];
679 properties_[i].schema = typeless_;
684 if (properties && properties->IsObject()) {
685 PointerType q = p.Append(GetPropertiesString(), allocator_);
686 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
688 if (FindPropertyIndex(itr->name, &index))
689 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
694 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
695 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
696 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
697 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
698 patternPropertyCount_ = 0;
700 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
701 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
702 PointerType r = q.Append(itr->name, allocator_);
703 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
704 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
705 patternPropertyCount_++;
709 if (required && required->IsArray())
710 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
711 if (itr->IsString()) {
713 if (FindPropertyIndex(*itr, &index)) {
714 properties_[index].required =
true;
720 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
721 if (dependencies && dependencies->IsObject()) {
722 PointerType q = p.Append(GetDependenciesString(), allocator_);
723 hasDependencies_ =
true;
724 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
726 if (FindPropertyIndex(itr->name, &sourceIndex)) {
727 if (itr->value.IsArray()) {
728 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
729 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
730 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
732 if (FindPropertyIndex(*targetItr, &targetIndex))
733 properties_[sourceIndex].dependencies[targetIndex] =
true;
736 else if (itr->value.IsObject()) {
737 hasSchemaDependencies_ =
true;
738 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
739 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
746 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
748 additionalProperties_ = v->GetBool();
749 else if (v->IsObject())
750 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
753 AssignIfExist(minProperties_, value, GetMinPropertiesString());
754 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
757 if (
const ValueType* v = GetMember(value, GetItemsString())) {
758 PointerType q = p.Append(GetItemsString(), allocator_);
760 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
761 else if (v->IsArray()) {
762 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
764 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
765 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
769 AssignIfExist(minItems_, value, GetMinItemsString());
770 AssignIfExist(maxItems_, value, GetMaxItemsString());
773 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
774 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
776 additionalItems_ = v->GetBool();
777 else if (v->IsObject())
778 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
781 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
784 AssignIfExist(minLength_, value, GetMinLengthString());
785 AssignIfExist(maxLength_, value, GetMaxLengthString());
787 if (
const ValueType* v = GetMember(value, GetPatternString()))
788 pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
791 if (
const ValueType* v = GetMember(value, GetMinimumString()))
793 minimum_.CopyFrom(*v, *allocator_);
795 if (
const ValueType* v = GetMember(value, GetMaximumString()))
797 maximum_.CopyFrom(*v, *allocator_);
799 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
800 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
802 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
803 if (v->IsNumber() && v->GetDouble() > 0.0)
804 multipleOf_.CopyFrom(*v, *allocator_);
807 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
809 defaultValueLength_ = v->GetStringLength();
814 if (spec_.oapi != kVersionNone)
815 AssignIfExist(readOnly_, value, GetReadOnlyString());
816 if (spec_.oapi >= kVersion30)
817 AssignIfExist(writeOnly_, value, GetWriteOnlyString());
818 if (readOnly_ && writeOnly_)
819 schemaDocument->SchemaError(kSchemaErrorReadOnlyAndWriteOnly, p);
823 if (spec_.oapi >= kVersion30) {
824 AssignIfExist(nullable_, value, GetNullableString());
826 AddType(GetNullString());
831 AllocatorType::Free(enum_);
833 for (SizeType i = 0; i < propertyCount_; i++)
834 properties_[i].~Property();
835 AllocatorType::Free(properties_);
837 if (patternProperties_) {
838 for (SizeType i = 0; i < patternPropertyCount_; i++)
839 patternProperties_[i].~PatternProperty();
840 AllocatorType::Free(patternProperties_);
842 AllocatorType::Free(itemsTuple_);
843#if RAPIDJSON_SCHEMA_HAS_REGEX
845 pattern_->~RegexType();
846 AllocatorType::Free(pattern_);
851 const SValue& GetURI()
const {
855 const UriType& GetId()
const {
859 const Specification& GetSpecification()
const {
863 const PointerType& GetPointer()
const {
867 bool BeginValue(Context& context)
const {
868 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::BeginValue");
869 if (context.inArray) {
871 context.valueUniqueness =
true;
874 context.valueSchema = itemsList_;
875 else if (itemsTuple_) {
876 if (context.arrayElementIndex < itemsTupleCount_)
877 context.valueSchema = itemsTuple_[context.arrayElementIndex];
878 else if (additionalItemsSchema_)
879 context.valueSchema = additionalItemsSchema_;
880 else if (additionalItems_)
881 context.valueSchema = typeless_;
883 context.error_handler.DisallowedItem(context.arrayElementIndex);
885 context.valueSchema = typeless_;
887 context.arrayElementIndex++;
888 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalItems);
892 context.valueSchema = typeless_;
894 context.arrayElementIndex++;
899 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
900 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndValue");
902 if (context.patternPropertiesValidatorCount > 0) {
903 bool otherValid =
false;
904 SizeType count = context.patternPropertiesValidatorCount;
905 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
906 otherValid = context.patternPropertiesValidators[--count]->IsValid();
908 bool patternValid =
true;
909 for (SizeType i = 0; i < count; i++)
910 if (!context.patternPropertiesValidators[i]->IsValid()) {
911 patternValid =
false;
915 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
917 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
918 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
921 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
922 if (!patternValid || !otherValid) {
923 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
924 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
927 else if (!patternValid && !otherValid) {
928 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
929 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPatternProperties);
934 if (enum_ && context.hasher) {
935 const uint64_t h = context.factory.GetHashCode(context.hasher);
936 for (SizeType i = 0; i < enumCount_; i++)
939 context.error_handler.DisallowedValue(kValidateErrorEnum);
940 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorEnum);
945 if (context.validatorCount > 0) {
947 for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
948 if (!context.validators[i]->IsValid()) {
949 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
950 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAllOf);
953 if (anyOf_.schemas) {
954 for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
955 if (context.validators[i]->IsValid())
957 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
958 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAnyOf);
962 if (oneOf_.schemas) {
963 bool oneValid =
false;
965 for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
966 if (context.validators[i]->IsValid()) {
968 context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
969 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOfMatch);
972 firstMatch = i - oneOf_.begin;
976 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
977 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorOneOf);
981 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
982 context.error_handler.Disallowed();
983 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorNot);
990 bool Null(Context& context)
const {
991 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Null");
992 if (!(type_ & (1 << kNullSchemaType))) {
993 DisallowedType(context, GetNullString());
994 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
996 return CreateParallelValidator(context);
999 bool Bool(Context& context,
bool b)
const {
1000 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Bool", b);
1001 if (!CheckBool(context, b))
1003 return CreateParallelValidator(context);
1006 bool Int(Context& context,
int i)
const {
1007 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int", (int64_t)i);
1008 if (!CheckInt(context, i))
1010 return CreateParallelValidator(context);
1013 bool Uint(Context& context,
unsigned u)
const {
1014 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint", (uint64_t)u);
1015 if (!CheckUint(context, u))
1017 return CreateParallelValidator(context);
1020 bool Int64(Context& context, int64_t i)
const {
1021 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int64", i);
1022 if (!CheckInt(context, i))
1024 return CreateParallelValidator(context);
1027 bool Uint64(Context& context, uint64_t u)
const {
1028 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint64", u);
1029 if (!CheckUint(context, u))
1031 return CreateParallelValidator(context);
1034 bool Double(Context& context,
double d)
const {
1035 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Double", d);
1036 if (!(type_ & (1 << kNumberSchemaType))) {
1037 DisallowedType(context, GetNumberString());
1038 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1041 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1044 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1047 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1050 return CreateParallelValidator(context);
1053 bool String(Context& context,
const Ch* str, SizeType length,
bool)
const {
1054 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::String", str);
1055 if (!(type_ & (1 << kStringSchemaType))) {
1056 DisallowedType(context, GetStringString());
1057 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1060 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
1062 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
1063 if (count < minLength_) {
1064 context.error_handler.TooShort(str, length, minLength_);
1065 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinLength);
1067 if (count > maxLength_) {
1068 context.error_handler.TooLong(str, length, maxLength_);
1069 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxLength);
1074 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
1075 context.error_handler.DoesNotMatch(str, length);
1076 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorPattern);
1079 return CreateParallelValidator(context);
1082 bool StartObject(Context& context)
const {
1083 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartObject");
1084 if (!(type_ & (1 << kObjectSchemaType))) {
1085 DisallowedType(context, GetObjectString());
1086 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1089 if (hasDependencies_ || hasRequired_) {
1090 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
1091 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
1094 if (patternProperties_) {
1095 SizeType count = patternPropertyCount_ + 1;
1096 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
1097 context.patternPropertiesSchemaCount = 0;
1098 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
1101 return CreateParallelValidator(context);
1104 bool Key(Context& context,
const Ch* str, SizeType len,
bool)
const {
1105 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Key", str);
1107 if (patternProperties_) {
1108 context.patternPropertiesSchemaCount = 0;
1109 for (SizeType i = 0; i < patternPropertyCount_; i++)
1110 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
1111 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
1112 context.valueSchema = typeless_;
1117 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
1118 if (context.patternPropertiesSchemaCount > 0) {
1119 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
1120 context.valueSchema = typeless_;
1121 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
1124 context.valueSchema = properties_[index].schema;
1126 if (context.propertyExist)
1127 context.propertyExist[index] =
true;
1132 if (additionalPropertiesSchema_) {
1133 if (context.patternPropertiesSchemaCount > 0) {
1134 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
1135 context.valueSchema = typeless_;
1136 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
1139 context.valueSchema = additionalPropertiesSchema_;
1142 else if (additionalProperties_) {
1143 context.valueSchema = typeless_;
1147 if (context.patternPropertiesSchemaCount == 0) {
1149 context.valueSchema = typeless_;
1150 context.error_handler.DisallowedProperty(str, len);
1151 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorAdditionalProperties);
1157 bool EndObject(Context& context, SizeType memberCount)
const {
1158 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndObject");
1160 context.error_handler.StartMissingProperties();
1161 for (SizeType index = 0; index < propertyCount_; index++)
1162 if (properties_[index].required && !context.propertyExist[index])
1163 if (properties_[index].schema->defaultValueLength_ == 0 )
1164 context.error_handler.AddMissingProperty(properties_[index].name);
1165 if (context.error_handler.EndMissingProperties())
1166 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorRequired);
1169 if (memberCount < minProperties_) {
1170 context.error_handler.TooFewProperties(memberCount, minProperties_);
1171 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinProperties);
1174 if (memberCount > maxProperties_) {
1175 context.error_handler.TooManyProperties(memberCount, maxProperties_);
1176 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxProperties);
1179 if (hasDependencies_) {
1180 context.error_handler.StartDependencyErrors();
1181 for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1182 const Property& source = properties_[sourceIndex];
1183 if (context.propertyExist[sourceIndex]) {
1184 if (source.dependencies) {
1185 context.error_handler.StartMissingDependentProperties();
1186 for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1187 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1188 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1189 context.error_handler.EndMissingDependentProperties(source.name);
1191 else if (source.dependenciesSchema) {
1192 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1193 if (!dependenciesValidator->IsValid())
1194 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1198 if (context.error_handler.EndDependencyErrors())
1199 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorDependencies);
1205 bool StartArray(Context& context)
const {
1206 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartArray");
1207 context.arrayElementIndex = 0;
1208 context.inArray =
true;
1210 if (!(type_ & (1 << kArraySchemaType))) {
1211 DisallowedType(context, GetArrayString());
1212 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1215 return CreateParallelValidator(context);
1218 bool EndArray(Context& context, SizeType elementCount)
const {
1219 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndArray");
1220 context.inArray =
false;
1222 if (elementCount < minItems_) {
1223 context.error_handler.TooFewItems(elementCount, minItems_);
1224 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMinItems);
1227 if (elementCount > maxItems_) {
1228 context.error_handler.TooManyItems(elementCount, maxItems_);
1229 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMaxItems);
1235 static const ValueType& GetValidateErrorKeyword(ValidateErrorCode validateErrorCode) {
1236 switch (validateErrorCode) {
1271 default:
return GetNullString();
1277#define RAPIDJSON_STRING_(name, ...) \
1278 static const ValueType& Get##name##String() {\
1279 static const Ch s[] = { __VA_ARGS__, '\0' };\
1280 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1284 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1285 RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
1286 RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
1287 RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
1288 RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
1289 RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
1290 RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
1291 RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
1292 RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
1293 RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
1294 RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
1295 RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
1296 RAPIDJSON_STRING_(Not, 'n', 'o', 't')
1297 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1298 RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
1299 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1300 RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1301 RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1302 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1303 RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1304 RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
1305 RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
1306 RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
1307 RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
1308 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1309 RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
1310 RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
1311 RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
1312 RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
1313 RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
1314 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1315 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
1316 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1317 RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
1318 RAPIDJSON_STRING_(Schema, '$', 's', 'c', 'h', 'e', 'm', 'a')
1319 RAPIDJSON_STRING_(Ref, '$', 'r', 'e', 'f')
1320 RAPIDJSON_STRING_(Id, 'i', 'd')
1321 RAPIDJSON_STRING_(Swagger, 's', 'w', 'a', 'g', 'g', 'e', 'r')
1322 RAPIDJSON_STRING_(OpenApi, 'o', 'p', 'e', 'n', 'a', 'p', 'i')
1323 RAPIDJSON_STRING_(ReadOnly, 'r', 'e', 'a', 'd', 'O', 'n', 'l', 'y')
1324 RAPIDJSON_STRING_(WriteOnly, 'w', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
1325 RAPIDJSON_STRING_(Nullable, 'n', 'u', 'l', 'l', 'a', 'b', 'l', 'e')
1327#undef RAPIDJSON_STRING_
1330 enum SchemaValueType {
1341#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1342 typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
1343#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1344 typedef std::basic_regex<Ch> RegexType;
1346 typedef char RegexType;
1349 struct SchemaArray {
1350 SchemaArray() : schemas(), count() {}
1351 ~SchemaArray() { AllocatorType::Free(schemas); }
1352 const SchemaType** schemas;
1357 template <
typename V1,
typename V2>
1358 void AddUniqueElement(V1& a,
const V2& v) {
1359 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1362 V1 c(v, *allocator_);
1363 a.PushBack(c, *allocator_);
1366 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1367 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1368 return itr != value.MemberEnd() ? &(itr->value) : 0;
1371 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1372 if (
const ValueType* v = GetMember(value, name))
1377 static void AssignIfExist(SizeType& out,
const ValueType& value,
const ValueType& name) {
1378 if (
const ValueType* v = GetMember(value, name))
1379 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1380 out =
static_cast<SizeType>(v->GetUint64());
1383 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1384 if (
const ValueType* v = GetMember(value, name)) {
1385 if (v->IsArray() && v->Size() > 0) {
1386 PointerType q = p.Append(name, allocator_);
1387 out.count = v->Size();
1388 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1389 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
1390 for (SizeType i = 0; i < out.count; i++)
1391 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1392 out.begin = validatorCount_;
1393 validatorCount_ += out.count;
1398#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1399 template <
typename ValueType>
1400 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1401 if (value.IsString()) {
1402 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1403 if (!r->IsValid()) {
1404 sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1406 AllocatorType::Free(r);
1414 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str, SizeType) {
1415 GenericRegexSearch<RegexType> rs(*pattern);
1416 return rs.Search(str);
1418#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1419 template <
typename ValueType>
1420 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1421 if (value.IsString()) {
1422 RegexType *r =
static_cast<RegexType*
>(allocator_->Malloc(
sizeof(RegexType)));
1424 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1426 catch (
const std::regex_error& e) {
1427 sd->SchemaErrorValue(kSchemaErrorRegexInvalid, p, value.GetString(), value.GetStringLength());
1428 AllocatorType::Free(r);
1434 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str, SizeType length) {
1435 std::match_results<const Ch*> r;
1436 return std::regex_search(str, str + length, r, *pattern);
1439 template <
typename ValueType>
1440 RegexType* CreatePattern(
const ValueType&) {
1444 static bool IsPatternMatch(
const RegexType*,
const Ch *, SizeType) {
return true; }
1447 void AddType(
const ValueType& type) {
1448 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1449 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1450 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1451 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1452 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1453 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1454 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1460 bool CreateParallelValidator(Context& context)
const {
1461 if (enum_ || context.arrayUniqueness)
1462 context.hasher = context.factory.CreateHasher();
1464 if (validatorCount_) {
1466 context.validators =
static_cast<ISchemaValidator**
>(context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1467 std::memset(context.validators, 0,
sizeof(ISchemaValidator*) * validatorCount_);
1468 context.validatorCount = validatorCount_;
1472 CreateSchemaValidators(context, allOf_,
false);
1475 CreateSchemaValidators(context, anyOf_,
false);
1478 CreateSchemaValidators(context, oneOf_,
false);
1481 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_,
false);
1483 if (hasSchemaDependencies_) {
1484 for (SizeType i = 0; i < propertyCount_; i++)
1485 if (properties_[i].dependenciesSchema)
1486 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema,
false);
1491 if (readOnly_ && (context.flags & kValidateWriteFlag)) {
1492 context.error_handler.DisallowedWhenWriting();
1493 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorReadOnly);
1495 if (writeOnly_ && (context.flags & kValidateReadFlag)) {
1496 context.error_handler.DisallowedWhenReading();
1497 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorWriteOnly);
1503 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas,
const bool inheritContinueOnErrors)
const {
1504 for (SizeType i = 0; i < schemas.count; i++)
1505 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1509 bool FindPropertyIndex(
const ValueType& name, SizeType* outIndex)
const {
1510 SizeType len = name.GetStringLength();
1511 const Ch* str = name.GetString();
1512 for (SizeType index = 0; index < propertyCount_; index++)
1513 if (properties_[index].name.GetStringLength() == len &&
1514 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1522 bool CheckBool(Context& context,
bool)
const {
1523 if (!(type_ & (1 << kBooleanSchemaType))) {
1524 DisallowedType(context, GetBooleanString());
1525 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1530 bool CheckInt(Context& context, int64_t i)
const {
1531 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1532 DisallowedType(context, GetIntegerString());
1533 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1536 if (!minimum_.IsNull()) {
1537 if (minimum_.IsInt64()) {
1538 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1539 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1540 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum);
1543 else if (minimum_.IsUint64()) {
1544 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1545 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum);
1547 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1551 if (!maximum_.IsNull()) {
1552 if (maximum_.IsInt64()) {
1553 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1554 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1555 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum);
1558 else if (maximum_.IsUint64()) { }
1560 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1564 if (!multipleOf_.IsNull()) {
1565 if (multipleOf_.IsUint64()) {
1566 if (
static_cast<uint64_t
>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1567 context.error_handler.NotMultipleOf(i, multipleOf_);
1568 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1571 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1578 bool CheckUint(Context& context, uint64_t i)
const {
1579 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1580 DisallowedType(context, GetIntegerString());
1581 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorType);
1584 if (!minimum_.IsNull()) {
1585 if (minimum_.IsUint64()) {
1586 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1587 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1588 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum);
1591 else if (minimum_.IsInt64())
1593 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1597 if (!maximum_.IsNull()) {
1598 if (maximum_.IsUint64()) {
1599 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1600 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1601 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum);
1604 else if (maximum_.IsInt64()) {
1605 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1606 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum);
1608 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1612 if (!multipleOf_.IsNull()) {
1613 if (multipleOf_.IsUint64()) {
1614 if (i % multipleOf_.GetUint64() != 0) {
1615 context.error_handler.NotMultipleOf(i, multipleOf_);
1616 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1619 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1626 bool CheckDoubleMinimum(Context& context,
double d)
const {
1627 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1628 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1629 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMinimum_ ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum);
1634 bool CheckDoubleMaximum(Context& context,
double d)
const {
1635 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1636 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1637 RAPIDJSON_INVALID_KEYWORD_RETURN(exclusiveMaximum_ ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum);
1642 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1643 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1645 double qRounded = std::floor(q + 0.5);
1646 double scaledEpsilon = (q + qRounded) * std::numeric_limits<double>::epsilon();
1647 double difference = std::abs(qRounded - q);
1648 bool isMultiple = difference <= scaledEpsilon || difference < (std::numeric_limits<double>::min)();
1650 context.error_handler.NotMultipleOf(d, multipleOf_);
1651 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorMultipleOf);
1656 void DisallowedType(Context& context,
const ValueType& actualType)
const {
1657 ErrorHandler& eh = context.error_handler;
1658 eh.StartDisallowedType();
1660 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1661 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1662 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1663 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1664 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1666 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1667 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1669 eh.EndDisallowedType(actualType);
1673 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1674 ~Property() { AllocatorType::Free(dependencies); }
1676 const SchemaType* schema;
1677 const SchemaType* dependenciesSchema;
1678 SizeType dependenciesValidatorIndex;
1683 struct PatternProperty {
1684 PatternProperty() : schema(), pattern() {}
1685 ~PatternProperty() {
1687 pattern->~RegexType();
1688 AllocatorType::Free(pattern);
1691 const SchemaType* schema;
1695 AllocatorType* allocator_;
1698 Specification spec_;
1699 PointerType pointer_;
1700 const SchemaType* typeless_;
1706 const SchemaType* not_;
1711 Property* properties_;
1712 const SchemaType* additionalPropertiesSchema_;
1713 PatternProperty* patternProperties_;
1718 bool additionalProperties_;
1719 bool hasDependencies_;
1721 bool hasSchemaDependencies_;
1723 const SchemaType* additionalItemsSchema_;
1724 const SchemaType* itemsList_;
1725 const SchemaType** itemsTuple_;
1729 bool additionalItems_;
1732 RegexType* pattern_;
1739 bool exclusiveMinimum_;
1740 bool exclusiveMaximum_;
1749template<
typename Stack,
typename Ch>
1751 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(Stack& documentStack, SizeType index) {
1752 *documentStack.template Push<Ch>() =
'/';
1754 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1755 for (
size_t i = 0; i < length; i++)
1756 *documentStack.template Push<Ch>() =
static_cast<Ch
>(buffer[i]);
1761template <
typename Stack>
1762struct TokenHelper<Stack, char> {
1763 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(Stack& documentStack, SizeType index) {
1764 RAPIDJSON_IF_CONSTEXPR (
sizeof(SizeType) == 4) {
1765 char *buffer = documentStack.template Push<char>(1 + 10);
1767 const char* end = internal::u32toa(index, buffer);
1768 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1771 char *buffer = documentStack.template Push<char>(1 + 20);
1773 const char* end = internal::u64toa(index, buffer);
1774 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1784template <
typename SchemaDocumentType>
1787 typedef typename SchemaDocumentType::Ch Ch;
1788 typedef typename SchemaDocumentType::ValueType ValueType;
1789 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
1792 virtual const SchemaDocumentType* GetRemoteDocument(
const Ch* uri,
SizeType length) = 0;
1798 return GetRemoteDocument(uri.GetBaseString(), uri.GetBaseStringLength());
1814template <
typename ValueT,
typename Allocator = CrtAllocator>
1817 typedef ValueT ValueType;
1820 typedef typename ValueType::EncodingType EncodingType;
1821 typedef typename EncodingType::Ch Ch;
1822 typedef internal::Schema<GenericSchemaDocument> SchemaType;
1828 template <
typename,
typename,
typename>
1847 remoteProvider_(remoteProvider),
1848 allocator_(allocator),
1852 schemaMap_(allocator, kInitialSchemaMapSize),
1853 schemaRef_(allocator, kInitialSchemaRefSize),
1858 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::GenericSchemaDocument");
1863 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1864 docId_ =
UriType(uri_, allocator_);
1866 typeless_ =
static_cast<SchemaType*
>(allocator_->Malloc(
sizeof(SchemaType)));
1871 SetSchemaSpecification(document);
1877 if (pointer.GetTokenCount() == 0) {
1878 CreateSchemaRecursive(&root_, pointer, document, document, docId_);
1880 else if (
const ValueType* v = pointer.Get(document)) {
1881 CreateSchema(&root_, pointer, *v, document, docId_);
1885 pointer.StringifyUriFragment(sb);
1891 schemaRef_.ShrinkToFit();
1894#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1897 remoteProvider_(rhs.remoteProvider_),
1898 allocator_(rhs.allocator_),
1899 ownAllocator_(rhs.ownAllocator_),
1901 typeless_(rhs.typeless_),
1902 schemaMap_(std::move(rhs.schemaMap_)),
1903 schemaRef_(std::move(rhs.schemaRef_)),
1904 uri_(std::move(rhs.uri_)),
1905 docId_(std::move(rhs.docId_)),
1907 error_(std::move(rhs.error_)),
1908 currentError_(std::move(rhs.currentError_))
1910 rhs.remoteProvider_ = 0;
1912 rhs.ownAllocator_ = 0;
1919 while (!schemaMap_.Empty())
1920 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1923 typeless_->~SchemaType();
1924 Allocator::Free(typeless_);
1930 currentError_.SetNull();
1935 const GValue& GetURI()
const {
return uri_; }
1937 const Specification& GetSpecification()
const {
return spec_; }
1938 bool IsSupportedSpecification()
const {
return spec_.IsSupported(); }
1944 if (draft != kDraftNone)
1948 if (oapi != kVersionNone)
1955 const SchemaType&
GetRoot()
const {
return *root_; }
1959 const GValue& GetError()
const {
return error_; }
1961 static const StringRefType& GetSchemaErrorKeyword(SchemaErrorCode schemaErrorCode) {
1962 switch (schemaErrorCode) {
1963 case kSchemaErrorStartUnknown:
return GetStartUnknownString();
1964 case kSchemaErrorRefPlainName:
return GetRefPlainNameString();
1965 case kSchemaErrorRefInvalid:
return GetRefInvalidString();
1966 case kSchemaErrorRefPointerInvalid:
return GetRefPointerInvalidString();
1967 case kSchemaErrorRefUnknown:
return GetRefUnknownString();
1968 case kSchemaErrorRefCyclical:
return GetRefCyclicalString();
1969 case kSchemaErrorRefNoRemoteProvider:
return GetRefNoRemoteProviderString();
1970 case kSchemaErrorRefNoRemoteSchema:
return GetRefNoRemoteSchemaString();
1971 case kSchemaErrorRegexInvalid:
return GetRegexInvalidString();
1972 case kSchemaErrorSpecUnknown:
return GetSpecUnknownString();
1973 case kSchemaErrorSpecUnsupported:
return GetSpecUnsupportedString();
1974 case kSchemaErrorSpecIllegal:
return GetSpecIllegalString();
1975 case kSchemaErrorReadOnlyAndWriteOnly:
return GetReadOnlyAndWriteOnlyString();
1976 default:
return GetNullString();
1983 AddCurrentError(code, location);
1989 currentError_.AddMember(GetValueString(),
GValue(value, length, *allocator_).Move(), *allocator_);
1990 AddCurrentError(code, location);
1996 currentError_.AddMember(GetValueString(),
GValue(value, length, *allocator_).Move(), *allocator_);
1998 AddCurrentError(code, location);
2007 typedef const PointerType* SchemaRefPtr;
2009 struct SchemaEntry {
2010 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o,
Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
2013 schema->~SchemaType();
2014 Allocator::Free(schema);
2017 PointerType pointer;
2022 void AddErrorInstanceLocation(GValue& result,
const PointerType& location) {
2023 GenericStringBuffer<EncodingType> sb;
2024 location.StringifyUriFragment(sb);
2025 GValue instanceRef(sb.GetString(),
static_cast<SizeType>(sb.GetSize() /
sizeof(Ch)), *allocator_);
2026 result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2029 void AddError(GValue& keyword, GValue& error) {
2030 typename GValue::MemberIterator member = error_.FindMember(keyword);
2031 if (member == error_.MemberEnd())
2032 error_.AddMember(keyword, error, *allocator_);
2034 if (member->value.IsObject()) {
2035 GValue errors(kArrayType);
2036 errors.PushBack(member->value, *allocator_);
2037 member->value = errors;
2039 member->value.PushBack(error, *allocator_);
2043 void AddCurrentError(
const SchemaErrorCode code,
const PointerType& location) {
2044 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2045 currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2046 AddErrorInstanceLocation(currentError_, location);
2047 AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2050#define RAPIDJSON_STRING_(name, ...) \
2051 static const StringRefType& Get##name##String() {\
2052 static const Ch s[] = { __VA_ARGS__, '\0' };\
2053 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2057 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2058 RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2059 RAPIDJSON_STRING_(Value, 'v', 'a', 'l', 'u', 'e')
2060 RAPIDJSON_STRING_(Offset, 'o', 'f', 'f', 's', 'e', 't')
2062 RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
2063 RAPIDJSON_STRING_(SpecUnknown, 'S', 'p', 'e', 'c', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2064 RAPIDJSON_STRING_(SpecUnsupported, 'S', 'p', 'e', 'c', 'U', 'n', 's', 'u', 'p', 'p', 'o', 'r', 't', 'e', 'd')
2065 RAPIDJSON_STRING_(SpecIllegal, 'S', 'p', 'e', 'c', 'I', 'l', 'l', 'e', 'g', 'a', 'l')
2066 RAPIDJSON_STRING_(StartUnknown, 'S', 't', 'a', 'r', 't', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2067 RAPIDJSON_STRING_(RefPlainName, 'R', 'e', 'f', 'P', 'l', 'a', 'i', 'n', 'N', 'a', 'm', 'e')
2068 RAPIDJSON_STRING_(RefInvalid, 'R', 'e', 'f', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2069 RAPIDJSON_STRING_(RefPointerInvalid, 'R', 'e', 'f', 'P', 'o', 'i', 'n', 't', 'e', 'r', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2070 RAPIDJSON_STRING_(RefUnknown, 'R', 'e', 'f', 'U', 'n', 'k', 'n', 'o', 'w', 'n')
2071 RAPIDJSON_STRING_(RefCyclical, 'R', 'e', 'f', 'C', 'y', 'c', 'l', 'i', 'c', 'a', 'l')
2072 RAPIDJSON_STRING_(RefNoRemoteProvider, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'P', 'r', 'o', 'v', 'i', 'd', 'e', 'r')
2073 RAPIDJSON_STRING_(RefNoRemoteSchema, 'R', 'e', 'f', 'N', 'o', 'R', 'e', 'm', 'o', 't', 'e', 'S', 'c', 'h', 'e', 'm', 'a')
2074 RAPIDJSON_STRING_(ReadOnlyAndWriteOnly, 'R', 'e', 'a', 'd', 'O', 'n', 'l', 'y', 'A', 'n', 'd', 'W', 'r', 'i', 't', 'e', 'O', 'n', 'l', 'y')
2075 RAPIDJSON_STRING_(RegexInvalid, 'R', 'e', 'g', 'e', 'x', 'I', 'n', 'v', 'a', 'l', 'i', 'd')
2077#undef RAPIDJSON_STRING_
2080 static SchemaDraft GetSchemaDraft(
const ValueType& document) {
2081 static const Ch kDraft03String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'3',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2082 static const Ch kDraft04String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'4',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2083 static const Ch kDraft05String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'5',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2084 static const Ch kDraft06String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'6',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2085 static const Ch kDraft07String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'7',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2086 static const Ch kDraft2019_09String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'1',
'9',
'-',
'0',
'9',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2087 static const Ch kDraft2020_12String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'2',
'0',
'-',
'1',
'2',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2089 if (!document.IsObject()) {
2094 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
2095 if (itr != document.MemberEnd()) {
2096 if (!itr->value.IsString())
return kDraftUnknown;
2097 const UriType draftUri(itr->value);
2099 if (draftUri.Match(UriType(kDraft04String),
false))
return kDraft04;
2100 if (draftUri.Match(UriType(kDraft05String),
false))
return kDraft05;
2101 if (draftUri.Match(UriType(kDraft06String),
false))
return kDraft06;
2102 if (draftUri.Match(UriType(kDraft07String),
false))
return kDraft07;
2103 if (draftUri.Match(UriType(kDraft03String),
false))
return kDraft03;
2104 if (draftUri.Match(UriType(kDraft2019_09String),
false))
return kDraft2019_09;
2105 if (draftUri.Match(UriType(kDraft2020_12String),
false))
return kDraft2020_12;
2106 return kDraftUnknown;
2114 static OpenApiVersion GetOpenApiVersion(
const ValueType& document) {
2115 static const Ch kVersion20String[] = {
'2',
'.',
'0',
'\0' };
2116 static const Ch kVersion30String[] = {
'3',
'.',
'0',
'.',
'\0' };
2117 static const Ch kVersion31String[] = {
'3',
'.',
'1',
'.',
'\0' };
2118 static SizeType len = internal::StrLen<Ch>(kVersion30String);
2120 if (!document.IsObject()) {
2121 return kVersionNone;
2125 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
2126 if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
2127 if (itr != document.MemberEnd()) {
2128 if (!itr->value.IsString())
return kVersionUnknown;
2129 const ValueType kVersion20Value(kVersion20String);
2130 if (kVersion20Value == itr->value)
return kVersion20;
2131 const ValueType kVersion30Value(kVersion30String);
2132 if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len))
return kVersion30;
2133 const ValueType kVersion31Value(kVersion31String);
2134 if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len))
return kVersion31;
2135 return kVersionUnknown;
2138 return kVersionNone;
2143 void SetSchemaSpecification(
const ValueType& document) {
2148 if (docDraft != kDraftNone && docOapi != kVersionNone)
2149 SchemaError(kSchemaErrorSpecIllegal, PointerType());
2151 if (docDraft != kDraftNone)
2152 spec_ = Specification(docDraft);
2153 else if (docOapi != kVersionNone)
2154 spec_ = Specification(docOapi);
2156 if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2157 SchemaError(kSchemaErrorSpecUnknown, PointerType());
2158 else if (!spec_.IsSupported())
2159 SchemaError(kSchemaErrorSpecUnsupported, PointerType());
2163 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2164 if (v.GetType() == kObjectType) {
2165 UriType newid = UriType(CreateSchema(schema, pointer, v, document,
id), allocator_);
2167 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
2168 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2171 for (SizeType i = 0; i < v.Size(); i++)
2172 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document, id);
2176 const UriType& CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2178 GenericStringBuffer<EncodingType> sb;
2179 pointer.StringifyUriFragment(sb);
2180 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::CreateSchema", sb.GetString(),
id.GetString());
2182 if (
const SchemaType* sc = GetSchema(pointer)) {
2185 AddSchemaRefs(
const_cast<SchemaType*
>(sc));
2187 else if (!HandleRefSchema(pointer, schema, v, document,
id)) {
2189 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_,
id);
2197 *schema = typeless_;
2198 AddSchemaRefs(typeless_);
2205 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2206 typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2207 if (itr == v.MemberEnd())
2210 GenericStringBuffer<EncodingType> sb;
2211 source.StringifyUriFragment(sb);
2212 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::HandleRefSchema", sb.GetString(),
id.GetString());
2214 new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2216 if (itr->value.IsString()) {
2217 SizeType len = itr->value.GetStringLength();
2219 SchemaError(kSchemaErrorRefInvalid, source);
2222 UriType scopeId = UriType(
id, allocator_);
2223 UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2224 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), itr->value.GetString(), ref.GetString());
2227 PointerType basePointer = PointerType();
2228 const ValueType *base = FindId(document, ref, basePointer, docId_,
false);
2231 if (!remoteProvider_)
2232 SchemaError(kSchemaErrorRefNoRemoteProvider, source);
2234 if (
const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(ref, spec_)) {
2235 const Ch* s = ref.GetFragString();
2236 len = ref.GetFragStringLength();
2237 if (len <= 1 || s[1] ==
'/') {
2239 const PointerType pointer(s, len, allocator_);
2240 if (!pointer.IsValid())
2241 SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, pointer);
2244 if (
const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
2247 AddSchemaRefs(
const_cast<SchemaType *
>(sc));
2250 SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2254 SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2256 SchemaErrorValue(kSchemaErrorRefNoRemoteSchema, source, ref.GetString(), ref.GetStringLength());
2260 const Ch* s = ref.GetFragString();
2261 len = ref.GetFragStringLength();
2262 if (len <= 1 || s[1] ==
'/') {
2264 const PointerType relPointer(s, len, allocator_);
2265 if (!relPointer.IsValid())
2266 SchemaErrorPointer(kSchemaErrorRefPointerInvalid, source, s, len, relPointer);
2269 if (
const ValueType *pv = relPointer.Get(*base)) {
2271 PointerType pointer(basePointer, allocator_);
2272 for (SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2273 pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2274 if (IsCyclicRef(pointer))
2275 SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2279 size_t unresolvedTokenIndex;
2280 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2281 CreateSchema(schema, pointer, *pv, document, scopeId);
2285 SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2290 PointerType pointer(allocator_);
2291 if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2292 SchemaErrorValue(kSchemaErrorRefPlainName, source, s, len);
2295 else if (
const ValueType *pv = FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_),
true, basePointer)) {
2296 if (IsCyclicRef(pointer))
2297 SchemaErrorValue(kSchemaErrorRefCyclical, source, ref.GetString(), ref.GetStringLength());
2301 size_t unresolvedTokenIndex;
2302 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2303 CreateSchema(schema, pointer, *pv, document, scopeId);
2307 SchemaErrorValue(kSchemaErrorRefUnknown, source, ref.GetString(), ref.GetStringLength());
2315 *schema = typeless_;
2316 AddSchemaRefs(typeless_);
2324 ValueType* FindId(
const ValueType& doc,
const UriType& finduri, PointerType& resptr,
const UriType& baseuri,
bool full,
const PointerType& here = PointerType())
const {
2326 ValueType* resval = 0;
2327 UriType tempuri = UriType(finduri, allocator_);
2328 UriType localuri = UriType(baseuri, allocator_);
2329 if (doc.GetType() == kObjectType) {
2331 typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
2332 if (m != doc.MemberEnd() && m->value.GetType() == kStringType) {
2333 localuri = UriType(m->value, allocator_).Resolve(baseuri, allocator_);
2336 if (localuri.Match(finduri, full)) {
2337 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
2338 resval =
const_cast<ValueType *
>(&doc);
2343 for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
2345 resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
2349 }
else if (doc.GetType() == kArrayType) {
2351 for (
typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
2353 resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
2363 void AddSchemaRefs(SchemaType* schema) {
2364 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::AddSchemaRefs");
2365 while (!schemaRef_.Empty()) {
2366 SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
2367 SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
2368 new (entry) SchemaEntry(**ref, schema,
false, allocator_);
2373 bool IsCyclicRef(
const PointerType& pointer)
const {
2374 for (
const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
2375 if (pointer == **ref)
2380 const SchemaType* GetSchema(
const PointerType& pointer)
const {
2381 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2382 if (pointer == target->pointer)
2383 return target->schema;
2387 PointerType GetPointer(
const SchemaType* schema)
const {
2388 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2389 if (schema == target->schema)
2390 return target->pointer;
2391 return PointerType();
2394 const SchemaType* GetTypeless()
const {
return typeless_; }
2396 static const size_t kInitialSchemaMapSize = 64;
2397 static const size_t kInitialSchemaRefSize = 64;
2399 IRemoteSchemaDocumentProviderType* remoteProvider_;
2402 const SchemaType* root_;
2403 SchemaType* typeless_;
2404 internal::Stack<Allocator> schemaMap_;
2405 internal::Stack<Allocator> schemaRef_;
2408 Specification spec_;
2410 GValue currentError_;
2434 typename SchemaDocumentType,
2435 typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
2436 typename StateAllocator = CrtAllocator>
2438 public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
2439 public internal::ISchemaValidator,
2440 public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType> {
2442 typedef typename SchemaDocumentType::SchemaType SchemaType;
2443 typedef typename SchemaDocumentType::PointerType PointerType;
2444 typedef typename SchemaType::EncodingType EncodingType;
2445 typedef typename SchemaType::SValue SValue;
2446 typedef typename EncodingType::Ch Ch;
2458 const SchemaDocumentType& schemaDocument,
2459 StateAllocator* allocator = 0,
2460 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2461 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2463 schemaDocument_(&schemaDocument),
2464 root_(schemaDocument.GetRoot()),
2465 stateAllocator_(allocator),
2466 ownStateAllocator_(0),
2467 schemaStack_(allocator, schemaStackCapacity),
2468 documentStack_(allocator, documentStackCapacity),
2472 missingDependents_(),
2477 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator");
2488 const SchemaDocumentType& schemaDocument,
2489 OutputHandler& outputHandler,
2490 StateAllocator* allocator = 0,
2491 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2492 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2494 schemaDocument_(&schemaDocument),
2495 root_(schemaDocument.GetRoot()),
2496 stateAllocator_(allocator),
2497 ownStateAllocator_(0),
2498 schemaStack_(allocator, schemaStackCapacity),
2499 documentStack_(allocator, documentStackCapacity),
2500 outputHandler_(&outputHandler),
2503 missingDependents_(),
2508 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (output handler)");
2519 while (!schemaStack_.Empty())
2521 documentStack_.Clear();
2528 currentError_.SetNull();
2529 missingDependents_.SetNull();
2537 virtual unsigned GetValidateFlags()
const {
2541 virtual bool IsValid()
const {
2542 if (!valid_)
return false;
2543 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return false;
2550 const ValueType& GetError()
const {
return error_; }
2555 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2561 if (!schemaStack_.Empty())
return CurrentContext().invalidKeyword;
2562 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return static_cast<const Ch*
>(GetErrorsString());
2569 if (!schemaStack_.Empty())
return CurrentContext().invalidCode;
2570 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return kValidateErrors;
2577 if (documentStack_.Empty()) {
2578 return PointerType();
2581 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
2585 void NotMultipleOf(int64_t actual,
const SValue& expected) {
2586 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2588 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
2589 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2591 void NotMultipleOf(
double actual,
const SValue& expected) {
2592 AddNumberError(kValidateErrorMultipleOf, ValueType(actual).Move(), expected);
2594 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
2595 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum, ValueType(actual).Move(), expected,
2596 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2598 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2599 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum, ValueType(actual).Move(), expected,
2600 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2602 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
2603 AddNumberError(exclusive ? kValidateErrorExclusiveMaximum :
kValidateErrorMaximum, ValueType(actual).Move(), expected,
2604 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2606 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
2607 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum, ValueType(actual).Move(), expected,
2608 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2610 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2611 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum, ValueType(actual).Move(), expected,
2612 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2614 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
2615 AddNumberError(exclusive ? kValidateErrorExclusiveMinimum :
kValidateErrorMinimum, ValueType(actual).Move(), expected,
2616 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2619 void TooLong(
const Ch* str, SizeType length, SizeType expected) {
2620 AddNumberError(kValidateErrorMaxLength,
2621 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2623 void TooShort(
const Ch* str, SizeType length, SizeType expected) {
2624 AddNumberError(kValidateErrorMinLength,
2625 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2627 void DoesNotMatch(
const Ch* str, SizeType length) {
2628 currentError_.SetObject();
2629 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2630 AddCurrentError(kValidateErrorPattern);
2633 void DisallowedItem(SizeType index) {
2634 currentError_.SetObject();
2635 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2636 AddCurrentError(kValidateErrorAdditionalItems,
true);
2638 void TooFewItems(SizeType actualCount, SizeType expectedCount) {
2639 AddNumberError(kValidateErrorMinItems,
2640 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2642 void TooManyItems(SizeType actualCount, SizeType expectedCount) {
2643 AddNumberError(kValidateErrorMaxItems,
2644 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2646 void DuplicateItems(SizeType index1, SizeType index2) {
2647 ValueType duplicates(kArrayType);
2648 duplicates.PushBack(index1, GetStateAllocator());
2649 duplicates.PushBack(index2, GetStateAllocator());
2650 currentError_.SetObject();
2651 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2652 AddCurrentError(kValidateErrorUniqueItems,
true);
2655 void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
2656 AddNumberError(kValidateErrorMaxProperties,
2657 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2659 void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
2660 AddNumberError(kValidateErrorMinProperties,
2661 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2663 void StartMissingProperties() {
2664 currentError_.SetArray();
2666 void AddMissingProperty(
const SValue& name) {
2667 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2669 bool EndMissingProperties() {
2670 if (currentError_.Empty())
2672 ValueType error(kObjectType);
2673 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2674 currentError_ = error;
2675 AddCurrentError(kValidateErrorRequired);
2678 void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
2679 for (SizeType i = 0; i < count; ++i)
2680 MergeError(
static_cast<GenericSchemaValidator*
>(subvalidators[i])->GetError());
2682 void DisallowedProperty(
const Ch* name, SizeType length) {
2683 currentError_.SetObject();
2684 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2685 AddCurrentError(kValidateErrorAdditionalProperties,
true);
2688 void StartDependencyErrors() {
2689 currentError_.SetObject();
2691 void StartMissingDependentProperties() {
2692 missingDependents_.SetArray();
2694 void AddMissingDependentProperty(
const SValue& targetName) {
2695 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2697 void EndMissingDependentProperties(
const SValue& sourceName) {
2698 if (!missingDependents_.Empty()) {
2700 ValueType error(kObjectType);
2702 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2703 AddErrorCode(error, code);
2704 AddErrorInstanceLocation(error,
false);
2706 PointerType schemaRef = GetInvalidSchemaPointer().Append(SchemaType::GetValidateErrorKeyword(kValidateErrorDependencies), &GetInvalidSchemaPointer().GetAllocator());
2707 AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &GetInvalidSchemaPointer().GetAllocator()));
2708 ValueType wrapper(kObjectType);
2709 wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2710 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2713 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2714 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2715 static_cast<GenericSchemaValidator*
>(subvalidator)->GetError(), GetStateAllocator());
2717 bool EndDependencyErrors() {
2718 if (currentError_.ObjectEmpty())
2720 ValueType error(kObjectType);
2721 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2722 currentError_ = error;
2723 AddCurrentError(kValidateErrorDependencies);
2727 void DisallowedValue(
const ValidateErrorCode code = kValidateErrorEnum) {
2728 currentError_.SetObject();
2729 AddCurrentError(code);
2731 void StartDisallowedType() {
2732 currentError_.SetArray();
2734 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2735 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2737 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2738 ValueType error(kObjectType);
2739 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2740 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2741 currentError_ = error;
2742 AddCurrentError(kValidateErrorType);
2744 void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2746 AddErrorArray(kValidateErrorAllOf, subvalidators, count);
2751 void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2752 AddErrorArray(kValidateErrorAnyOf, subvalidators, count);
2754 void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2755 AddErrorArray(kValidateErrorOneOf, subvalidators, count);
2757 void MultipleOneOf(SizeType index1, SizeType index2) {
2758 ValueType matches(kArrayType);
2759 matches.PushBack(index1, GetStateAllocator());
2760 matches.PushBack(index2, GetStateAllocator());
2761 currentError_.SetObject();
2762 currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
2763 AddCurrentError(kValidateErrorOneOfMatch);
2766 currentError_.SetObject();
2767 AddCurrentError(kValidateErrorNot);
2769 void DisallowedWhenWriting() {
2770 currentError_.SetObject();
2771 AddCurrentError(kValidateErrorReadOnly);
2773 void DisallowedWhenReading() {
2774 currentError_.SetObject();
2775 AddCurrentError(kValidateErrorWriteOnly);
2778#define RAPIDJSON_STRING_(name, ...) \
2779 static const StringRefType& Get##name##String() {\
2780 static const Ch s[] = { __VA_ARGS__, '\0' };\
2781 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2785 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2786 RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2787 RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2788 RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2789 RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2790 RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2791 RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2792 RAPIDJSON_STRING_(ErrorCode, 'e', 'r', 'r', 'o', 'r', 'C', 'o', 'd', 'e')
2793 RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', 'a', 'g', 'e')
2794 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2795 RAPIDJSON_STRING_(Matches, 'm', 'a', 't', 'c', 'h', 'e', 's')
2797#undef RAPIDJSON_STRING_
2799#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2800 if (!valid_) return false; \
2801 if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2802 *documentStack_.template Push<Ch>() = '\0';\
2803 documentStack_.template Pop<Ch>(1);\
2804 RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
2809#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2810 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2811 if (context->hasher)\
2812 static_cast<HasherType*>(context->hasher)->method arg2;\
2813 if (context->validators)\
2814 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2815 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2816 if (context->patternPropertiesValidators)\
2817 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2818 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2821#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2822 valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2825#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2826 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2827 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2828 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2830 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2831 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2832 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2833 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2834 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2835 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2836 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2837 bool RawNumber(
const Ch* str, SizeType length,
bool copy)
2838 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2839 bool String(
const Ch* str, SizeType length,
bool copy)
2840 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2842 bool StartObject() {
2843 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartObject");
2844 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2845 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2846 valid_ = !outputHandler_ || outputHandler_->StartObject();
2850 bool Key(
const Ch* str, SizeType len,
bool copy) {
2851 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::Key", str);
2852 if (!valid_)
return false;
2853 AppendToken(str, len);
2854 if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
2858 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2859 valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2863 bool EndObject(SizeType memberCount) {
2864 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndObject");
2865 if (!valid_)
return false;
2866 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2867 if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
2871 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2875 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartArray");
2876 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2877 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2878 valid_ = !outputHandler_ || outputHandler_->StartArray();
2882 bool EndArray(SizeType elementCount) {
2883 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndArray");
2884 if (!valid_)
return false;
2885 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2886 if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
2890 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2893#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2894#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2895#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2898 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root,
const bool inheritContinueOnErrors) {
2899 *documentStack_.template Push<Ch>() =
'\0';
2900 documentStack_.template Pop<Ch>(1);
2901 ISchemaValidator* sv =
new (GetStateAllocator().Malloc(
sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
2903 &GetStateAllocator());
2904 sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~static_cast<unsigned>(kValidateContinueOnErrorFlag));
2908 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2909 GenericSchemaValidator* v =
static_cast<GenericSchemaValidator*
>(validator);
2910 v->~GenericSchemaValidator();
2911 StateAllocator::Free(v);
2914 virtual void* CreateHasher() {
2915 return new (GetStateAllocator().Malloc(
sizeof(HasherType))) HasherType(&GetStateAllocator());
2918 virtual uint64_t GetHashCode(
void* hasher) {
2919 return static_cast<HasherType*
>(hasher)->GetHashCode();
2922 virtual void DestroryHasher(
void* hasher) {
2923 HasherType* h =
static_cast<HasherType*
>(hasher);
2925 StateAllocator::Free(h);
2928 virtual void* MallocState(
size_t size) {
2929 return GetStateAllocator().Malloc(size);
2932 virtual void FreeState(
void* p) {
2933 StateAllocator::Free(p);
2938 typedef typename SchemaType::Context Context;
2939 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2940 typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2942 GenericSchemaValidator(
2943 const SchemaDocumentType& schemaDocument,
2944 const SchemaType& root,
2945 const char* basePath,
size_t basePathSize,
2947 StateAllocator* allocator = 0,
2948 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2949 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2951 schemaDocument_(&schemaDocument),
2953 stateAllocator_(allocator),
2954 ownStateAllocator_(0),
2955 schemaStack_(allocator, schemaStackCapacity),
2956 documentStack_(allocator, documentStackCapacity),
2960 missingDependents_(),
2965 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath :
"");
2966 if (basePath && basePathSize)
2967 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2970 StateAllocator& GetStateAllocator() {
2971 if (!stateAllocator_)
2972 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2973 return *stateAllocator_;
2976 bool GetContinueOnErrors()
const {
2981 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::BeginValue");
2982 if (schemaStack_.Empty())
2985 if (CurrentContext().inArray)
2986 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2988 if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2991 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2992 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2993 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2994 bool valueUniqueness = CurrentContext().valueUniqueness;
2996 PushSchema(*CurrentContext().valueSchema);
2999 CurrentContext().objectPatternValidatorType = patternValidatorType;
3000 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3001 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3002 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
3003 std::memset(va, 0,
sizeof(ISchemaValidator*) * count);
3004 for (SizeType i = 0; i < count; i++)
3005 va[validatorCount++] = CreateSchemaValidator(*sa[i],
true);
3008 CurrentContext().arrayUniqueness = valueUniqueness;
3014 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndValue");
3015 if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3018 GenericStringBuffer<EncodingType> sb;
3019 schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3020 *documentStack_.template Push<Ch>() =
'\0';
3021 documentStack_.template Pop<Ch>(1);
3022 RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(), documentStack_.template Bottom<Ch>(), depth_);
3023 void* hasher = CurrentContext().hasher;
3024 uint64_t h = hasher && CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(hasher)->GetHashCode() : 0;
3028 if (!schemaStack_.Empty()) {
3029 Context& context = CurrentContext();
3031 if (hasher && context.valueUniqueness) {
3032 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
3034 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(kArrayType);
3035 for (
typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
3036 if (itr->GetUint64() == h) {
3037 DuplicateItems(
static_cast<SizeType>(itr - a->Begin()), a->Size());
3039 if (GetContinueOnErrors()) {
3040 a->PushBack(h, GetStateAllocator());
3041 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/');
3043 RAPIDJSON_INVALID_KEYWORD_RETURN(kValidateErrorUniqueItems);
3045 a->PushBack(h, GetStateAllocator());
3050 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
3056 void AppendToken(
const Ch* str, SizeType len) {
3057 documentStack_.template Reserve<Ch>(1 + len * 2);
3058 *documentStack_.template PushUnsafe<Ch>() =
'/';
3059 for (SizeType i = 0; i < len; i++) {
3060 if (str[i] ==
'~') {
3061 *documentStack_.template PushUnsafe<Ch>() =
'~';
3062 *documentStack_.template PushUnsafe<Ch>() =
'0';
3064 else if (str[i] ==
'/') {
3065 *documentStack_.template PushUnsafe<Ch>() =
'~';
3066 *documentStack_.template PushUnsafe<Ch>() =
'1';
3069 *documentStack_.template PushUnsafe<Ch>() = str[i];
3073 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema, flags_); }
3075 RAPIDJSON_FORCEINLINE
void PopSchema() {
3076 Context* c = schemaStack_.template Pop<Context>(1);
3077 if (HashCodeArray* a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
3078 a->~HashCodeArray();
3079 StateAllocator::Free(a);
3084 void AddErrorInstanceLocation(ValueType& result,
bool parent) {
3085 GenericStringBuffer<EncodingType> sb;
3086 PointerType instancePointer = GetInvalidDocumentPointer();
3087 ((parent && instancePointer.GetTokenCount() > 0)
3088 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3089 : instancePointer).StringifyUriFragment(sb);
3090 ValueType instanceRef(sb.GetString(),
static_cast<SizeType>(sb.GetSize() /
sizeof(Ch)),
3091 GetStateAllocator());
3092 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3095 void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
3096 GenericStringBuffer<EncodingType> sb;
3097 SizeType len = CurrentSchema().GetURI().GetStringLength();
3098 if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len *
sizeof(Ch));
3099 if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
3100 else GetInvalidSchemaPointer().StringifyUriFragment(sb);
3101 ValueType schemaRef(sb.GetString(),
static_cast<SizeType>(sb.GetSize() /
sizeof(Ch)),
3102 GetStateAllocator());
3103 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3106 void AddErrorCode(ValueType& result,
const ValidateErrorCode code) {
3107 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3110 void AddError(ValueType& keyword, ValueType& error) {
3111 typename ValueType::MemberIterator member = error_.FindMember(keyword);
3112 if (member == error_.MemberEnd())
3113 error_.AddMember(keyword, error, GetStateAllocator());
3115 if (member->value.IsObject()) {
3116 ValueType errors(kArrayType);
3117 errors.PushBack(member->value, GetStateAllocator());
3118 member->value = errors;
3120 member->value.PushBack(error, GetStateAllocator());
3124 void AddCurrentError(
const ValidateErrorCode code,
bool parent =
false) {
3125 AddErrorCode(currentError_, code);
3126 AddErrorInstanceLocation(currentError_, parent);
3127 AddErrorSchemaLocation(currentError_);
3128 AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(),
false).Move(), currentError_);
3131 void MergeError(ValueType& other) {
3132 for (
typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
3133 AddError(it->name, it->value);
3137 void AddNumberError(
const ValidateErrorCode code, ValueType& actual,
const SValue& expected,
3138 const typename SchemaType::ValueType& (*exclusive)() = 0) {
3139 currentError_.SetObject();
3140 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
3141 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
3143 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
3144 AddCurrentError(code);
3147 void AddErrorArray(
const ValidateErrorCode code,
3148 ISchemaValidator** subvalidators, SizeType count) {
3149 ValueType errors(kArrayType);
3150 for (SizeType i = 0; i < count; ++i)
3151 errors.PushBack(
static_cast<GenericSchemaValidator*
>(subvalidators[i])->GetError(), GetStateAllocator());
3152 currentError_.SetObject();
3153 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
3154 AddCurrentError(code);
3157 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
3158 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
3159 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
3161 static const size_t kDefaultSchemaStackCapacity = 1024;
3162 static const size_t kDefaultDocumentStackCapacity = 256;
3163 const SchemaDocumentType* schemaDocument_;
3164 const SchemaType& root_;
3165 StateAllocator* stateAllocator_;
3166 StateAllocator* ownStateAllocator_;
3167 internal::Stack<StateAllocator> schemaStack_;
3168 internal::Stack<StateAllocator> documentStack_;
3169 OutputHandler* outputHandler_;
3171 ValueType currentError_;
3172 ValueType missingDependents_;
3178typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
3194 unsigned parseFlags,
3195 typename InputStream,
3196 typename SourceEncoding,
3198 typename StackAllocator = CrtAllocator>
3201 typedef typename SchemaDocumentType::PointerType PointerType;
3202 typedef typename InputStream::Ch Ch;
3212 template <
typename Handler>
3213 bool operator()(
Handler& handler) {
3216 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
3218 isValid_ = validator.IsValid();
3220 invalidSchemaPointer_ = PointerType();
3221 invalidSchemaKeyword_ = 0;
3222 invalidDocumentPointer_ = PointerType();
3226 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
3227 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
3228 invalidSchemaCode_ = validator.GetInvalidSchemaCode();
3229 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
3230 error_.CopyFrom(validator.GetError(), allocator_);
3233 return parseResult_;
3236 const ParseResult& GetParseResult()
const {
return parseResult_; }
3237 bool IsValid()
const {
return isValid_; }
3238 const PointerType& GetInvalidSchemaPointer()
const {
return invalidSchemaPointer_; }
3239 const Ch* GetInvalidSchemaKeyword()
const {
return invalidSchemaKeyword_; }
3240 const PointerType& GetInvalidDocumentPointer()
const {
return invalidDocumentPointer_; }
3241 const ValueType& GetError()
const {
return error_; }
3246 const SchemaDocumentType& sd_;
3248 ParseResult parseResult_;
3249 PointerType invalidSchemaPointer_;
3250 const Ch* invalidSchemaKeyword_;
3251 PointerType invalidDocumentPointer_;
3253 StackAllocator allocator_;
3258RAPIDJSON_NAMESPACE_END
Concept for allocating, resizing and freeing memory block.
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition pointer.h:74
size_t GetParseErrorOffset() const
Get the parsing error offset in code unit.
Definition pointer.h:336
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition reader.h:539
JSON schema document.
Definition schema.h:1815
static const Specification GetSpecification(const ValueType &document)
Static method to get the specification of any schema document
Definition schema.h:1942
const SchemaType & GetRoot() const
Get the root schema.
Definition schema.h:1955
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:1994
void SchemaErrorValue(const SchemaErrorCode code, const PointerType &location, const Ch *value, SizeType length)
Method for error with single string value insert
Definition schema.h:1987
void SchemaError(const SchemaErrorCode code, const PointerType &location)
Default error method
Definition schema.h:1981
GValue & GetError()
Gets the error object.
Definition schema.h:1958
~GenericSchemaDocument()
Destructor
Definition schema.h:1918
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:1843
JSON Schema Validator.
Definition schema.h:2440
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition schema.h:2487
ValidateErrorCode GetInvalidSchemaCode() const
Gets the error code of invalid schema.
Definition schema.h:2568
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition schema.h:2554
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition schema.h:2576
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition schema.h:2560
ValueType & GetError()
End of Implementation of ISchemaValidator
Definition schema.h:2549
void ResetError()
Reset the error state.
Definition schema.h:2526
void SetValidateFlags(unsigned flags)
Implementation of ISchemaValidator
Definition schema.h:2534
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition schema.h:2457
~GenericSchemaValidator()
Destructor.
Definition schema.h:2512
void Reset()
Reset the internal states.
Definition schema.h:2518
Represents an in-memory output stream.
Definition stringbuffer.h:41
size_t GetSize() const
Get the size of string in bytes in the string buffer.
Definition stringbuffer.h:82
Represents a JSON value. Use Value for UTF8 encoding and default allocator.
Definition document.h:668
Concept for receiving events from GenericReader upon parsing. The functions return true if no error o...
A helper class for parsing with validation.
Definition schema.h:3199
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor
Definition schema.h:3210
#define RAPIDJSON_VALIDATE_DEFAULT_FLAGS
User-defined kValidateDefaultFlags definition.
Definition schema.h:174
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition rapidjson.h:437
ValidateErrorCode
Error codes when validating.
Definition error.h:162
SchemaErrorCode
Error codes when validating.
Definition error.h:220
@ kValidateErrors
Top level error code when kValidateContinueOnErrorsFlag set.
Definition error.h:163
@ kValidateErrorMaxItems
Array is longer than the 'maxItems' value.
Definition error.h:176
@ kValidateErrorRequired
Object is missing one or more members required by the schema.
Definition error.h:183
@ kValidateErrorMinProperties
Object has less members than 'minProperties' value.
Definition error.h:182
@ kValidateErrorMaximum
Number is greater than the 'maximum' value.
Definition error.h:167
@ kValidateErrorAdditionalProperties
Object has additional members that are not allowed by the schema.
Definition error.h:184
@ kValidateErrorNone
No error.
Definition error.h:164
@ kValidateErrorOneOf
Property did not match any of the sub-schemas specified by 'oneOf'.
Definition error.h:191
@ kValidateErrorEnum
Property has a value that is not one of its allowed enumerated values.
Definition error.h:188
@ kValidateErrorMaxLength
String is longer than the 'maxLength' value.
Definition error.h:172
@ kValidateErrorType
Property has a type that is not allowed by the schema.
Definition error.h:189
@ kValidateErrorMaxProperties
Object has more members than 'maxProperties' value.
Definition error.h:181
@ kValidateErrorNot
Property matched the sub-schema specified by 'not'.
Definition error.h:195
@ kValidateErrorExclusiveMinimum
Number is less than or equal to the 'minimum' value.
Definition error.h:170
@ kValidateErrorExclusiveMaximum
Number is greater than or equal to the 'maximum' value.
Definition error.h:168
@ kValidateErrorMultipleOf
Number is not a multiple of the 'multipleOf' value.
Definition error.h:166
@ kValidateErrorAnyOf
Property did not match any of the sub-schemas specified by 'anyOf'.
Definition error.h:194
@ kValidateErrorReadOnly
Property is read-only but has been provided when validation is for writing
Definition error.h:197
@ kValidateErrorWriteOnly
Property is write-only but has been provided when validation is for reading
Definition error.h:198
@ kValidateErrorAdditionalItems
Array has additional items that are not allowed by the schema.
Definition error.h:179
@ kValidateErrorPatternProperties
See other errors.
Definition error.h:185
@ kValidateErrorMinLength
String is longer than the 'maxLength' value.
Definition error.h:173
@ kValidateErrorMinimum
Number is less than the 'minimum' value.
Definition error.h:169
@ kValidateErrorDependencies
Object has missing property or schema dependencies.
Definition error.h:186
@ kValidateErrorMinItems
Array is shorter than the 'minItems' value.
Definition error.h:177
@ kValidateErrorOneOfMatch
Property matched more than one of the sub-schemas specified by 'oneOf'.
Definition error.h:192
@ kValidateErrorUniqueItems
Array has duplicate items but 'uniqueItems' is true.
Definition error.h:178
@ kValidateErrorPattern
String does not match the 'pattern' regular expression.
Definition error.h:174
@ kValidateErrorAllOf
Property did not match all of the sub-schemas specified by 'allOf'.
Definition error.h:193
@ kSchemaErrorStartUnknown
Pointer to start of schema does not resolve to a location in the document
Definition error.h:223
unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition rapidjson.h:415
GenericSchemaDocument< Value, CrtAllocator > SchemaDocument
GenericSchemaDocument using Value type.
Definition fwd.h:138
OpenApiVersion
Definition schema.h:202
@ kVersionMin
Current minimum supported version
Definition schema.h:205
@ kVersionMax
Current maximum supported version
Definition schema.h:208
ValidateFlag
Combination of validate flags
Definition schema.h:178
@ kValidateWriteFlag
Validation is for a write semantic.
Definition schema.h:182
@ kValidateContinueOnErrorFlag
Don't stop after first validation error.
Definition schema.h:180
@ kValidateNoFlags
No flags are set.
Definition schema.h:179
@ kValidateReadFlag
Validation is for a read semantic.
Definition schema.h:181
@ kValidateDefaultFlags
Default validate flags. Can be customized by defining RAPIDJSON_VALIDATE_DEFAULT_FLAGS
Definition schema.h:183
SchemaDraft
Definition schema.h:188
@ kDraftMin
Current minimum supported draft
Definition schema.h:192
@ kDraftMax
Current maximum supported draft
Definition schema.h:195
@ kArrayType
array
Definition rapidjson.h:734
@ kFalseType
false
Definition rapidjson.h:731
@ kObjectType
object
Definition rapidjson.h:733
IGenericRemoteSchemaDocumentProvider< SchemaDocument > IRemoteSchemaDocumentProvider
IGenericRemoteSchemaDocumentProvider using SchemaDocument.
Definition fwd.h:139
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition rapidjson.h:716
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition rapidjson.h:320
#define RAPIDJSON_NEW(TypeName)
! customization point for global new
Definition rapidjson.h:712
Reference to a constant string (not taking a copy)
Definition document.h:346