15 #ifndef RAPIDJSON_SCHEMA_H_ 16 #define RAPIDJSON_SCHEMA_H_ 22 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) 23 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 25 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 28 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) 29 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 31 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 34 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 35 #include "internal/regex.h" 36 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 40 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX 41 #define RAPIDJSON_SCHEMA_HAS_REGEX 1 43 #define RAPIDJSON_SCHEMA_HAS_REGEX 0 46 #ifndef RAPIDJSON_SCHEMA_VERBOSE 47 #define RAPIDJSON_SCHEMA_VERBOSE 0 50 #if RAPIDJSON_SCHEMA_VERBOSE 51 #include "stringbuffer.h" 57 RAPIDJSON_DIAG_OFF(effc++)
61 RAPIDJSON_DIAG_OFF(weak-vtables)
62 RAPIDJSON_DIAG_OFF(exit-time-destructors)
63 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
64 RAPIDJSON_DIAG_OFF(variadic-macros)
68 RAPIDJSON_DIAG_OFF(4512)
76 #if RAPIDJSON_SCHEMA_VERBOSE 80 inline void PrintInvalidKeyword(
const char* keyword) {
81 printf(
"Fail keyword: %s\n", keyword);
84 inline void PrintInvalidKeyword(
const wchar_t* keyword) {
85 wprintf(L
"Fail keyword: %ls\n", keyword);
88 inline void PrintInvalidDocument(
const char* document) {
89 printf(
"Fail document: %s\n\n", document);
92 inline void PrintInvalidDocument(
const wchar_t* document) {
93 wprintf(L
"Fail document: %ls\n\n", document);
96 inline void PrintValidatorPointers(
unsigned depth,
const char* s,
const char* d) {
97 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
100 inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
101 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
106 #endif // RAPIDJSON_SCHEMA_VERBOSE 111 #if RAPIDJSON_SCHEMA_VERBOSE 112 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) 114 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) 117 #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ 118 RAPIDJSON_MULTILINEMACRO_BEGIN\ 119 context.invalidKeyword = keyword.GetString();\ 120 RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ 122 RAPIDJSON_MULTILINEMACRO_END 127 template <
typename ValueType,
typename Allocator>
132 template <
typename SchemaDocumentType>
141 virtual bool IsValid()
const = 0;
147 template <
typename SchemaType>
153 virtual void* CreateHasher() = 0;
154 virtual uint64_t GetHashCode(
void* hasher) = 0;
155 virtual void DestroryHasher(
void* hasher) = 0;
156 virtual void* MallocState(
size_t size) = 0;
157 virtual void FreeState(
void* p) = 0;
164 template<
typename Encoding,
typename Allocator>
167 typedef typename Encoding::Ch Ch;
169 Hasher(Allocator* allocator = 0,
size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
171 bool Null() {
return WriteType(
kNullType); }
173 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
174 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
175 bool Int64(int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
176 bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
179 if (d < 0) n.u.i =
static_cast<int64_t
>(d);
180 else n.u.u =
static_cast<uint64_t
>(d);
182 return WriteNumber(n);
185 bool RawNumber(
const Ch* str,
SizeType len,
bool) {
190 bool String(
const Ch* str,
SizeType len,
bool) {
195 bool StartObject() {
return true; }
196 bool Key(
const Ch* str,
SizeType len,
bool copy) {
return String(str, len, copy); }
197 bool EndObject(
SizeType memberCount) {
199 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
200 for (
SizeType i = 0; i < memberCount; i++)
201 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
202 *stack_.template Push<uint64_t>() = h;
206 bool StartArray() {
return true; }
207 bool EndArray(
SizeType elementCount) {
209 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
210 for (
SizeType i = 0; i < elementCount; i++)
212 *stack_.template Push<uint64_t>() = h;
216 bool IsValid()
const {
return stack_.GetSize() ==
sizeof(uint64_t); }
218 uint64_t GetHashCode()
const {
220 return *stack_.template Top<uint64_t>();
224 static const size_t kDefaultSize = 256;
233 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
235 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
237 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
240 const unsigned char* d =
static_cast<const unsigned char*
>(data);
241 for (
size_t i = 0; i < len; i++)
243 *stack_.template Push<uint64_t>() = h;
247 static uint64_t Hash(uint64_t h, uint64_t d) {
260 template <
typename SchemaDocumentType>
264 typedef typename SchemaType::ValueType ValueType;
265 typedef typename ValueType::Ch Ch;
267 enum PatternValidatorType {
268 kPatternValidatorOnly,
269 kPatternValidatorWithProperty,
270 kPatternValidatorWithAdditionalProperty
279 arrayElementHashCodes(),
282 patternPropertiesValidators(),
283 patternPropertiesValidatorCount(),
284 patternPropertiesSchemas(),
285 patternPropertiesSchemaCount(),
286 valuePatternValidatorType(kPatternValidatorOnly),
289 valueUniqueness(
false),
290 arrayUniqueness(
false)
296 factory.DestroryHasher(hasher);
298 for (
SizeType i = 0; i < validatorCount; i++)
299 factory.DestroySchemaValidator(validators[i]);
300 factory.FreeState(validators);
302 if (patternPropertiesValidators) {
303 for (
SizeType i = 0; i < patternPropertiesValidatorCount; i++)
304 factory.DestroySchemaValidator(patternPropertiesValidators[i]);
305 factory.FreeState(patternPropertiesValidators);
307 if (patternPropertiesSchemas)
308 factory.FreeState(patternPropertiesSchemas);
310 factory.FreeState(propertyExist);
313 SchemaValidatorFactoryType& factory;
314 const SchemaType* schema;
315 const SchemaType* valueSchema;
316 const Ch* invalidKeyword;
318 void* arrayElementHashCodes;
322 SizeType patternPropertiesValidatorCount;
323 const SchemaType** patternPropertiesSchemas;
324 SizeType patternPropertiesSchemaCount;
325 PatternValidatorType valuePatternValidatorType;
326 PatternValidatorType objectPatternValidatorType;
330 bool valueUniqueness;
331 bool arrayUniqueness;
337 template <
typename SchemaDocumentType>
340 typedef typename SchemaDocumentType::ValueType ValueType;
341 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
342 typedef typename SchemaDocumentType::PointerType PointerType;
343 typedef typename ValueType::EncodingType EncodingType;
344 typedef typename EncodingType::Ch Ch;
350 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator) :
351 allocator_(allocator),
352 typeless_(schemaDocument->GetTypeless()),
356 type_((1 << kTotalSchemaType) - 1),
359 additionalPropertiesSchema_(),
360 patternProperties_(),
361 patternPropertyCount_(),
365 additionalProperties_(
true),
368 hasSchemaDependencies_(),
369 additionalItemsSchema_(),
375 additionalItems_(
true),
380 exclusiveMinimum_(
false),
381 exclusiveMaximum_(
false)
383 typedef typename SchemaDocumentType::ValueType ValueType;
384 typedef typename ValueType::ConstValueIterator ConstValueIterator;
385 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
387 if (!value.IsObject())
390 if (
const ValueType* v = GetMember(value, GetTypeString())) {
394 else if (v->IsArray())
395 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
399 if (
const ValueType* v = GetMember(value, GetEnumString()))
400 if (v->IsArray() && v->Size() > 0) {
401 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
402 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
404 char buffer[256 + 24];
406 EnumHasherType h(&hasherAllocator, 256);
408 enum_[enumCount_++] = h.GetHashCode();
412 if (schemaDocument) {
413 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
414 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
415 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
418 if (
const ValueType* v = GetMember(value, GetNotString())) {
419 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
420 notValidatorIndex_ = validatorCount_;
426 const ValueType* properties = GetMember(value, GetPropertiesString());
427 const ValueType* required = GetMember(value, GetRequiredString());
428 const ValueType* dependencies = GetMember(value, GetDependenciesString());
433 if (properties && properties->IsObject())
434 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
435 AddUniqueElement(allProperties, itr->name);
437 if (required && required->IsArray())
438 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
440 AddUniqueElement(allProperties, *itr);
442 if (dependencies && dependencies->IsObject())
443 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
444 AddUniqueElement(allProperties, itr->name);
445 if (itr->value.IsArray())
446 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
448 AddUniqueElement(allProperties, *i);
451 if (allProperties.Size() > 0) {
452 propertyCount_ = allProperties.Size();
453 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
454 for (
SizeType i = 0; i < propertyCount_; i++) {
455 new (&properties_[i]) Property();
456 properties_[i].name = allProperties[i];
457 properties_[i].schema = typeless_;
462 if (properties && properties->IsObject()) {
463 PointerType q = p.Append(GetPropertiesString(), allocator_);
464 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
466 if (FindPropertyIndex(itr->name, &index))
467 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
471 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
472 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
473 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
474 patternPropertyCount_ = 0;
476 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
477 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
478 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
479 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
480 patternPropertyCount_++;
484 if (required && required->IsArray())
485 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
486 if (itr->IsString()) {
488 if (FindPropertyIndex(*itr, &index)) {
489 properties_[index].required =
true;
494 if (dependencies && dependencies->IsObject()) {
495 PointerType q = p.Append(GetDependenciesString(), allocator_);
496 hasDependencies_ =
true;
497 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
499 if (FindPropertyIndex(itr->name, &sourceIndex)) {
500 if (itr->value.IsArray()) {
501 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
502 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
503 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
505 if (FindPropertyIndex(*targetItr, &targetIndex))
506 properties_[sourceIndex].dependencies[targetIndex] =
true;
509 else if (itr->value.IsObject()) {
510 hasSchemaDependencies_ =
true;
511 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
512 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
519 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
521 additionalProperties_ = v->GetBool();
522 else if (v->IsObject())
523 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
526 AssignIfExist(minProperties_, value, GetMinPropertiesString());
527 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
530 if (
const ValueType* v = GetMember(value, GetItemsString())) {
531 PointerType q = p.Append(GetItemsString(), allocator_);
533 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
534 else if (v->IsArray()) {
535 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
537 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
538 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
542 AssignIfExist(minItems_, value, GetMinItemsString());
543 AssignIfExist(maxItems_, value, GetMaxItemsString());
545 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
547 additionalItems_ = v->GetBool();
548 else if (v->IsObject())
549 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
552 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
555 AssignIfExist(minLength_, value, GetMinLengthString());
556 AssignIfExist(maxLength_, value, GetMaxLengthString());
558 if (
const ValueType* v = GetMember(value, GetPatternString()))
559 pattern_ = CreatePattern(*v);
562 if (
const ValueType* v = GetMember(value, GetMinimumString()))
564 minimum_.CopyFrom(*v, *allocator_);
566 if (
const ValueType* v = GetMember(value, GetMaximumString()))
568 maximum_.CopyFrom(*v, *allocator_);
570 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
571 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
573 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
574 if (v->IsNumber() && v->GetDouble() > 0.0)
575 multipleOf_.CopyFrom(*v, *allocator_);
579 AllocatorType::Free(enum_);
581 for (
SizeType i = 0; i < propertyCount_; i++)
582 properties_[i].~Property();
583 AllocatorType::Free(properties_);
585 if (patternProperties_) {
586 for (
SizeType i = 0; i < patternPropertyCount_; i++)
587 patternProperties_[i].~PatternProperty();
588 AllocatorType::Free(patternProperties_);
590 AllocatorType::Free(itemsTuple_);
591 #if RAPIDJSON_SCHEMA_HAS_REGEX 593 pattern_->~RegexType();
594 AllocatorType::Free(pattern_);
599 bool BeginValue(Context& context)
const {
600 if (context.inArray) {
602 context.valueUniqueness =
true;
605 context.valueSchema = itemsList_;
606 else if (itemsTuple_) {
607 if (context.arrayElementIndex < itemsTupleCount_)
608 context.valueSchema = itemsTuple_[context.arrayElementIndex];
609 else if (additionalItemsSchema_)
610 context.valueSchema = additionalItemsSchema_;
611 else if (additionalItems_)
612 context.valueSchema = typeless_;
614 RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
617 context.valueSchema = typeless_;
619 context.arrayElementIndex++;
624 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
625 if (context.patternPropertiesValidatorCount > 0) {
626 bool otherValid =
false;
627 SizeType count = context.patternPropertiesValidatorCount;
628 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
629 otherValid = context.patternPropertiesValidators[--count]->IsValid();
631 bool patternValid =
true;
632 for (
SizeType i = 0; i < count; i++)
633 if (!context.patternPropertiesValidators[i]->IsValid()) {
634 patternValid =
false;
638 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
640 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
642 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
643 if (!patternValid || !otherValid)
644 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
646 else if (!patternValid && !otherValid)
647 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
651 const uint64_t h = context.factory.GetHashCode(context.hasher);
652 for (
SizeType i = 0; i < enumCount_; i++)
655 RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
660 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
661 if (!context.validators[i]->IsValid())
662 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
664 if (anyOf_.schemas) {
665 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
666 if (context.validators[i]->IsValid())
668 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
672 if (oneOf_.schemas) {
673 bool oneValid =
false;
674 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
675 if (context.validators[i]->IsValid()) {
677 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
682 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
685 if (not_ && context.validators[notValidatorIndex_]->IsValid())
686 RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
691 bool Null(Context& context)
const {
692 if (!(type_ & (1 << kNullSchemaType)))
693 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
694 return CreateParallelValidator(context);
697 bool Bool(Context& context,
bool)
const {
698 if (!(type_ & (1 << kBooleanSchemaType)))
699 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
700 return CreateParallelValidator(context);
703 bool Int(Context& context,
int i)
const {
704 if (!CheckInt(context, i))
706 return CreateParallelValidator(context);
709 bool Uint(Context& context,
unsigned u)
const {
710 if (!CheckUint(context, u))
712 return CreateParallelValidator(context);
715 bool Int64(Context& context, int64_t i)
const {
716 if (!CheckInt(context, i))
718 return CreateParallelValidator(context);
721 bool Uint64(Context& context, uint64_t u)
const {
722 if (!CheckUint(context, u))
724 return CreateParallelValidator(context);
727 bool Double(Context& context,
double d)
const {
728 if (!(type_ & (1 << kNumberSchemaType)))
729 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
731 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
734 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
737 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
740 return CreateParallelValidator(context);
743 bool String(Context& context,
const Ch* str,
SizeType length,
bool)
const {
744 if (!(type_ & (1 << kStringSchemaType)))
745 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
747 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
749 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
750 if (count < minLength_)
751 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
752 if (count > maxLength_)
753 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
757 if (pattern_ && !IsPatternMatch(pattern_, str, length))
758 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
760 return CreateParallelValidator(context);
763 bool StartObject(Context& context)
const {
764 if (!(type_ & (1 << kObjectSchemaType)))
765 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
767 if (hasDependencies_ || hasRequired_) {
768 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
769 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
772 if (patternProperties_) {
773 SizeType count = patternPropertyCount_ + 1;
774 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
775 context.patternPropertiesSchemaCount = 0;
776 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
779 return CreateParallelValidator(context);
782 bool Key(Context& context,
const Ch* str,
SizeType len,
bool)
const {
783 if (patternProperties_) {
784 context.patternPropertiesSchemaCount = 0;
785 for (
SizeType i = 0; i < patternPropertyCount_; i++)
786 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
787 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
791 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
792 if (context.patternPropertiesSchemaCount > 0) {
793 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
794 context.valueSchema = typeless_;
795 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
798 context.valueSchema = properties_[index].schema;
800 if (context.propertyExist)
801 context.propertyExist[index] =
true;
806 if (additionalPropertiesSchema_) {
807 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
808 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
809 context.valueSchema = typeless_;
810 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
813 context.valueSchema = additionalPropertiesSchema_;
816 else if (additionalProperties_) {
817 context.valueSchema = typeless_;
821 if (context.patternPropertiesSchemaCount == 0)
822 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
827 bool EndObject(Context& context,
SizeType memberCount)
const {
829 for (
SizeType index = 0; index < propertyCount_; index++)
830 if (properties_[index].required)
831 if (!context.propertyExist[index])
832 RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
834 if (memberCount < minProperties_)
835 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
837 if (memberCount > maxProperties_)
838 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
840 if (hasDependencies_) {
841 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
842 if (context.propertyExist[sourceIndex]) {
843 if (properties_[sourceIndex].dependencies) {
844 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
845 if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
846 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
848 else if (properties_[sourceIndex].dependenciesSchema)
849 if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
850 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
857 bool StartArray(Context& context)
const {
858 if (!(type_ & (1 << kArraySchemaType)))
859 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
861 context.arrayElementIndex = 0;
862 context.inArray =
true;
864 return CreateParallelValidator(context);
867 bool EndArray(Context& context,
SizeType elementCount)
const {
868 context.inArray =
false;
870 if (elementCount < minItems_)
871 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
873 if (elementCount > maxItems_)
874 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
880 #define RAPIDJSON_STRING_(name, ...) \ 881 static const ValueType& Get##name##String() {\ 882 static const Ch s[] = { __VA_ARGS__, '\0' };\ 883 static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ 887 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
888 RAPIDJSON_STRING_(Boolean,
'b',
'o',
'o',
'l',
'e',
'a',
'n')
889 RAPIDJSON_STRING_(Object,
'o',
'b',
'j',
'e',
'c',
't')
890 RAPIDJSON_STRING_(Array,
'a',
'r',
'r',
'a',
'y')
891 RAPIDJSON_STRING_(String,
's',
't',
'r',
'i',
'n',
'g')
892 RAPIDJSON_STRING_(Number,
'n',
'u',
'm',
'b',
'e',
'r')
893 RAPIDJSON_STRING_(Integer,
'i',
'n',
't',
'e',
'g',
'e',
'r')
894 RAPIDJSON_STRING_(
Type,
't',
'y',
'p',
'e')
895 RAPIDJSON_STRING_(Enum,
'e',
'n',
'u',
'm')
896 RAPIDJSON_STRING_(AllOf,
'a',
'l',
'l',
'O',
'f')
897 RAPIDJSON_STRING_(AnyOf,
'a',
'n',
'y',
'O',
'f')
898 RAPIDJSON_STRING_(OneOf,
'o',
'n',
'e',
'O',
'f')
899 RAPIDJSON_STRING_(Not,
'n',
'o',
't')
900 RAPIDJSON_STRING_(Properties,
'p',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
901 RAPIDJSON_STRING_(Required,
'r',
'e',
'q',
'u',
'i',
'r',
'e',
'd')
902 RAPIDJSON_STRING_(Dependencies,
'd',
'e',
'p',
'e',
'n',
'd',
'e',
'n',
'c',
'i',
'e',
's')
903 RAPIDJSON_STRING_(PatternProperties,
'p',
'a',
't',
't',
'e',
'r',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
904 RAPIDJSON_STRING_(AdditionalProperties,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
905 RAPIDJSON_STRING_(MinProperties,
'm',
'i',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
906 RAPIDJSON_STRING_(MaxProperties,
'm',
'a',
'x',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
907 RAPIDJSON_STRING_(Items,
'i',
't',
'e',
'm',
's')
908 RAPIDJSON_STRING_(MinItems,
'm',
'i',
'n',
'I',
't',
'e',
'm',
's')
909 RAPIDJSON_STRING_(MaxItems,
'm',
'a',
'x',
'I',
't',
'e',
'm',
's')
910 RAPIDJSON_STRING_(AdditionalItems,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'I',
't',
'e',
'm',
's')
911 RAPIDJSON_STRING_(UniqueItems,
'u',
'n',
'i',
'q',
'u',
'e',
'I',
't',
'e',
'm',
's')
912 RAPIDJSON_STRING_(MinLength,
'm',
'i',
'n',
'L',
'e',
'n',
'g',
't',
'h')
913 RAPIDJSON_STRING_(MaxLength,
'm',
'a',
'x',
'L',
'e',
'n',
'g',
't',
'h')
914 RAPIDJSON_STRING_(Pattern,
'p',
'a',
't',
't',
'e',
'r',
'n')
915 RAPIDJSON_STRING_(Minimum,
'm',
'i',
'n',
'i',
'm',
'u',
'm')
916 RAPIDJSON_STRING_(Maximum,
'm',
'a',
'x',
'i',
'm',
'u',
'm')
917 RAPIDJSON_STRING_(ExclusiveMinimum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'i',
'n',
'i',
'm',
'u',
'm')
918 RAPIDJSON_STRING_(ExclusiveMaximum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'a',
'x',
'i',
'm',
'u',
'm')
919 RAPIDJSON_STRING_(MultipleOf,
'm',
'u',
'l',
't',
'i',
'p',
'l',
'e',
'O',
'f')
921 #undef RAPIDJSON_STRING_ 924 enum SchemaValueType {
935 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 937 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 938 typedef std::basic_regex<Ch> RegexType;
940 typedef char RegexType;
944 SchemaArray() : schemas(), count() {}
945 ~SchemaArray() { AllocatorType::Free(schemas); }
946 const SchemaType** schemas;
951 template <
typename V1,
typename V2>
952 void AddUniqueElement(V1& a,
const V2& v) {
953 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
956 V1 c(v, *allocator_);
957 a.PushBack(c, *allocator_);
960 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
961 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
962 return itr != value.MemberEnd() ? &(itr->value) : 0;
965 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
966 if (
const ValueType* v = GetMember(value, name))
971 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
972 if (
const ValueType* v = GetMember(value, name))
973 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
974 out = static_cast<SizeType>(v->GetUint64());
977 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
978 if (
const ValueType* v = GetMember(value, name)) {
979 if (v->IsArray() && v->Size() > 0) {
980 PointerType q = p.Append(name, allocator_);
981 out.count = v->Size();
982 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
983 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
984 for (
SizeType i = 0; i < out.count; i++)
985 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
986 out.begin = validatorCount_;
987 validatorCount_ += out.count;
992 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX 993 template <
typename ValueType>
994 RegexType* CreatePattern(
const ValueType& value) {
995 if (value.IsString()) {
996 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString());
999 AllocatorType::Free(r);
1007 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1009 return rs.Search(str);
1011 #elif RAPIDJSON_SCHEMA_USE_STDREGEX 1012 template <
typename ValueType>
1013 RegexType* CreatePattern(
const ValueType& value) {
1014 if (value.IsString())
1016 return new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1018 catch (
const std::regex_error&) {
1023 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1024 std::match_results<const Ch*> r;
1025 return std::regex_search(str, str + length, r, *pattern);
1028 template <
typename ValueType>
1029 RegexType* CreatePattern(
const ValueType&) {
return 0; }
1031 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1032 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX 1034 void AddType(
const ValueType& type) {
1035 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1036 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1037 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1038 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1039 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1040 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1041 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1044 bool CreateParallelValidator(Context& context)
const {
1045 if (enum_ || context.arrayUniqueness)
1046 context.hasher = context.factory.CreateHasher();
1048 if (validatorCount_) {
1051 context.validatorCount = validatorCount_;
1054 CreateSchemaValidators(context, allOf_);
1057 CreateSchemaValidators(context, anyOf_);
1060 CreateSchemaValidators(context, oneOf_);
1063 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1065 if (hasSchemaDependencies_) {
1066 for (
SizeType i = 0; i < propertyCount_; i++)
1067 if (properties_[i].dependenciesSchema)
1068 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1075 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas)
const {
1076 for (
SizeType i = 0; i < schemas.count; i++)
1077 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1081 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1082 SizeType len = name.GetStringLength();
1083 const Ch* str = name.GetString();
1084 for (
SizeType index = 0; index < propertyCount_; index++)
1085 if (properties_[index].name.GetStringLength() == len &&
1086 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1094 bool CheckInt(Context& context, int64_t i)
const {
1095 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1096 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1098 if (!minimum_.IsNull()) {
1099 if (minimum_.IsInt64()) {
1100 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1101 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1103 else if (minimum_.IsUint64()) {
1104 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1106 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1110 if (!maximum_.IsNull()) {
1111 if (maximum_.IsInt64()) {
1112 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1113 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1115 else if (maximum_.IsUint64())
1117 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1121 if (!multipleOf_.IsNull()) {
1122 if (multipleOf_.IsUint64()) {
1123 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1124 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1126 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1133 bool CheckUint(Context& context, uint64_t i)
const {
1134 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1135 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1137 if (!minimum_.IsNull()) {
1138 if (minimum_.IsUint64()) {
1139 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1140 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1142 else if (minimum_.IsInt64())
1144 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
1148 if (!maximum_.IsNull()) {
1149 if (maximum_.IsUint64()) {
1150 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1151 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1153 else if (maximum_.IsInt64())
1154 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1155 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
1159 if (!multipleOf_.IsNull()) {
1160 if (multipleOf_.IsUint64()) {
1161 if (i % multipleOf_.GetUint64() != 0)
1162 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1164 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
1171 bool CheckDoubleMinimum(Context& context,
double d)
const {
1172 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
1173 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1177 bool CheckDoubleMaximum(Context& context,
double d)
const {
1178 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
1179 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1183 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1184 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1185 double q = std::floor(a / b);
1186 double r = a - q * b;
1188 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1193 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1194 ~Property() { AllocatorType::Free(dependencies); }
1196 const SchemaType* schema;
1197 const SchemaType* dependenciesSchema;
1198 SizeType dependenciesValidatorIndex;
1203 struct PatternProperty {
1204 PatternProperty() : schema(), pattern() {}
1205 ~PatternProperty() {
1207 pattern->~RegexType();
1208 AllocatorType::Free(pattern);
1211 const SchemaType* schema;
1215 AllocatorType* allocator_;
1216 const SchemaType* typeless_;
1222 const SchemaType* not_;
1227 Property* properties_;
1228 const SchemaType* additionalPropertiesSchema_;
1229 PatternProperty* patternProperties_;
1234 bool additionalProperties_;
1235 bool hasDependencies_;
1237 bool hasSchemaDependencies_;
1239 const SchemaType* additionalItemsSchema_;
1240 const SchemaType* itemsList_;
1241 const SchemaType** itemsTuple_;
1245 bool additionalItems_;
1248 RegexType* pattern_;
1255 bool exclusiveMinimum_;
1256 bool exclusiveMaximum_;
1259 template<
typename Stack,
typename Ch>
1261 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1262 *documentStack.template Push<Ch>() =
'/';
1264 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
1265 for (
size_t i = 0; i < length; i++)
1266 *documentStack.template Push<Ch>() = buffer[i];
1271 template <
typename Stack>
1273 RAPIDJSON_FORCEINLINE
static void AppendIndexToken(
Stack& documentStack,
SizeType index) {
1275 char *buffer = documentStack.template Push<char>(1 + 10);
1277 const char* end = internal::u32toa(index, buffer);
1278 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1281 char *buffer = documentStack.template Push<char>(1 + 20);
1283 const char* end = internal::u64toa(index, buffer);
1284 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1294 template <
typename SchemaDocumentType>
1297 typedef typename SchemaDocumentType::Ch Ch;
1300 virtual const SchemaDocumentType* GetRemoteDocument(
const Ch* uri,
SizeType length) = 0;
1315 template <
typename ValueT,
typename Allocator = CrtAllocator>
1318 typedef ValueT ValueType;
1320 typedef Allocator AllocatorType;
1321 typedef typename ValueType::EncodingType EncodingType;
1322 typedef typename EncodingType::Ch Ch;
1326 template <
typename,
typename,
typename>
1337 explicit GenericSchemaDocument(
const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1338 remoteProvider_(remoteProvider),
1339 allocator_(allocator),
1343 schemaMap_(allocator, kInitialSchemaMapSize),
1344 schemaRef_(allocator, kInitialSchemaRefSize)
1349 typeless_ =
static_cast<SchemaType*
>(allocator_->Malloc(
sizeof(SchemaType)));
1350 new (typeless_) SchemaType(
this, PointerType(), ValueType(
kObjectType).Move(), ValueType(
kObjectType).Move(), 0);
1354 CreateSchemaRecursive(&root_, PointerType(), document, document);
1357 while (!schemaRef_.Empty()) {
1358 SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
1359 if (
const SchemaType* s = GetSchema(refEntry->target)) {
1360 if (refEntry->schema)
1361 *refEntry->schema = s;
1364 if (!GetSchema(refEntry->source)) {
1365 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s),
false, allocator_);
1368 else if (refEntry->schema)
1369 *refEntry->schema = typeless_;
1371 refEntry->~SchemaRefEntry();
1376 schemaRef_.ShrinkToFit();
1379 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS 1380 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
1382 remoteProvider_(rhs.remoteProvider_),
1383 allocator_(rhs.allocator_),
1384 ownAllocator_(rhs.ownAllocator_),
1386 typeless_(rhs.typeless_),
1387 schemaMap_(std::move(rhs.schemaMap_)),
1388 schemaRef_(std::move(rhs.schemaRef_))
1390 rhs.remoteProvider_ = 0;
1392 rhs.ownAllocator_ = 0;
1399 while (!schemaMap_.Empty())
1400 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1403 typeless_->~SchemaType();
1404 Allocator::Free(typeless_);
1411 const SchemaType&
GetRoot()
const {
return *root_; }
1415 GenericSchemaDocument(
const GenericSchemaDocument&);
1417 GenericSchemaDocument& operator=(
const GenericSchemaDocument&);
1419 struct SchemaRefEntry {
1420 SchemaRefEntry(
const PointerType& s,
const PointerType& t,
const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
1423 const SchemaType** schema;
1426 struct SchemaEntry {
1427 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
1430 schema->~SchemaType();
1431 Allocator::Free(schema);
1434 PointerType pointer;
1439 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1441 *schema = typeless_;
1444 const SchemaType* s = GetSchema(pointer);
1446 CreateSchema(schema, pointer, v, document);
1448 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1449 CreateSchemaRecursive(0, pointer.
Append(itr->name, allocator_), itr->value, document);
1452 for (
SizeType i = 0; i < v.Size(); i++)
1453 CreateSchemaRecursive(0, pointer.
Append(i, allocator_), v[i], document);
1456 void CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document) {
1459 if (!HandleRefSchema(pointer, schema, v, document)) {
1460 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_);
1461 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s,
true, allocator_);
1468 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document) {
1469 static const Ch kRefString[] = {
'$',
'r',
'e',
'f',
'\0' };
1470 static const ValueType kRefValue(kRefString, 4);
1472 typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
1473 if (itr == v.MemberEnd())
1476 if (itr->value.IsString()) {
1477 SizeType len = itr->value.GetStringLength();
1479 const Ch* s = itr->value.GetString();
1481 while (i < len && s[i] !=
'#')
1485 if (remoteProvider_) {
1486 if (
const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
1487 PointerType pointer(&s[i], len - i, allocator_);
1488 if (pointer.IsValid()) {
1489 if (
const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
1498 else if (s[i] ==
'#') {
1499 PointerType pointer(&s[i], len - i, allocator_);
1500 if (pointer.IsValid()) {
1501 if (
const ValueType* nv = pointer.Get(document))
1502 if (HandleRefSchema(source, schema, *nv, document))
1505 new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
1514 const SchemaType* GetSchema(
const PointerType& pointer)
const {
1515 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1516 if (pointer == target->pointer)
1517 return target->schema;
1521 PointerType GetPointer(
const SchemaType* schema)
const {
1522 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1523 if (schema == target->schema)
1524 return target->pointer;
1525 return PointerType();
1528 const SchemaType* GetTypeless()
const {
return typeless_; }
1530 static const size_t kInitialSchemaMapSize = 64;
1531 static const size_t kInitialSchemaRefSize = 64;
1533 IRemoteSchemaDocumentProviderType* remoteProvider_;
1534 Allocator *allocator_;
1535 Allocator *ownAllocator_;
1536 const SchemaType* root_;
1537 SchemaType* typeless_;
1563 typename SchemaDocumentType,
1571 typedef typename SchemaDocumentType::SchemaType
SchemaType;
1572 typedef typename SchemaDocumentType::PointerType
PointerType;
1573 typedef typename SchemaType::EncodingType EncodingType;
1574 typedef typename EncodingType::Ch Ch;
1584 const SchemaDocumentType& schemaDocument,
1585 StateAllocator* allocator = 0,
1586 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1587 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1589 schemaDocument_(&schemaDocument),
1590 root_(schemaDocument.GetRoot()),
1591 stateAllocator_(allocator),
1592 ownStateAllocator_(0),
1593 schemaStack_(allocator, schemaStackCapacity),
1594 documentStack_(allocator, documentStackCapacity),
1595 outputHandler_(CreateNullHandler()),
1597 #if RAPIDJSON_SCHEMA_VERBOSE
1611 const SchemaDocumentType& schemaDocument,
1612 OutputHandler& outputHandler,
1613 StateAllocator* allocator = 0,
1614 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1615 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1617 schemaDocument_(&schemaDocument),
1618 root_(schemaDocument.GetRoot()),
1619 stateAllocator_(allocator),
1620 ownStateAllocator_(0),
1621 schemaStack_(allocator, schemaStackCapacity),
1622 documentStack_(allocator, documentStackCapacity),
1623 outputHandler_(outputHandler),
1626 #if RAPIDJSON_SCHEMA_VERBOSE
1636 nullHandler_->~OutputHandler();
1637 StateAllocator::Free(nullHandler_);
1644 while (!schemaStack_.Empty())
1646 documentStack_.Clear();
1656 return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
1661 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1666 return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
1669 #if RAPIDJSON_SCHEMA_VERBOSE 1670 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ 1671 RAPIDJSON_MULTILINEMACRO_BEGIN\ 1672 *documentStack_.template Push<Ch>() = '\0';\ 1673 documentStack_.template Pop<Ch>(1);\ 1674 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\ 1675 RAPIDJSON_MULTILINEMACRO_END 1677 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() 1680 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ 1681 if (!valid_) return false; \ 1682 if (!BeginValue() || !CurrentSchema().method arg1) {\ 1683 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ 1684 return valid_ = false;\ 1687 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ 1688 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\ 1689 if (context->hasher)\ 1690 static_cast<HasherType*>(context->hasher)->method arg2;\ 1691 if (context->validators)\ 1692 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ 1693 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\ 1694 if (context->patternPropertiesValidators)\ 1695 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ 1696 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\ 1699 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ 1700 return valid_ = EndValue() && outputHandler_.method arg2 1702 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ 1703 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ 1704 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ 1705 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) 1707 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
1708 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
1709 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
1710 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
1711 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
1712 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
1713 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
1714 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
1715 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1716 bool String(
const Ch* str,
SizeType length,
bool copy)
1717 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
1719 bool StartObject() {
1720 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
1721 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
1722 return valid_ = outputHandler_.StartObject();
1725 bool Key(
const Ch* str,
SizeType len,
bool copy) {
1726 if (!valid_)
return false;
1727 AppendToken(str, len);
1728 if (!CurrentSchema().Key(CurrentContext(), str, len, copy))
return valid_ =
false;
1729 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
1730 return valid_ = outputHandler_.Key(str, len, copy);
1733 bool EndObject(
SizeType memberCount) {
1734 if (!valid_)
return false;
1735 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
1736 if (!CurrentSchema().EndObject(CurrentContext(), memberCount))
return valid_ =
false;
1737 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
1741 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
1742 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
1743 return valid_ = outputHandler_.StartArray();
1746 bool EndArray(
SizeType elementCount) {
1747 if (!valid_)
return false;
1748 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
1749 if (!CurrentSchema().EndArray(CurrentContext(), elementCount))
return valid_ =
false;
1750 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
1753 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ 1754 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ 1755 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ 1756 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ 1759 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root) {
1761 #
if RAPIDJSON_SCHEMA_VERBOSE
1764 &GetStateAllocator());
1767 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
1770 StateAllocator::Free(v);
1773 virtual void* CreateHasher() {
1777 virtual uint64_t GetHashCode(
void* hasher) {
1778 return static_cast<HasherType*
>(hasher)->GetHashCode();
1781 virtual void DestroryHasher(
void* hasher) {
1784 StateAllocator::Free(h);
1787 virtual void* MallocState(
size_t size) {
1788 return GetStateAllocator().Malloc(size);
1791 virtual void FreeState(
void* p) {
1792 return StateAllocator::Free(p);
1796 typedef typename SchemaType::Context Context;
1801 const SchemaDocumentType& schemaDocument,
1802 const SchemaType& root,
1803 #
if RAPIDJSON_SCHEMA_VERBOSE
1806 StateAllocator* allocator = 0,
1807 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1808 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1810 schemaDocument_(&schemaDocument),
1812 stateAllocator_(allocator),
1813 ownStateAllocator_(0),
1814 schemaStack_(allocator, schemaStackCapacity),
1815 documentStack_(allocator, documentStackCapacity),
1816 outputHandler_(CreateNullHandler()),
1818 #if RAPIDJSON_SCHEMA_VERBOSE 1824 StateAllocator& GetStateAllocator() {
1825 if (!stateAllocator_)
1826 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator());
1827 return *stateAllocator_;
1831 if (schemaStack_.Empty())
1834 if (CurrentContext().inArray)
1837 if (!CurrentSchema().BeginValue(CurrentContext()))
1840 SizeType count = CurrentContext().patternPropertiesSchemaCount;
1841 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
1842 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
1843 bool valueUniqueness = CurrentContext().valueUniqueness;
1845 PushSchema(*CurrentContext().valueSchema);
1848 CurrentContext().objectPatternValidatorType = patternValidatorType;
1849 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
1850 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
1851 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
1852 for (
SizeType i = 0; i < count; i++)
1853 va[validatorCount++] = CreateSchemaValidator(*sa[i]);
1856 CurrentContext().arrayUniqueness = valueUniqueness;
1862 if (!CurrentSchema().EndValue(CurrentContext()))
1865 #if RAPIDJSON_SCHEMA_VERBOSE 1867 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
1869 *documentStack_.template Push<Ch>() =
'\0';
1870 documentStack_.template Pop<Ch>(1);
1871 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
1874 uint64_t h = CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(CurrentContext().hasher)->GetHashCode() : 0;
1878 if (!schemaStack_.Empty()) {
1879 Context& context = CurrentContext();
1880 if (context.valueUniqueness) {
1881 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
1883 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
1885 if (itr->GetUint64() == h)
1886 RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
1887 a->PushBack(h, GetStateAllocator());
1892 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
1898 void AppendToken(
const Ch* str,
SizeType len) {
1899 documentStack_.template Reserve<Ch>(1 + len * 2);
1900 *documentStack_.template PushUnsafe<Ch>() =
'/';
1901 for (
SizeType i = 0; i < len; i++) {
1902 if (str[i] ==
'~') {
1903 *documentStack_.template PushUnsafe<Ch>() =
'~';
1904 *documentStack_.template PushUnsafe<Ch>() =
'0';
1906 else if (str[i] ==
'/') {
1907 *documentStack_.template PushUnsafe<Ch>() =
'~';
1908 *documentStack_.template PushUnsafe<Ch>() =
'1';
1911 *documentStack_.template PushUnsafe<Ch>() = str[i];
1915 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, &schema); }
1917 RAPIDJSON_FORCEINLINE
void PopSchema() {
1918 Context* c = schemaStack_.template Pop<Context>(1);
1919 if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
1920 a->~HashCodeArray();
1921 StateAllocator::Free(a);
1926 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
1927 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
1928 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
1930 OutputHandler& CreateNullHandler() {
1931 return *(nullHandler_ =
static_cast<OutputHandler*
>(GetStateAllocator().Malloc(
sizeof(OutputHandler))));
1934 static const size_t kDefaultSchemaStackCapacity = 1024;
1935 static const size_t kDefaultDocumentStackCapacity = 256;
1936 const SchemaDocumentType* schemaDocument_;
1937 const SchemaType& root_;
1938 StateAllocator* stateAllocator_;
1939 StateAllocator* ownStateAllocator_;
1942 OutputHandler& outputHandler_;
1943 OutputHandler* nullHandler_;
1945 #if RAPIDJSON_SCHEMA_VERBOSE 1966 unsigned parseFlags,
1967 typename InputStream,
1968 typename SourceEncoding,
1969 typename SchemaDocumentType = SchemaDocument,
1973 typedef typename SchemaDocumentType::PointerType PointerType;
1974 typedef typename InputStream::Ch Ch;
1981 SchemaValidatingReader(InputStream& is,
const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
1983 template <
typename Handler>
1984 bool operator()(Handler& handler) {
1987 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
1989 isValid_ = validator.
IsValid();
1991 invalidSchemaPointer_ = PointerType();
1992 invalidSchemaKeyword_ = 0;
1993 invalidDocumentPointer_ = PointerType();
2001 return parseResult_;
2004 const ParseResult& GetParseResult()
const {
return parseResult_; }
2005 bool IsValid()
const {
return isValid_; }
2006 const PointerType& GetInvalidSchemaPointer()
const {
return invalidSchemaPointer_; }
2007 const Ch* GetInvalidSchemaKeyword()
const {
return invalidSchemaKeyword_; }
2008 const PointerType& GetInvalidDocumentPointer()
const {
return invalidDocumentPointer_; }
2012 const SchemaDocumentType& sd_;
2015 PointerType invalidSchemaPointer_;
2016 const Ch* invalidSchemaKeyword_;
2017 PointerType invalidDocumentPointer_;
2024 #endif // RAPIDJSON_SCHEMA_H_ RAPIDJSON_NAMESPACE_BEGIN typedef unsigned SizeType
Size type (for string lengths, array sizes, etc.)
Definition: rapidjson.h:380
#define RAPIDJSON_ASSERT(x)
Assertion.
Definition: rapidjson.h:402
#define RAPIDJSON_UINT64_C2(high32, low32)
Construct a 64-bit literal by a pair of 32-bit integer.
Definition: rapidjson.h:289
object
Definition: rapidjson.h:607
Default implementation of Handler.
Definition: fwd.h:85
PointerType GetInvalidDocumentPointer() const
Gets the JSON pointer pointed to the invalid value.
Definition: schema.h:1665
JSON schema document.
Definition: fwd.h:136
GenericSchemaDocument(const ValueType &document, IRemoteSchemaDocumentProviderType *remoteProvider=0, Allocator *allocator=0)
Constructor.
Definition: schema.h:1337
Definition: schema.h:1260
#define RAPIDJSON_NAMESPACE_END
provide custom rapidjson namespace (closing expression)
Definition: rapidjson.h:119
array
Definition: rapidjson.h:608
const Ch * GetInvalidSchemaKeyword() const
Gets the keyword of invalid schema.
Definition: schema.h:1660
~GenericSchemaValidator()
Destructor.
Definition: schema.h:1633
GenericPointer Append(const Token &token, Allocator *allocator=0) const
Append a token and return a new Pointer.
Definition: pointer.h:211
A type-unsafe stack for storing different types of data.
Definition: stack.h:36
SchemaValidatingReader(InputStream &is, const SchemaDocumentType &sd)
Constructor.
Definition: schema.h:1981
false
Definition: rapidjson.h:605
Regular expression engine with subset of ECMAscript grammar.
Definition: regex.h:113
Result of parsing (wraps ParseErrorCode)
Definition: error.h:106
void Reset()
Reset the internal states.
Definition: schema.h:1643
#define RAPIDJSON_NAMESPACE_BEGIN
provide custom rapidjson namespace (opening expression)
Definition: rapidjson.h:116
PointerType GetInvalidSchemaPointer() const
Gets the JSON pointer pointed to the invalid schema.
Definition: schema.h:1655
virtual bool IsValid() const
Checks whether the current state is valid.
Definition: schema.h:1652
const SchemaType & GetRoot() const
Get the root schema.
Definition: schema.h:1411
string
Definition: rapidjson.h:609
SAX-style JSON parser. Use Reader for UTF8 encoding and default allocator.
Definition: fwd.h:88
Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
Definition: fwd.h:126
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, OutputHandler &outputHandler, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor with output handler.
Definition: schema.h:1610
number
Definition: rapidjson.h:610
#define RAPIDJSON_NEW(x)
! customization point for global new
Definition: rapidjson.h:586
#define RAPIDJSON_DELETE(x)
! customization point for global delete
Definition: rapidjson.h:590
Definition: document.h:399
C-runtime library allocator.
Definition: allocators.h:62
A helper class for parsing with validation.
Definition: schema.h:1971
Represents an in-memory output stream.
Definition: fwd.h:59
true
Definition: rapidjson.h:606
~GenericSchemaDocument()
Destructor.
Definition: schema.h:1398
Type
Type of JSON value.
Definition: rapidjson.h:603
Default memory allocator used by the parser and DOM.
Definition: allocators.h:102
GenericSchemaValidator(const SchemaDocumentType &schemaDocument, StateAllocator *allocator=0, size_t schemaStackCapacity=kDefaultSchemaStackCapacity, size_t documentStackCapacity=kDefaultDocumentStackCapacity)
Constructor without output handler.
Definition: schema.h:1583
JSON Schema Validator.
Definition: fwd.h:145
null
Definition: rapidjson.h:604