398 typedef typename SchemaDocumentType::ValueType ValueType;
399 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
400 typedef typename SchemaDocumentType::PointerType PointerType;
401 typedef typename ValueType::EncodingType EncodingType;
402 typedef typename EncodingType::Ch Ch;
404 typedef Schema<SchemaDocumentType> SchemaType;
409 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator) :
410 allocator_(allocator),
411 uri_(schemaDocument->GetURI(), *allocator),
412 pointer_(p, allocator),
413 typeless_(schemaDocument->GetTypeless()),
417 type_((1 << kTotalSchemaType) - 1),
419 notValidatorIndex_(),
421 additionalPropertiesSchema_(),
422 patternProperties_(),
423 patternPropertyCount_(),
427 additionalProperties_(
true),
430 hasSchemaDependencies_(),
431 additionalItemsSchema_(),
437 additionalItems_(
true),
442 exclusiveMinimum_(
false),
443 exclusiveMaximum_(
false),
444 defaultValueLength_(0)
446 typedef typename ValueType::ConstValueIterator ConstValueIterator;
447 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
449 if (!value.IsObject())
452 if (
const ValueType* v = GetMember(value, GetTypeString())) {
456 else if (v->IsArray())
457 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
461 if (
const ValueType* v = GetMember(value, GetEnumString()))
462 if (v->IsArray() && v->Size() > 0) {
463 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
464 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
466 char buffer[256u + 24];
468 EnumHasherType h(&hasherAllocator, 256);
470 enum_[enumCount_++] = h.GetHashCode();
474 if (schemaDocument) {
475 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
476 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
477 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
480 if (
const ValueType* v = GetMember(value, GetNotString())) {
481 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document);
482 notValidatorIndex_ = validatorCount_;
488 const ValueType* properties = GetMember(value, GetPropertiesString());
489 const ValueType* required = GetMember(value, GetRequiredString());
490 const ValueType* dependencies = GetMember(value, GetDependenciesString());
495 if (properties && properties->IsObject())
496 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
497 AddUniqueElement(allProperties, itr->name);
499 if (required && required->IsArray())
500 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
502 AddUniqueElement(allProperties, *itr);
504 if (dependencies && dependencies->IsObject())
505 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
506 AddUniqueElement(allProperties, itr->name);
507 if (itr->value.IsArray())
508 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
510 AddUniqueElement(allProperties, *i);
513 if (allProperties.Size() > 0) {
514 propertyCount_ = allProperties.Size();
515 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
516 for (
SizeType i = 0; i < propertyCount_; i++) {
517 new (&properties_[i]) Property();
518 properties_[i].name = allProperties[i];
519 properties_[i].schema = typeless_;
524 if (properties && properties->IsObject()) {
525 PointerType q = p.Append(GetPropertiesString(), allocator_);
526 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
528 if (FindPropertyIndex(itr->name, &index))
529 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
533 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
534 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
535 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
536 patternPropertyCount_ = 0;
538 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
539 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
540 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
541 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
542 patternPropertyCount_++;
546 if (required && required->IsArray())
547 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
548 if (itr->IsString()) {
550 if (FindPropertyIndex(*itr, &index)) {
551 properties_[index].required =
true;
556 if (dependencies && dependencies->IsObject()) {
557 PointerType q = p.Append(GetDependenciesString(), allocator_);
558 hasDependencies_ =
true;
559 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
561 if (FindPropertyIndex(itr->name, &sourceIndex)) {
562 if (itr->value.IsArray()) {
563 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
564 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
565 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
567 if (FindPropertyIndex(*targetItr, &targetIndex))
568 properties_[sourceIndex].dependencies[targetIndex] =
true;
571 else if (itr->value.IsObject()) {
572 hasSchemaDependencies_ =
true;
573 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
574 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
581 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
583 additionalProperties_ = v->GetBool();
584 else if (v->IsObject())
585 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
588 AssignIfExist(minProperties_, value, GetMinPropertiesString());
589 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
592 if (
const ValueType* v = GetMember(value, GetItemsString())) {
593 PointerType q = p.Append(GetItemsString(), allocator_);
595 schemaDocument->CreateSchema(&itemsList_, q, *v, document);
596 else if (v->IsArray()) {
597 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
599 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
600 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
604 AssignIfExist(minItems_, value, GetMinItemsString());
605 AssignIfExist(maxItems_, value, GetMaxItemsString());
607 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
609 additionalItems_ = v->GetBool();
610 else if (v->IsObject())
611 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
614 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
617 AssignIfExist(minLength_, value, GetMinLengthString());
618 AssignIfExist(maxLength_, value, GetMaxLengthString());
620 if (
const ValueType* v = GetMember(value, GetPatternString()))
621 pattern_ = CreatePattern(*v);
624 if (
const ValueType* v = GetMember(value, GetMinimumString()))
626 minimum_.CopyFrom(*v, *allocator_);
628 if (
const ValueType* v = GetMember(value, GetMaximumString()))
630 maximum_.CopyFrom(*v, *allocator_);
632 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
633 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
635 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
636 if (v->IsNumber() && v->GetDouble() > 0.0)
637 multipleOf_.CopyFrom(*v, *allocator_);
640 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
642 defaultValueLength_ = v->GetStringLength();
647 AllocatorType::Free(enum_);
649 for (
SizeType i = 0; i < propertyCount_; i++)
650 properties_[i].~Property();
651 AllocatorType::Free(properties_);
653 if (patternProperties_) {
654 for (
SizeType i = 0; i < patternPropertyCount_; i++)
655 patternProperties_[i].~PatternProperty();
656 AllocatorType::Free(patternProperties_);
658 AllocatorType::Free(itemsTuple_);
659#if RAPIDJSON_SCHEMA_HAS_REGEX
661 pattern_->~BESRegexType();
662 AllocatorType::Free(pattern_);
667 const SValue& GetURI()
const {
671 const PointerType& GetPointer()
const {
675 bool BeginValue(Context& context)
const {
676 if (context.inArray) {
678 context.valueUniqueness =
true;
681 context.valueSchema = itemsList_;
682 else if (itemsTuple_) {
683 if (context.arrayElementIndex < itemsTupleCount_)
684 context.valueSchema = itemsTuple_[context.arrayElementIndex];
685 else if (additionalItemsSchema_)
686 context.valueSchema = additionalItemsSchema_;
687 else if (additionalItems_)
688 context.valueSchema = typeless_;
690 context.error_handler.DisallowedItem(context.arrayElementIndex);
691 RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
695 context.valueSchema = typeless_;
697 context.arrayElementIndex++;
702 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
703 if (context.patternPropertiesValidatorCount > 0) {
704 bool otherValid =
false;
705 SizeType count = context.patternPropertiesValidatorCount;
706 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
707 otherValid = context.patternPropertiesValidators[--count]->IsValid();
709 bool patternValid =
true;
710 for (
SizeType i = 0; i < count; i++)
711 if (!context.patternPropertiesValidators[i]->IsValid()) {
712 patternValid =
false;
716 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
718 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
719 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
722 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
723 if (!patternValid || !otherValid) {
724 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
725 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
728 else if (!patternValid && !otherValid) {
729 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
730 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
735 const uint64_t h = context.factory.GetHashCode(context.hasher);
736 for (
SizeType i = 0; i < enumCount_; i++)
739 context.error_handler.DisallowedValue();
740 RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
745 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
746 if (!context.validators[i]->IsValid()) {
747 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
748 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
751 if (anyOf_.schemas) {
752 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
753 if (context.validators[i]->IsValid())
755 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
756 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
760 if (oneOf_.schemas) {
761 bool oneValid =
false;
762 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
763 if (context.validators[i]->IsValid()) {
765 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
766 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
771 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
772 RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
776 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777 context.error_handler.Disallowed();
778 RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
784 bool Null(Context& context)
const {
785 if (!(type_ & (1 << kNullSchemaType))) {
786 DisallowedType(context, GetNullString());
787 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
789 return CreateParallelValidator(context);
792 bool Bool(Context& context,
bool)
const {
793 if (!(type_ & (1 << kBooleanSchemaType))) {
794 DisallowedType(context, GetBooleanString());
795 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
797 return CreateParallelValidator(context);
800 bool Int(Context& context,
int i)
const {
801 if (!CheckInt(context, i))
803 return CreateParallelValidator(context);
806 bool Uint(Context& context,
unsigned u)
const {
807 if (!CheckUint(context, u))
809 return CreateParallelValidator(context);
812 bool Int64(Context& context, int64_t i)
const {
813 if (!CheckInt(context, i))
815 return CreateParallelValidator(context);
818 bool Uint64(Context& context, uint64_t u)
const {
819 if (!CheckUint(context, u))
821 return CreateParallelValidator(context);
824 bool Double(Context& context,
double d)
const {
825 if (!(type_ & (1 << kNumberSchemaType))) {
826 DisallowedType(context, GetNumberString());
827 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
830 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
833 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
836 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
839 return CreateParallelValidator(context);
842 bool String(Context& context,
const Ch* str,
SizeType length,
bool)
const {
843 if (!(type_ & (1 << kStringSchemaType))) {
844 DisallowedType(context, GetStringString());
845 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
848 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
850 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
851 if (count < minLength_) {
852 context.error_handler.TooShort(str, length, minLength_);
853 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
855 if (count > maxLength_) {
856 context.error_handler.TooLong(str, length, maxLength_);
857 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
862 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863 context.error_handler.DoesNotMatch(str, length);
864 RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
867 return CreateParallelValidator(context);
870 bool StartObject(Context& context)
const {
871 if (!(type_ & (1 << kObjectSchemaType))) {
872 DisallowedType(context, GetObjectString());
873 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
876 if (hasDependencies_ || hasRequired_) {
877 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
878 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
881 if (patternProperties_) {
882 SizeType count = patternPropertyCount_ + 1;
883 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
884 context.patternPropertiesSchemaCount = 0;
885 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
888 return CreateParallelValidator(context);
891 bool Key(Context& context,
const Ch* str,
SizeType len,
bool)
const {
892 if (patternProperties_) {
893 context.patternPropertiesSchemaCount = 0;
894 for (
SizeType i = 0; i < patternPropertyCount_; i++)
895 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
896 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
897 context.valueSchema = typeless_;
902 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
903 if (context.patternPropertiesSchemaCount > 0) {
904 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
905 context.valueSchema = typeless_;
906 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
909 context.valueSchema = properties_[index].schema;
911 if (context.propertyExist)
912 context.propertyExist[index] =
true;
917 if (additionalPropertiesSchema_) {
918 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
919 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
920 context.valueSchema = typeless_;
921 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
924 context.valueSchema = additionalPropertiesSchema_;
927 else if (additionalProperties_) {
928 context.valueSchema = typeless_;
932 if (context.patternPropertiesSchemaCount == 0) {
933 context.error_handler.DisallowedProperty(str, len);
934 RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
940 bool EndObject(Context& context,
SizeType memberCount)
const {
942 context.error_handler.StartMissingProperties();
943 for (
SizeType index = 0; index < propertyCount_; index++)
944 if (properties_[index].required && !context.propertyExist[index])
945 if (properties_[index].schema->defaultValueLength_ == 0 )
946 context.error_handler.AddMissingProperty(properties_[index].name);
947 if (context.error_handler.EndMissingProperties())
948 RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
951 if (memberCount < minProperties_) {
952 context.error_handler.TooFewProperties(memberCount, minProperties_);
953 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
956 if (memberCount > maxProperties_) {
957 context.error_handler.TooManyProperties(memberCount, maxProperties_);
958 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
961 if (hasDependencies_) {
962 context.error_handler.StartDependencyErrors();
963 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
964 const Property& source = properties_[sourceIndex];
965 if (context.propertyExist[sourceIndex]) {
966 if (source.dependencies) {
967 context.error_handler.StartMissingDependentProperties();
968 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
969 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
970 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
971 context.error_handler.EndMissingDependentProperties(source.name);
973 else if (source.dependenciesSchema) {
974 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
975 if (!dependenciesValidator->IsValid())
976 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
980 if (context.error_handler.EndDependencyErrors())
981 RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
987 bool StartArray(Context& context)
const {
988 if (!(type_ & (1 << kArraySchemaType))) {
989 DisallowedType(context, GetArrayString());
990 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
993 context.arrayElementIndex = 0;
994 context.inArray =
true;
996 return CreateParallelValidator(context);
999 bool EndArray(Context& context,
SizeType elementCount)
const {
1000 context.inArray =
false;
1002 if (elementCount < minItems_) {
1003 context.error_handler.TooFewItems(elementCount, minItems_);
1004 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1007 if (elementCount > maxItems_) {
1008 context.error_handler.TooManyItems(elementCount, maxItems_);
1009 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1016#define RAPIDJSON_STRING_(name, ...) \
1017 static const ValueType& Get##name##String() {\
1018 static const Ch s[] = { __VA_ARGS__, '\0' };\
1019 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1023 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1024 RAPIDJSON_STRING_(Boolean,
'b',
'o',
'o',
'l',
'e',
'a',
'n')
1025 RAPIDJSON_STRING_(Object,
'o',
'b',
'j',
'e',
'c',
't')
1026 RAPIDJSON_STRING_(Array,
'a',
'r',
'r',
'a',
'y')
1027 RAPIDJSON_STRING_(String,
's',
't',
'r',
'i',
'n',
'g')
1028 RAPIDJSON_STRING_(Number,
'n',
'u',
'm',
'b',
'e',
'r')
1029 RAPIDJSON_STRING_(Integer,
'i',
'n',
't',
'e',
'g',
'e',
'r')
1030 RAPIDJSON_STRING_(
Type,
't',
'y',
'p',
'e')
1031 RAPIDJSON_STRING_(Enum,
'e',
'n',
'u',
'm')
1032 RAPIDJSON_STRING_(AllOf,
'a',
'l',
'l',
'O',
'f')
1033 RAPIDJSON_STRING_(AnyOf,
'a',
'n',
'y',
'O',
'f')
1034 RAPIDJSON_STRING_(OneOf,
'o',
'n',
'e',
'O',
'f')
1035 RAPIDJSON_STRING_(Not,
'n',
'o',
't')
1036 RAPIDJSON_STRING_(Properties,
'p',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1037 RAPIDJSON_STRING_(Required,
'r',
'e',
'q',
'u',
'i',
'r',
'e',
'd')
1038 RAPIDJSON_STRING_(Dependencies,
'd',
'e',
'p',
'e',
'n',
'd',
'e',
'n',
'c',
'i',
'e',
's')
1039 RAPIDJSON_STRING_(PatternProperties,
'p',
'a',
't',
't',
'e',
'r',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1040 RAPIDJSON_STRING_(AdditionalProperties,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1041 RAPIDJSON_STRING_(MinProperties,
'm',
'i',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1042 RAPIDJSON_STRING_(MaxProperties,
'm',
'a',
'x',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1043 RAPIDJSON_STRING_(Items,
'i',
't',
'e',
'm',
's')
1044 RAPIDJSON_STRING_(MinItems,
'm',
'i',
'n',
'I',
't',
'e',
'm',
's')
1045 RAPIDJSON_STRING_(MaxItems,
'm',
'a',
'x',
'I',
't',
'e',
'm',
's')
1046 RAPIDJSON_STRING_(AdditionalItems,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'I',
't',
'e',
'm',
's')
1047 RAPIDJSON_STRING_(UniqueItems,
'u',
'n',
'i',
'q',
'u',
'e',
'I',
't',
'e',
'm',
's')
1048 RAPIDJSON_STRING_(MinLength,
'm',
'i',
'n',
'L',
'e',
'n',
'g',
't',
'h')
1049 RAPIDJSON_STRING_(MaxLength,
'm',
'a',
'x',
'L',
'e',
'n',
'g',
't',
'h')
1050 RAPIDJSON_STRING_(Pattern,
'p',
'a',
't',
't',
'e',
'r',
'n')
1051 RAPIDJSON_STRING_(Minimum,
'm',
'i',
'n',
'i',
'm',
'u',
'm')
1052 RAPIDJSON_STRING_(Maximum,
'm',
'a',
'x',
'i',
'm',
'u',
'm')
1053 RAPIDJSON_STRING_(ExclusiveMinimum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'i',
'n',
'i',
'm',
'u',
'm')
1054 RAPIDJSON_STRING_(ExclusiveMaximum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'a',
'x',
'i',
'm',
'u',
'm')
1055 RAPIDJSON_STRING_(MultipleOf,
'm',
'u',
'l',
't',
'i',
'p',
'l',
'e',
'O',
'f')
1056 RAPIDJSON_STRING_(DefaultValue,
'd',
'e',
'f',
'a',
'u',
'l',
't')
1058#undef RAPIDJSON_STRING_
1061 enum SchemaValueType {
1072#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1074#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1075 typedef std::basic_regex<Ch> BESRegexType;
1077 typedef char BESRegexType;
1080 struct SchemaArray {
1081 SchemaArray() : schemas(), count() {}
1082 ~SchemaArray() { AllocatorType::Free(schemas); }
1083 const SchemaType** schemas;
1088 template <
typename V1,
typename V2>
1089 void AddUniqueElement(V1& a,
const V2& v) {
1090 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1093 V1 c(v, *allocator_);
1094 a.PushBack(c, *allocator_);
1097 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1098 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1099 return itr != value.MemberEnd() ? &(itr->value) : 0;
1102 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1103 if (
const ValueType* v = GetMember(value, name))
1108 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
1109 if (
const ValueType* v = GetMember(value, name))
1110 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1111 out =
static_cast<SizeType>(v->GetUint64());
1114 void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1115 if (
const ValueType* v = GetMember(value, name)) {
1116 if (v->IsArray() && v->Size() > 0) {
1117 PointerType q = p.Append(name, allocator_);
1118 out.count = v->Size();
1119 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1120 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
1121 for (
SizeType i = 0; i < out.count; i++)
1122 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
1123 out.begin = validatorCount_;
1124 validatorCount_ += out.count;
1129#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1130 template <
typename ValueType>
1131 BESRegexType* CreatePattern(
const ValueType& value) {
1132 if (value.IsString()) {
1133 BESRegexType* r =
new (allocator_->Malloc(
sizeof(BESRegexType))) BESRegexType(value.GetString(), allocator_);
1134 if (!r->IsValid()) {
1136 AllocatorType::Free(r);
1144 static bool IsPatternMatch(
const BESRegexType* pattern,
const Ch *str,
SizeType) {
1146 return rs.Search(str);
1148#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1149 template <
typename ValueType>
1150 BESRegexType* CreatePattern(
const ValueType& value) {
1151 if (value.IsString()) {
1152 BESRegexType *r =
static_cast<BESRegexType*
>(allocator_->Malloc(
sizeof(BESRegexType)));
1154 return new (r) BESRegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1156 catch (
const std::regex_error&) {
1157 AllocatorType::Free(r);
1163 static bool IsPatternMatch(
const BESRegexType* pattern,
const Ch *str,
SizeType length) {
1164 std::match_results<const Ch*> r;
1165 return std::regex_search(str, str + length, r, *pattern);
1168 template <
typename ValueType>
1169 BESRegexType* CreatePattern(
const ValueType&) {
return 0; }
1171 static bool IsPatternMatch(
const BESRegexType*,
const Ch *,
SizeType) {
return true; }
1174 void AddType(
const ValueType& type) {
1175 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1176 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1177 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1178 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1179 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1180 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1181 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1184 bool CreateParallelValidator(Context& context)
const {
1185 if (enum_ || context.arrayUniqueness)
1186 context.hasher = context.factory.CreateHasher();
1188 if (validatorCount_) {
1191 context.validatorCount = validatorCount_;
1194 CreateSchemaValidators(context, allOf_);
1197 CreateSchemaValidators(context, anyOf_);
1200 CreateSchemaValidators(context, oneOf_);
1203 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
1205 if (hasSchemaDependencies_) {
1206 for (
SizeType i = 0; i < propertyCount_; i++)
1207 if (properties_[i].dependenciesSchema)
1208 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
1215 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas)
const {
1216 for (
SizeType i = 0; i < schemas.count; i++)
1217 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
1221 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1222 SizeType len = name.GetStringLength();
1223 const Ch* str = name.GetString();
1224 for (
SizeType index = 0; index < propertyCount_; index++)
1225 if (properties_[index].name.GetStringLength() == len &&
1226 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1234 bool CheckInt(Context& context, int64_t i)
const {
1235 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1236 DisallowedType(context, GetIntegerString());
1237 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1240 if (!minimum_.IsNull()) {
1241 if (minimum_.IsInt64()) {
1242 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1243 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1244 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1247 else if (minimum_.IsUint64()) {
1248 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1249 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1251 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1255 if (!maximum_.IsNull()) {
1256 if (maximum_.IsInt64()) {
1257 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1258 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1259 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1262 else if (maximum_.IsUint64()) { }
1264 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1268 if (!multipleOf_.IsNull()) {
1269 if (multipleOf_.IsUint64()) {
1270 if (
static_cast<uint64_t
>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1271 context.error_handler.NotMultipleOf(i, multipleOf_);
1272 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1275 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1282 bool CheckUint(Context& context, uint64_t i)
const {
1283 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1284 DisallowedType(context, GetIntegerString());
1285 RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1288 if (!minimum_.IsNull()) {
1289 if (minimum_.IsUint64()) {
1290 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1291 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1292 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1295 else if (minimum_.IsInt64())
1297 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1301 if (!maximum_.IsNull()) {
1302 if (maximum_.IsUint64()) {
1303 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1304 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1305 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1308 else if (maximum_.IsInt64()) {
1309 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1310 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1312 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1316 if (!multipleOf_.IsNull()) {
1317 if (multipleOf_.IsUint64()) {
1318 if (i % multipleOf_.GetUint64() != 0) {
1319 context.error_handler.NotMultipleOf(i, multipleOf_);
1320 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1323 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1330 bool CheckDoubleMinimum(Context& context,
double d)
const {
1331 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1332 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1333 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1338 bool CheckDoubleMaximum(Context& context,
double d)
const {
1339 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1340 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1341 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1346 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1347 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1348 double q = std::floor(a / b);
1349 double r = a - q * b;
1351 context.error_handler.NotMultipleOf(d, multipleOf_);
1352 RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1357 void DisallowedType(Context& context,
const ValueType& actualType)
const {
1358 ErrorHandler& eh = context.error_handler;
1359 eh.StartDisallowedType();
1361 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1362 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1363 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1364 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1365 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1367 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1368 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1370 eh.EndDisallowedType(actualType);
1374 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1375 ~Property() { AllocatorType::Free(dependencies); }
1377 const SchemaType* schema;
1378 const SchemaType* dependenciesSchema;
1379 SizeType dependenciesValidatorIndex;
1384 struct PatternProperty {
1385 PatternProperty() : schema(), pattern() {}
1386 ~PatternProperty() {
1388 pattern->~BESRegexType();
1389 AllocatorType::Free(pattern);
1392 const SchemaType* schema;
1393 BESRegexType* pattern;
1396 AllocatorType* allocator_;
1398 PointerType pointer_;
1399 const SchemaType* typeless_;
1405 const SchemaType* not_;
1410 Property* properties_;
1411 const SchemaType* additionalPropertiesSchema_;
1412 PatternProperty* patternProperties_;
1417 bool additionalProperties_;
1418 bool hasDependencies_;
1420 bool hasSchemaDependencies_;
1422 const SchemaType* additionalItemsSchema_;
1423 const SchemaType* itemsList_;
1424 const SchemaType** itemsTuple_;
1428 bool additionalItems_;
1431 BESRegexType* pattern_;
1438 bool exclusiveMinimum_;
1439 bool exclusiveMaximum_;
1769 typedef typename SchemaDocumentType::SchemaType SchemaType;
1770 typedef typename SchemaDocumentType::PointerType PointerType;
1771 typedef typename SchemaType::EncodingType EncodingType;
1772 typedef typename SchemaType::SValue SValue;
1773 typedef typename EncodingType::Ch Ch;
1785 const SchemaDocumentType& schemaDocument,
1786 StateAllocator* allocator = 0,
1787 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1788 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1790 schemaDocument_(&schemaDocument),
1791 root_(schemaDocument.GetRoot()),
1792 stateAllocator_(allocator),
1793 ownStateAllocator_(0),
1794 schemaStack_(allocator, schemaStackCapacity),
1795 documentStack_(allocator, documentStackCapacity),
1799 missingDependents_(),
1801#if RAPIDJSON_SCHEMA_VERBOSE
1815 const SchemaDocumentType& schemaDocument,
1816 OutputHandler& outputHandler,
1817 StateAllocator* allocator = 0,
1818 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
1819 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
1821 schemaDocument_(&schemaDocument),
1822 root_(schemaDocument.GetRoot()),
1823 stateAllocator_(allocator),
1824 ownStateAllocator_(0),
1825 schemaStack_(allocator, schemaStackCapacity),
1826 documentStack_(allocator, documentStackCapacity),
1827 outputHandler_(&outputHandler),
1830 missingDependents_(),
1832#if RAPIDJSON_SCHEMA_VERBOSE
1846 while (!schemaStack_.Empty())
1848 documentStack_.Clear();
1850 currentError_.SetNull();
1851 missingDependents_.SetNull();
1861 const ValueType&
GetError()
const {
return error_; }
1865 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
1870 return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
1875 if (documentStack_.Empty()) {
1876 return PointerType();
1879 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(Ch));
1883 void NotMultipleOf(int64_t actual,
const SValue& expected) {
1884 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1886 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
1887 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1889 void NotMultipleOf(
double actual,
const SValue& expected) {
1890 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1892 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
1893 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1894 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1896 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
1897 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1898 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1900 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
1901 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1902 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1904 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
1905 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1906 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1908 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
1909 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1910 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1912 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
1913 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1914 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1918 AddNumberError(SchemaType::GetMaxLengthString(),
1919 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1922 AddNumberError(SchemaType::GetMinLengthString(),
1923 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1925 void DoesNotMatch(
const Ch* str,
SizeType length) {
1926 currentError_.SetObject();
1927 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
1928 AddCurrentError(SchemaType::GetPatternString());
1931 void DisallowedItem(
SizeType index) {
1932 currentError_.SetObject();
1933 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
1934 AddCurrentError(SchemaType::GetAdditionalItemsString(),
true);
1937 AddNumberError(SchemaType::GetMinItemsString(),
1938 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1941 AddNumberError(SchemaType::GetMaxItemsString(),
1942 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1946 duplicates.PushBack(index1, GetStateAllocator());
1947 duplicates.PushBack(index2, GetStateAllocator());
1948 currentError_.SetObject();
1949 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1950 AddCurrentError(SchemaType::GetUniqueItemsString(),
true);
1954 AddNumberError(SchemaType::GetMaxPropertiesString(),
1955 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1958 AddNumberError(SchemaType::GetMinPropertiesString(),
1959 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1961 void StartMissingProperties() {
1962 currentError_.SetArray();
1964 void AddMissingProperty(
const SValue& name) {
1965 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1967 bool EndMissingProperties() {
1968 if (currentError_.Empty())
1971 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1972 currentError_ = error;
1973 AddCurrentError(SchemaType::GetRequiredString());
1976 void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) {
1977 for (
SizeType i = 0; i < count; ++i)
1980 void DisallowedProperty(
const Ch* name,
SizeType length) {
1981 currentError_.SetObject();
1982 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
1983 AddCurrentError(SchemaType::GetAdditionalPropertiesString(),
true);
1986 void StartDependencyErrors() {
1987 currentError_.SetObject();
1989 void StartMissingDependentProperties() {
1990 missingDependents_.SetArray();
1992 void AddMissingDependentProperty(
const SValue& targetName) {
1993 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1995 void EndMissingDependentProperties(
const SValue& sourceName) {
1996 if (!missingDependents_.Empty())
1997 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
1998 missingDependents_, GetStateAllocator());
2000 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2001 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2004 bool EndDependencyErrors() {
2005 if (currentError_.ObjectEmpty())
2008 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2009 currentError_ = error;
2010 AddCurrentError(SchemaType::GetDependenciesString());
2014 void DisallowedValue() {
2015 currentError_.SetObject();
2016 AddCurrentError(SchemaType::GetEnumString());
2018 void StartDisallowedType() {
2019 currentError_.SetArray();
2021 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2022 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2024 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2026 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2027 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2028 currentError_ = error;
2029 AddCurrentError(SchemaType::GetTypeString());
2031 void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) {
2032 for (
SizeType i = 0; i < count; ++i) {
2036 void NoneOf(ISchemaValidator** subvalidators,
SizeType count) {
2037 AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
2039 void NotOneOf(ISchemaValidator** subvalidators,
SizeType count) {
2040 AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
2043 currentError_.SetObject();
2044 AddCurrentError(SchemaType::GetNotString());
2047#define RAPIDJSON_STRING_(name, ...) \
2048 static const StringRefType& Get##name##String() {\
2049 static const Ch s[] = { __VA_ARGS__, '\0' };\
2050 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2054 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2055 RAPIDJSON_STRING_(SchemaRef,
's',
'c',
'h',
'e',
'm',
'a',
'R',
'e',
'f')
2056 RAPIDJSON_STRING_(Expected,
'e',
'x',
'p',
'e',
'c',
't',
'e',
'd')
2057 RAPIDJSON_STRING_(Actual,
'a',
'c',
't',
'u',
'a',
'l')
2058 RAPIDJSON_STRING_(Disallowed,
'd',
'i',
's',
'a',
'l',
'l',
'o',
'w',
'e',
'd')
2059 RAPIDJSON_STRING_(Missing,
'm',
'i',
's',
's',
'i',
'n',
'g')
2060 RAPIDJSON_STRING_(Errors,
'e',
'r',
'r',
'o',
'r',
's')
2061 RAPIDJSON_STRING_(Duplicates,
'd',
'u',
'p',
'l',
'i',
'c',
'a',
't',
'e',
's')
2063#undef RAPIDJSON_STRING_
2065#if RAPIDJSON_SCHEMA_VERBOSE
2066#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2067RAPIDJSON_MULTILINEMACRO_BEGIN\
2068 *documentStack_.template Push<Ch>() = '\0';\
2069 documentStack_.template Pop<Ch>(1);\
2070 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2071RAPIDJSON_MULTILINEMACRO_END
2073#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2076#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2077 if (!valid_) return false; \
2078 if (!BeginValue() || !CurrentSchema().method arg1) {\
2079 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2080 return valid_ = false;\
2083#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2084 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2085 if (context->hasher)\
2086 static_cast<HasherType*>(context->hasher)->method arg2;\
2087 if (context->validators)\
2088 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2089 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2090 if (context->patternPropertiesValidators)\
2091 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2092 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2095#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2096 return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
2098#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2099 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2100 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2101 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2103 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2104 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2105 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2106 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2107 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2108 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2109 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2110 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
2111 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2112 bool String(
const Ch* str,
SizeType length,
bool copy)
2113 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2115 bool StartObject() {
2116 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2117 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2118 return valid_ = !outputHandler_ || outputHandler_->StartObject();
2121 bool Key(
const Ch* str,
SizeType len,
bool copy) {
2122 if (!valid_)
return false;
2123 AppendToken(str, len);
2124 if (!CurrentSchema().Key(CurrentContext(), str, len, copy))
return valid_ =
false;
2125 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2126 return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2129 bool EndObject(
SizeType memberCount) {
2130 if (!valid_)
return false;
2131 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2132 if (!CurrentSchema().EndObject(CurrentContext(), memberCount))
return valid_ =
false;
2133 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2137 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2138 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2139 return valid_ = !outputHandler_ || outputHandler_->StartArray();
2142 bool EndArray(
SizeType elementCount) {
2143 if (!valid_)
return false;
2144 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2145 if (!CurrentSchema().EndArray(CurrentContext(), elementCount))
return valid_ =
false;
2146 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2149#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2150#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2151#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2152#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2155 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root) {
2157#
if RAPIDJSON_SCHEMA_VERBOSE
2160 &GetStateAllocator());
2163 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2166 StateAllocator::Free(v);
2169 virtual void* CreateHasher() {
2170 return new (GetStateAllocator().Malloc(
sizeof(HasherType))) HasherType(&GetStateAllocator());
2173 virtual uint64_t GetHashCode(
void* hasher) {
2174 return static_cast<HasherType*
>(hasher)->GetHashCode();
2177 virtual void DestroryHasher(
void* hasher) {
2178 HasherType* h =
static_cast<HasherType*
>(hasher);
2180 StateAllocator::Free(h);
2183 virtual void* MallocState(
size_t size) {
2184 return GetStateAllocator().Malloc(size);
2187 virtual void FreeState(
void* p) {
2188 StateAllocator::Free(p);
2192 typedef typename SchemaType::Context Context;
2193 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2194 typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2197 const SchemaDocumentType& schemaDocument,
2198 const SchemaType& root,
2199 const char* basePath,
size_t basePathSize,
2200#
if RAPIDJSON_SCHEMA_VERBOSE
2203 StateAllocator* allocator = 0,
2204 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2205 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2207 schemaDocument_(&schemaDocument),
2209 stateAllocator_(allocator),
2210 ownStateAllocator_(0),
2211 schemaStack_(allocator, schemaStackCapacity),
2212 documentStack_(allocator, documentStackCapacity),
2216 missingDependents_(),
2218#if RAPIDJSON_SCHEMA_VERBOSE
2222 if (basePath && basePathSize)
2223 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2226 StateAllocator& GetStateAllocator() {
2227 if (!stateAllocator_)
2228 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2229 return *stateAllocator_;
2233 if (schemaStack_.Empty())
2236 if (CurrentContext().inArray)
2237 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
2239 if (!CurrentSchema().BeginValue(CurrentContext()))
2242 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2243 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2244 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2245 bool valueUniqueness = CurrentContext().valueUniqueness;
2247 PushSchema(*CurrentContext().valueSchema);
2250 CurrentContext().objectPatternValidatorType = patternValidatorType;
2251 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2252 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2253 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
2254 for (
SizeType i = 0; i < count; i++)
2255 va[validatorCount++] = CreateSchemaValidator(*sa[i]);
2258 CurrentContext().arrayUniqueness = valueUniqueness;
2264 if (!CurrentSchema().EndValue(CurrentContext()))
2267#if RAPIDJSON_SCHEMA_VERBOSE
2268 GenericStringBuffer<EncodingType> sb;
2269 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2271 *documentStack_.template Push<Ch>() =
'\0';
2272 documentStack_.template Pop<Ch>(1);
2273 internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
2276 uint64_t h = CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(CurrentContext().hasher)->GetHashCode() : 0;
2280 if (!schemaStack_.Empty()) {
2281 Context& context = CurrentContext();
2282 if (context.valueUniqueness) {
2283 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
2285 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
2287 if (itr->GetUint64() == h) {
2288 DuplicateItems(
static_cast<SizeType>(itr - a->Begin()), a->Size());
2289 RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
2291 a->PushBack(h, GetStateAllocator());
2296 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
2302 void AppendToken(
const Ch* str,
SizeType len) {
2303 documentStack_.template Reserve<Ch>(1 + len * 2);
2304 *documentStack_.template PushUnsafe<Ch>() =
'/';
2305 for (
SizeType i = 0; i < len; i++) {
2306 if (str[i] ==
'~') {
2307 *documentStack_.template PushUnsafe<Ch>() =
'~';
2308 *documentStack_.template PushUnsafe<Ch>() =
'0';
2310 else if (str[i] ==
'/') {
2311 *documentStack_.template PushUnsafe<Ch>() =
'~';
2312 *documentStack_.template PushUnsafe<Ch>() =
'1';
2315 *documentStack_.template PushUnsafe<Ch>() = str[i];
2319 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema); }
2321 RAPIDJSON_FORCEINLINE
void PopSchema() {
2322 Context* c = schemaStack_.template Pop<Context>(1);
2323 if (HashCodeArray* a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
2324 a->~HashCodeArray();
2325 StateAllocator::Free(a);
2330 void AddErrorLocation(ValueType& result,
bool parent) {
2331 GenericStringBuffer<EncodingType> sb;
2333 ((parent && instancePointer.GetTokenCount() > 0)
2334 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2335 : instancePointer).StringifyUriFragment(sb);
2336 ValueType instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
2337 GetStateAllocator());
2338 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2340 memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
2341 CurrentSchema().GetURI().GetString(),
2342 CurrentSchema().GetURI().GetStringLength() *
sizeof(Ch));
2344 ValueType schemaRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
2345 GetStateAllocator());
2346 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2349 void AddError(ValueType& keyword, ValueType& error) {
2351 if (member == error_.MemberEnd())
2352 error_.AddMember(keyword, error, GetStateAllocator());
2354 if (member->value.IsObject()) {
2356 errors.PushBack(member->value, GetStateAllocator());
2357 member->value = errors;
2359 member->value.PushBack(error, GetStateAllocator());
2363 void AddCurrentError(
const typename SchemaType::ValueType& keyword,
bool parent =
false) {
2364 AddErrorLocation(currentError_, parent);
2365 AddError(ValueType(keyword, GetStateAllocator(),
false).Move(), currentError_);
2368 void MergeError(ValueType& other) {
2370 AddError(it->name, it->value);
2374 void AddNumberError(
const typename SchemaType::ValueType& keyword, ValueType& actual,
const SValue& expected,
2375 const typename SchemaType::ValueType& (*exclusive)() = 0) {
2376 currentError_.SetObject();
2377 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2378 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2380 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
2381 AddCurrentError(keyword);
2384 void AddErrorArray(
const typename SchemaType::ValueType& keyword,
2385 ISchemaValidator** subvalidators,
SizeType count) {
2387 for (
SizeType i = 0; i < count; ++i)
2388 errors.PushBack(
static_cast<GenericSchemaValidator*
>(subvalidators[i])->GetError(), GetStateAllocator());
2389 currentError_.SetObject();
2390 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2391 AddCurrentError(keyword);
2394 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
2395 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
2396 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
2398 static const size_t kDefaultSchemaStackCapacity = 1024;
2399 static const size_t kDefaultDocumentStackCapacity = 256;
2400 const SchemaDocumentType* schemaDocument_;
2401 const SchemaType& root_;
2402 StateAllocator* stateAllocator_;
2403 StateAllocator* ownStateAllocator_;
2404 internal::Stack<StateAllocator> schemaStack_;
2405 internal::Stack<StateAllocator> documentStack_;
2406 OutputHandler* outputHandler_;
2408 ValueType currentError_;
2409 ValueType missingDependents_;
2411#if RAPIDJSON_SCHEMA_VERBOSE