521 typedef typename SchemaDocumentType::ValueType ValueType;
522 typedef typename SchemaDocumentType::AllocatorType AllocatorType;
523 typedef typename SchemaDocumentType::PointerType PointerType;
524 typedef typename ValueType::EncodingType EncodingType;
525 typedef typename EncodingType::Ch Ch;
527 typedef Schema<SchemaDocumentType> SchemaType;
533 Schema(SchemaDocumentType* schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& document, AllocatorType* allocator,
const UriType&
id = UriType()) :
534 allocator_(allocator),
535 uri_(schemaDocument->GetURI(), *allocator),
537 spec_(schemaDocument->GetSpecification()),
538 pointer_(p, allocator),
539 typeless_(schemaDocument->GetTypeless()),
543 type_((1 << kTotalSchemaType) - 1),
545 notValidatorIndex_(),
547 additionalPropertiesSchema_(),
548 patternProperties_(),
549 patternPropertyCount_(),
553 additionalProperties_(
true),
556 hasSchemaDependencies_(),
557 additionalItemsSchema_(),
563 additionalItems_(
true),
568 exclusiveMinimum_(
false),
569 exclusiveMaximum_(
false),
570 defaultValueLength_(0),
576 p.StringifyUriFragment(sb);
577 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Schema", sb.GetString(),
id.GetString());
579 typedef typename ValueType::ConstValueIterator ConstValueIterator;
580 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
586 if (
this != typeless_) {
587 typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
588 SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
589 new (entry) SchemaEntry(pointer_,
this,
true, allocator_);
590 schemaDocument->AddSchemaRefs(
this);
593 if (!value.IsObject())
598 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
599 if (
const ValueType* v = GetMember(value, GetIdString())) {
601 UriType local(*v, allocator);
602 id_ = local.
Resolve(id_, allocator);
603 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), v->GetString(), id_.GetString());
607 if (
const ValueType* v = GetMember(value, GetTypeString())) {
611 else if (v->IsArray())
612 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
616 if (
const ValueType* v = GetMember(value, GetEnumString())) {
617 if (v->IsArray() && v->Size() > 0) {
618 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(uint64_t) * v->Size()));
619 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
621 char buffer[256u + 24];
623 EnumHasherType h(&hasherAllocator, 256);
625 enum_[enumCount_++] = h.GetHashCode();
631 AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
634 if (schemaDocument && spec_.oapi != kVersion20) {
635 AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
636 AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
638 if (
const ValueType* v = GetMember(value, GetNotString())) {
639 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document, id_);
640 notValidatorIndex_ = validatorCount_;
647 const ValueType* properties = GetMember(value, GetPropertiesString());
648 const ValueType* required = GetMember(value, GetRequiredString());
649 const ValueType* dependencies = GetMember(value, GetDependenciesString());
654 if (properties && properties->IsObject())
655 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
656 AddUniqueElement(allProperties, itr->name);
658 if (required && required->IsArray())
659 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
661 AddUniqueElement(allProperties, *itr);
664 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
665 if (dependencies && dependencies->IsObject())
666 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
667 AddUniqueElement(allProperties, itr->name);
668 if (itr->value.IsArray())
669 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
671 AddUniqueElement(allProperties, *i);
674 if (allProperties.Size() > 0) {
675 propertyCount_ = allProperties.Size();
676 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(
Property) * propertyCount_));
677 for (
SizeType i = 0; i < propertyCount_; i++) {
679 properties_[i].name = allProperties[i];
680 properties_[i].schema = typeless_;
685 if (properties && properties->IsObject()) {
686 PointerType q = p.Append(GetPropertiesString(), allocator_);
687 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
689 if (FindPropertyIndex(itr->name, &index))
690 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document, id_);
695 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
696 if (
const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
697 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
699 patternPropertyCount_ = 0;
701 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
703 PointerType r = q.Append(itr->name, allocator_);
704 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name, schemaDocument, r);
705 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, r, itr->value, document, id_);
706 patternPropertyCount_++;
710 if (required && required->IsArray())
711 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
712 if (itr->IsString()) {
714 if (FindPropertyIndex(*itr, &index)) {
715 properties_[index].required =
true;
721 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
722 if (dependencies && dependencies->IsObject()) {
723 PointerType q = p.Append(GetDependenciesString(), allocator_);
724 hasDependencies_ =
true;
725 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
727 if (FindPropertyIndex(itr->name, &sourceIndex)) {
728 if (itr->value.IsArray()) {
729 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
730 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
731 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
733 if (FindPropertyIndex(*targetItr, &targetIndex))
734 properties_[sourceIndex].dependencies[targetIndex] =
true;
737 else if (itr->value.IsObject()) {
738 hasSchemaDependencies_ =
true;
739 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document, id_);
740 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
747 if (
const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
749 additionalProperties_ = v->GetBool();
750 else if (v->IsObject())
751 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document, id_);
754 AssignIfExist(minProperties_, value, GetMinPropertiesString());
755 AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
758 if (
const ValueType* v = GetMember(value, GetItemsString())) {
759 PointerType q = p.Append(GetItemsString(), allocator_);
761 schemaDocument->CreateSchema(&itemsList_, q, *v, document, id_);
762 else if (v->IsArray()) {
763 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
765 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
766 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document, id_);
770 AssignIfExist(minItems_, value, GetMinItemsString());
771 AssignIfExist(maxItems_, value, GetMaxItemsString());
774 if (spec_.oapi != kVersion20 && spec_.oapi != kVersion30)
775 if (
const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
777 additionalItems_ = v->GetBool();
778 else if (v->IsObject())
779 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document, id_);
782 AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
785 AssignIfExist(minLength_, value, GetMinLengthString());
786 AssignIfExist(maxLength_, value, GetMaxLengthString());
788 if (
const ValueType* v = GetMember(value, GetPatternString()))
789 pattern_ = CreatePattern(*v, schemaDocument, p.Append(GetPatternString(), allocator_));
792 if (
const ValueType* v = GetMember(value, GetMinimumString()))
794 minimum_.CopyFrom(*v, *allocator_);
796 if (
const ValueType* v = GetMember(value, GetMaximumString()))
798 maximum_.CopyFrom(*v, *allocator_);
800 AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
801 AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
803 if (
const ValueType* v = GetMember(value, GetMultipleOfString()))
804 if (v->IsNumber() && v->GetDouble() > 0.0)
805 multipleOf_.CopyFrom(*v, *allocator_);
808 if (
const ValueType* v = GetMember(value, GetDefaultValueString()))
810 defaultValueLength_ = v->GetStringLength();
815 if (spec_.oapi != kVersionNone)
816 AssignIfExist(readOnly_, value, GetReadOnlyString());
817 if (spec_.oapi >= kVersion30)
818 AssignIfExist(writeOnly_, value, GetWriteOnlyString());
819 if (readOnly_ && writeOnly_)
824 if (spec_.oapi >= kVersion30) {
825 AssignIfExist(nullable_, value, GetNullableString());
827 AddType(GetNullString());
832 AllocatorType::Free(enum_);
834 for (
SizeType i = 0; i < propertyCount_; i++)
836 AllocatorType::Free(properties_);
838 if (patternProperties_) {
839 for (
SizeType i = 0; i < patternPropertyCount_; i++)
841 AllocatorType::Free(patternProperties_);
843 AllocatorType::Free(itemsTuple_);
844#if RAPIDJSON_SCHEMA_HAS_REGEX
846 pattern_->~RegexType();
847 AllocatorType::Free(pattern_);
852 const SValue& GetURI()
const {
856 const UriType& GetId()
const {
864 const PointerType& GetPointer()
const {
868 bool BeginValue(Context& context)
const {
869 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::BeginValue");
870 if (context.inArray) {
872 context.valueUniqueness =
true;
875 context.valueSchema = itemsList_;
876 else if (itemsTuple_) {
877 if (context.arrayElementIndex < itemsTupleCount_)
878 context.valueSchema = itemsTuple_[context.arrayElementIndex];
879 else if (additionalItemsSchema_)
880 context.valueSchema = additionalItemsSchema_;
881 else if (additionalItems_)
882 context.valueSchema = typeless_;
884 context.error_handler.DisallowedItem(context.arrayElementIndex);
886 context.valueSchema = typeless_;
888 context.arrayElementIndex++;
893 context.valueSchema = typeless_;
895 context.arrayElementIndex++;
900 RAPIDJSON_FORCEINLINE
bool EndValue(Context& context)
const {
901 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndValue");
903 if (context.patternPropertiesValidatorCount > 0) {
904 bool otherValid =
false;
905 SizeType count = context.patternPropertiesValidatorCount;
906 if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
907 otherValid = context.patternPropertiesValidators[--count]->IsValid();
909 bool patternValid =
true;
910 for (
SizeType i = 0; i < count; i++)
911 if (!context.patternPropertiesValidators[i]->IsValid()) {
912 patternValid =
false;
916 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
918 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
922 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
923 if (!patternValid || !otherValid) {
924 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
928 else if (!patternValid && !otherValid) {
929 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
935 if (enum_ && context.hasher) {
936 const uint64_t h = context.factory.GetHashCode(context.hasher);
937 for (
SizeType i = 0; i < enumCount_; i++)
946 if (context.validatorCount > 0) {
948 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
949 if (!context.validators[i]->IsValid()) {
950 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
954 if (anyOf_.schemas) {
955 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
956 if (context.validators[i]->IsValid())
958 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
963 if (oneOf_.schemas) {
964 bool oneValid =
false;
966 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
967 if (context.validators[i]->IsValid()) {
969 context.error_handler.MultipleOneOf(firstMatch, i - oneOf_.begin);
973 firstMatch = i - oneOf_.begin;
977 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
982 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
983 context.error_handler.Disallowed();
991 bool Null(Context& context)
const {
992 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Null");
993 if (!(type_ & (1 << kNullSchemaType))) {
994 DisallowedType(context, GetNullString());
997 return CreateParallelValidator(context);
1000 bool Bool(Context& context,
bool b)
const {
1001 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Bool", b);
1002 if (!CheckBool(context, b))
1004 return CreateParallelValidator(context);
1007 bool Int(Context& context,
int i)
const {
1008 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int", (int64_t)i);
1009 if (!CheckInt(context, i))
1011 return CreateParallelValidator(context);
1014 bool Uint(Context& context,
unsigned u)
const {
1015 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint", (uint64_t)u);
1016 if (!CheckUint(context, u))
1018 return CreateParallelValidator(context);
1021 bool Int64(Context& context, int64_t i)
const {
1022 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Int64", i);
1023 if (!CheckInt(context, i))
1025 return CreateParallelValidator(context);
1028 bool Uint64(Context& context, uint64_t u)
const {
1029 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Uint64", u);
1030 if (!CheckUint(context, u))
1032 return CreateParallelValidator(context);
1035 bool Double(Context& context,
double d)
const {
1036 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Double", d);
1037 if (!(type_ & (1 << kNumberSchemaType))) {
1038 DisallowedType(context, GetNumberString());
1042 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
1045 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
1048 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
1051 return CreateParallelValidator(context);
1054 bool String(Context& context,
const Ch* str,
SizeType length,
bool)
const {
1055 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::String", str);
1056 if (!(type_ & (1 << kStringSchemaType))) {
1057 DisallowedType(context, GetStringString());
1061 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
1063 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
1064 if (count < minLength_) {
1065 context.error_handler.TooShort(str, length, minLength_);
1068 if (count > maxLength_) {
1069 context.error_handler.TooLong(str, length, maxLength_);
1075 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
1076 context.error_handler.DoesNotMatch(str, length);
1080 return CreateParallelValidator(context);
1083 bool StartObject(Context& context)
const {
1084 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartObject");
1085 if (!(type_ & (1 << kObjectSchemaType))) {
1086 DisallowedType(context, GetObjectString());
1090 if (hasDependencies_ || hasRequired_) {
1091 context.propertyExist =
static_cast<bool*
>(context.factory.MallocState(
sizeof(
bool) * propertyCount_));
1092 std::memset(context.propertyExist, 0,
sizeof(
bool) * propertyCount_);
1095 if (patternProperties_) {
1096 SizeType count = patternPropertyCount_ + 1;
1097 context.patternPropertiesSchemas =
static_cast<const SchemaType**
>(context.factory.MallocState(
sizeof(
const SchemaType*) * count));
1098 context.patternPropertiesSchemaCount = 0;
1099 std::memset(context.patternPropertiesSchemas, 0,
sizeof(SchemaType*) * count);
1102 return CreateParallelValidator(context);
1105 bool Key(Context& context,
const Ch* str,
SizeType len,
bool)
const {
1106 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::Key", str);
1108 if (patternProperties_) {
1109 context.patternPropertiesSchemaCount = 0;
1110 for (
SizeType i = 0; i < patternPropertyCount_; i++)
1111 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
1112 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
1113 context.valueSchema = typeless_;
1118 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
1119 if (context.patternPropertiesSchemaCount > 0) {
1120 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
1121 context.valueSchema = typeless_;
1122 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
1125 context.valueSchema = properties_[index].schema;
1127 if (context.propertyExist)
1128 context.propertyExist[index] =
true;
1133 if (additionalPropertiesSchema_) {
1134 if (context.patternPropertiesSchemaCount > 0) {
1135 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
1136 context.valueSchema = typeless_;
1137 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
1140 context.valueSchema = additionalPropertiesSchema_;
1143 else if (additionalProperties_) {
1144 context.valueSchema = typeless_;
1148 if (context.patternPropertiesSchemaCount == 0) {
1150 context.valueSchema = typeless_;
1151 context.error_handler.DisallowedProperty(str, len);
1158 bool EndObject(Context& context,
SizeType memberCount)
const {
1159 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndObject");
1161 context.error_handler.StartMissingProperties();
1162 for (
SizeType index = 0; index < propertyCount_; index++)
1163 if (properties_[index].required && !context.propertyExist[index])
1164 if (properties_[index].schema->defaultValueLength_ == 0 )
1165 context.error_handler.AddMissingProperty(properties_[index].name);
1166 if (context.error_handler.EndMissingProperties())
1170 if (memberCount < minProperties_) {
1171 context.error_handler.TooFewProperties(memberCount, minProperties_);
1175 if (memberCount > maxProperties_) {
1176 context.error_handler.TooManyProperties(memberCount, maxProperties_);
1180 if (hasDependencies_) {
1181 context.error_handler.StartDependencyErrors();
1182 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1183 const Property& source = properties_[sourceIndex];
1184 if (context.propertyExist[sourceIndex]) {
1185 if (source.dependencies) {
1186 context.error_handler.StartMissingDependentProperties();
1187 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1188 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
1189 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
1190 context.error_handler.EndMissingDependentProperties(source.name);
1192 else if (source.dependenciesSchema) {
1193 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
1194 if (!dependenciesValidator->IsValid())
1195 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
1199 if (context.error_handler.EndDependencyErrors())
1206 bool StartArray(Context& context)
const {
1207 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::StartArray");
1208 context.arrayElementIndex = 0;
1209 context.inArray =
true;
1211 if (!(type_ & (1 << kArraySchemaType))) {
1212 DisallowedType(context, GetArrayString());
1216 return CreateParallelValidator(context);
1219 bool EndArray(Context& context,
SizeType elementCount)
const {
1220 RAPIDJSON_SCHEMA_PRINT(Method,
"Schema::EndArray");
1221 context.inArray =
false;
1223 if (elementCount < minItems_) {
1224 context.error_handler.TooFewItems(elementCount, minItems_);
1228 if (elementCount > maxItems_) {
1229 context.error_handler.TooManyItems(elementCount, maxItems_);
1236 static const ValueType& GetValidateErrorKeyword(
ValidateErrorCode validateErrorCode) {
1237 switch (validateErrorCode) {
1272 default:
return GetNullString();
1278#define RAPIDJSON_STRING_(name, ...) \
1279 static const ValueType& Get##name##String() {\
1280 static const Ch s[] = { __VA_ARGS__, '\0' };\
1281 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1285 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
1286 RAPIDJSON_STRING_(Boolean,
'b',
'o',
'o',
'l',
'e',
'a',
'n')
1287 RAPIDJSON_STRING_(Object,
'o',
'b',
'j',
'e',
'c',
't')
1288 RAPIDJSON_STRING_(Array,
'a',
'r',
'r',
'a',
'y')
1289 RAPIDJSON_STRING_(String,
's',
't',
'r',
'i',
'n',
'g')
1290 RAPIDJSON_STRING_(Number,
'n',
'u',
'm',
'b',
'e',
'r')
1291 RAPIDJSON_STRING_(Integer,
'i',
'n',
't',
'e',
'g',
'e',
'r')
1292 RAPIDJSON_STRING_(
Type,
't',
'y',
'p',
'e')
1293 RAPIDJSON_STRING_(Enum,
'e',
'n',
'u',
'm')
1294 RAPIDJSON_STRING_(AllOf,
'a',
'l',
'l',
'O',
'f')
1295 RAPIDJSON_STRING_(AnyOf,
'a',
'n',
'y',
'O',
'f')
1296 RAPIDJSON_STRING_(OneOf,
'o',
'n',
'e',
'O',
'f')
1297 RAPIDJSON_STRING_(Not,
'n',
'o',
't')
1298 RAPIDJSON_STRING_(Properties,
'p',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1299 RAPIDJSON_STRING_(Required,
'r',
'e',
'q',
'u',
'i',
'r',
'e',
'd')
1300 RAPIDJSON_STRING_(Dependencies,
'd',
'e',
'p',
'e',
'n',
'd',
'e',
'n',
'c',
'i',
'e',
's')
1301 RAPIDJSON_STRING_(PatternProperties,
'p',
'a',
't',
't',
'e',
'r',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1302 RAPIDJSON_STRING_(AdditionalProperties,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1303 RAPIDJSON_STRING_(MinProperties,
'm',
'i',
'n',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1304 RAPIDJSON_STRING_(MaxProperties,
'm',
'a',
'x',
'P',
'r',
'o',
'p',
'e',
'r',
't',
'i',
'e',
's')
1305 RAPIDJSON_STRING_(Items,
'i',
't',
'e',
'm',
's')
1306 RAPIDJSON_STRING_(MinItems,
'm',
'i',
'n',
'I',
't',
'e',
'm',
's')
1307 RAPIDJSON_STRING_(MaxItems,
'm',
'a',
'x',
'I',
't',
'e',
'm',
's')
1308 RAPIDJSON_STRING_(AdditionalItems,
'a',
'd',
'd',
'i',
't',
'i',
'o',
'n',
'a',
'l',
'I',
't',
'e',
'm',
's')
1309 RAPIDJSON_STRING_(UniqueItems,
'u',
'n',
'i',
'q',
'u',
'e',
'I',
't',
'e',
'm',
's')
1310 RAPIDJSON_STRING_(MinLength,
'm',
'i',
'n',
'L',
'e',
'n',
'g',
't',
'h')
1311 RAPIDJSON_STRING_(MaxLength,
'm',
'a',
'x',
'L',
'e',
'n',
'g',
't',
'h')
1312 RAPIDJSON_STRING_(Pattern,
'p',
'a',
't',
't',
'e',
'r',
'n')
1313 RAPIDJSON_STRING_(Minimum,
'm',
'i',
'n',
'i',
'm',
'u',
'm')
1314 RAPIDJSON_STRING_(Maximum,
'm',
'a',
'x',
'i',
'm',
'u',
'm')
1315 RAPIDJSON_STRING_(ExclusiveMinimum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'i',
'n',
'i',
'm',
'u',
'm')
1316 RAPIDJSON_STRING_(ExclusiveMaximum,
'e',
'x',
'c',
'l',
'u',
's',
'i',
'v',
'e',
'M',
'a',
'x',
'i',
'm',
'u',
'm')
1317 RAPIDJSON_STRING_(MultipleOf,
'm',
'u',
'l',
't',
'i',
'p',
'l',
'e',
'O',
'f')
1318 RAPIDJSON_STRING_(DefaultValue,
'd',
'e',
'f',
'a',
'u',
'l',
't')
1319 RAPIDJSON_STRING_(Schema,
'$',
's',
'c',
'h',
'e',
'm',
'a')
1320 RAPIDJSON_STRING_(Ref,
'$',
'r',
'e',
'f')
1321 RAPIDJSON_STRING_(Id,
'i',
'd')
1322 RAPIDJSON_STRING_(Swagger,
's',
'w',
'a',
'g',
'g',
'e',
'r')
1323 RAPIDJSON_STRING_(OpenApi,
'o',
'p',
'e',
'n',
'a',
'p',
'i')
1324 RAPIDJSON_STRING_(ReadOnly,
'r',
'e',
'a',
'd',
'O',
'n',
'l',
'y')
1325 RAPIDJSON_STRING_(WriteOnly,
'w',
'r',
'i',
't',
'e',
'O',
'n',
'l',
'y')
1326 RAPIDJSON_STRING_(Nullable,
'n',
'u',
'l',
'l',
'a',
'b',
'l',
'e')
1328#undef RAPIDJSON_STRING_
1331 enum SchemaValueType {
1342#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1344#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1345 typedef std::basic_regex<Ch> RegexType;
1347 typedef char RegexType;
1350 struct SchemaArray {
1351 SchemaArray() : schemas(), count() {}
1352 ~SchemaArray() { AllocatorType::Free(schemas); }
1353 const SchemaType** schemas;
1358 template <
typename V1,
typename V2>
1359 void AddUniqueElement(V1& a,
const V2& v) {
1360 for (
typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
1363 V1 c(v, *allocator_);
1364 a.PushBack(c, *allocator_);
1367 static const ValueType* GetMember(
const ValueType& value,
const ValueType& name) {
1368 typename ValueType::ConstMemberIterator itr = value.FindMember(name);
1369 return itr != value.MemberEnd() ? &(itr->value) : 0;
1372 static void AssignIfExist(
bool& out,
const ValueType& value,
const ValueType& name) {
1373 if (
const ValueType* v = GetMember(value, name))
1378 static void AssignIfExist(
SizeType& out,
const ValueType& value,
const ValueType& name) {
1379 if (
const ValueType* v = GetMember(value, name))
1380 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1381 out =
static_cast<SizeType>(v->GetUint64());
1384 void AssignIfExist(
SchemaArray& out, SchemaDocumentType& schemaDocument,
const PointerType& p,
const ValueType& value,
const ValueType& name,
const ValueType& document) {
1385 if (
const ValueType* v = GetMember(value, name)) {
1386 if (v->IsArray() && v->Size() > 0) {
1387 PointerType q = p.Append(name, allocator_);
1388 out.count = v->Size();
1389 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1390 memset(out.schemas, 0,
sizeof(Schema*)* out.count);
1391 for (
SizeType i = 0; i < out.count; i++)
1392 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document, id_);
1393 out.begin = validatorCount_;
1394 validatorCount_ += out.count;
1399#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1400 template <
typename ValueType>
1401 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1402 if (value.IsString()) {
1403 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(value.GetString(), allocator_);
1404 if (!r->IsValid()) {
1407 AllocatorType::Free(r);
1415 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1416 GenericRegexSearch<RegexType> rs(*pattern);
1417 return rs.Search(str);
1419#elif RAPIDJSON_SCHEMA_USE_STDREGEX
1420 template <
typename ValueType>
1421 RegexType* CreatePattern(
const ValueType& value, SchemaDocumentType* sd,
const PointerType& p) {
1422 if (value.IsString()) {
1423 RegexType *r =
static_cast<RegexType*
>(allocator_->Malloc(
sizeof(RegexType)));
1425 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1427 catch (
const std::regex_error& e) {
1429 AllocatorType::Free(r);
1435 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1436 std::match_results<const Ch*> r;
1437 return std::regex_search(str, str + length, r, *pattern);
1440 template <
typename ValueType>
1441 RegexType* CreatePattern(
const ValueType&) {
1445 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1448 void AddType(
const ValueType& type) {
1449 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1450 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1451 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1452 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1453 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1454 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1455 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1461 bool CreateParallelValidator(Context& context)
const {
1462 if (enum_ || context.arrayUniqueness)
1463 context.hasher = context.factory.CreateHasher();
1465 if (validatorCount_) {
1467 context.validators =
static_cast<ISchemaValidator**
>(context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1468 std::memset(context.validators, 0,
sizeof(ISchemaValidator*) * validatorCount_);
1469 context.validatorCount = validatorCount_;
1473 CreateSchemaValidators(context, allOf_,
false);
1476 CreateSchemaValidators(context, anyOf_,
false);
1479 CreateSchemaValidators(context, oneOf_,
false);
1482 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_,
false);
1484 if (hasSchemaDependencies_) {
1485 for (
SizeType i = 0; i < propertyCount_; i++)
1486 if (properties_[i].dependenciesSchema)
1487 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema,
false);
1492 if (readOnly_ && (context.flags & kValidateWriteFlag)) {
1493 context.error_handler.DisallowedWhenWriting();
1496 if (writeOnly_ && (context.flags & kValidateReadFlag)) {
1497 context.error_handler.DisallowedWhenReading();
1504 void CreateSchemaValidators(Context& context,
const SchemaArray& schemas,
const bool inheritContinueOnErrors)
const {
1505 for (
SizeType i = 0; i < schemas.count; i++)
1506 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1510 bool FindPropertyIndex(
const ValueType& name,
SizeType* outIndex)
const {
1512 const Ch* str = name.GetString();
1513 for (
SizeType index = 0; index < propertyCount_; index++)
1514 if (properties_[index].name.GetStringLength() == len &&
1515 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(Ch) * len) == 0))
1523 bool CheckBool(Context& context,
bool)
const {
1524 if (!(type_ & (1 << kBooleanSchemaType))) {
1525 DisallowedType(context, GetBooleanString());
1531 bool CheckInt(Context& context, int64_t i)
const {
1532 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1533 DisallowedType(context, GetIntegerString());
1537 if (!minimum_.IsNull()) {
1538 if (minimum_.IsInt64()) {
1539 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1540 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1544 else if (minimum_.IsUint64()) {
1545 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1548 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1552 if (!maximum_.IsNull()) {
1553 if (maximum_.IsInt64()) {
1554 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1555 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1559 else if (maximum_.IsUint64()) { }
1561 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1565 if (!multipleOf_.IsNull()) {
1566 if (multipleOf_.IsUint64()) {
1567 if (
static_cast<uint64_t
>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1568 context.error_handler.NotMultipleOf(i, multipleOf_);
1572 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1579 bool CheckUint(Context& context, uint64_t i)
const {
1580 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1581 DisallowedType(context, GetIntegerString());
1585 if (!minimum_.IsNull()) {
1586 if (minimum_.IsUint64()) {
1587 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1588 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1592 else if (minimum_.IsInt64())
1594 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1598 if (!maximum_.IsNull()) {
1599 if (maximum_.IsUint64()) {
1600 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1601 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1605 else if (maximum_.IsInt64()) {
1606 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1609 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1613 if (!multipleOf_.IsNull()) {
1614 if (multipleOf_.IsUint64()) {
1615 if (i % multipleOf_.GetUint64() != 0) {
1616 context.error_handler.NotMultipleOf(i, multipleOf_);
1620 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1627 bool CheckDoubleMinimum(Context& context,
double d)
const {
1628 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1629 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1635 bool CheckDoubleMaximum(Context& context,
double d)
const {
1636 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1637 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1643 bool CheckDoubleMultipleOf(Context& context,
double d)
const {
1644 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1646 double qRounded = std::floor(q + 0.5);
1647 double scaledEpsilon = (q + qRounded) * std::numeric_limits<double>::epsilon();
1648 double difference = std::abs(qRounded - q);
1649 bool isMultiple = difference <= scaledEpsilon || difference < (std::numeric_limits<double>::min)();
1651 context.error_handler.NotMultipleOf(d, multipleOf_);
1657 void DisallowedType(Context& context,
const ValueType& actualType)
const {
1658 ErrorHandler& eh = context.error_handler;
1659 eh.StartDisallowedType();
1661 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1662 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1663 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1664 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1665 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1667 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1668 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1670 eh.EndDisallowedType(actualType);
1674 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(
false) {}
1675 ~Property() { AllocatorType::Free(dependencies); }
1677 const SchemaType* schema;
1678 const SchemaType* dependenciesSchema;
1679 SizeType dependenciesValidatorIndex;
1684 struct PatternProperty {
1685 PatternProperty() : schema(), pattern() {}
1686 ~PatternProperty() {
1688 pattern->~RegexType();
1689 AllocatorType::Free(pattern);
1692 const SchemaType* schema;
1696 AllocatorType* allocator_;
1700 PointerType pointer_;
1701 const SchemaType* typeless_;
1707 const SchemaType* not_;
1713 const SchemaType* additionalPropertiesSchema_;
1719 bool additionalProperties_;
1720 bool hasDependencies_;
1722 bool hasSchemaDependencies_;
1724 const SchemaType* additionalItemsSchema_;
1725 const SchemaType* itemsList_;
1726 const SchemaType** itemsTuple_;
1730 bool additionalItems_;
1733 RegexType* pattern_;
1740 bool exclusiveMinimum_;
1741 bool exclusiveMaximum_;
1818 typedef ValueT ValueType;
1821 typedef typename ValueType::EncodingType EncodingType;
1822 typedef typename EncodingType::Ch Ch;
1829 template <
typename,
typename,
typename>
1830 friend class GenericSchemaValidator;
1845 IRemoteSchemaDocumentProviderType* remoteProvider = 0,
Allocator* allocator = 0,
1846 const PointerType& pointer = PointerType(),
1848 remoteProvider_(remoteProvider),
1849 allocator_(allocator),
1853 schemaMap_(allocator, kInitialSchemaMapSize),
1854 schemaRef_(allocator, kInitialSchemaRefSize),
1859 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::GenericSchemaDocument");
1864 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1865 docId_ = UriType(uri_, allocator_);
1867 typeless_ =
static_cast<SchemaType*
>(allocator_->Malloc(
sizeof(SchemaType)));
1868 new (typeless_) SchemaType(
this, PointerType(), ValueType(
kObjectType).Move(), ValueType(
kObjectType).Move(), allocator_, docId_);
1872 SetSchemaSpecification(document);
1878 if (pointer.GetTokenCount() == 0) {
1879 CreateSchemaRecursive(&
root_, pointer, document, document, docId_);
1881 else if (
const ValueType* v = pointer.Get(document)) {
1882 CreateSchema(&
root_, pointer, *v, document, docId_);
1886 pointer.StringifyUriFragment(sb);
1892 schemaRef_.ShrinkToFit();
1895#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1898 remoteProvider_(rhs.remoteProvider_),
1899 allocator_(rhs.allocator_),
1900 ownAllocator_(rhs.ownAllocator_),
1902 typeless_(rhs.typeless_),
1903 schemaMap_(std::move(rhs.schemaMap_)),
1904 schemaRef_(std::move(rhs.schemaRef_)),
1905 uri_(std::move(rhs.uri_)),
1906 docId_(std::move(rhs.docId_)),
1908 error_(std::move(rhs.error_)),
1909 currentError_(std::move(rhs.currentError_))
1911 rhs.remoteProvider_ = 0;
1913 rhs.ownAllocator_ = 0;
1920 while (!schemaMap_.Empty())
1921 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1924 typeless_->~SchemaType();
1925 Allocator::Free(typeless_);
1931 currentError_.SetNull();
1936 const GValue& GetURI()
const {
return uri_; }
1938 const Specification& GetSpecification()
const {
return spec_; }
1939 bool IsSupportedSpecification()
const {
return spec_.IsSupported(); }
1944 SchemaDraft draft = GetSchemaDraft(document);
1945 if (draft != kDraftNone)
1948 OpenApiVersion oapi = GetOpenApiVersion(document);
1949 if (oapi != kVersionNone)
1960 const GValue&
GetError()
const {
return error_; }
1962 static const StringRefType& GetSchemaErrorKeyword(
SchemaErrorCode schemaErrorCode) {
1963 switch (schemaErrorCode) {
1977 default:
return GetNullString();
1984 AddCurrentError(code, location);
1990 currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1991 AddCurrentError(code, location);
1997 currentError_.AddMember(GetValueString(), GValue(value, length, *allocator_).Move(), *allocator_);
1998 currentError_.AddMember(GetOffsetString(),
static_cast<SizeType>(pointer.GetParseErrorOffset() /
sizeof(Ch)), *allocator_);
1999 AddCurrentError(code, location);
2008 typedef const PointerType* SchemaRefPtr;
2010 struct SchemaEntry {
2011 SchemaEntry(
const PointerType& p, SchemaType* s,
bool o,
Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
2014 schema->~SchemaType();
2015 Allocator::Free(schema);
2018 PointerType pointer;
2023 void AddErrorInstanceLocation(GValue& result,
const PointerType& location) {
2025 location.StringifyUriFragment(sb);
2026 GValue instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)), *allocator_);
2027 result.AddMember(GetInstanceRefString(), instanceRef, *allocator_);
2030 void AddError(GValue& keyword, GValue& error) {
2032 if (member == error_.MemberEnd())
2033 error_.AddMember(keyword, error, *allocator_);
2035 if (member->value.IsObject()) {
2037 errors.PushBack(member->value, *allocator_);
2038 member->value = errors;
2040 member->value.PushBack(error, *allocator_);
2044 void AddCurrentError(
const SchemaErrorCode code,
const PointerType& location) {
2045 RAPIDJSON_SCHEMA_PRINT(InvalidKeyword, GetSchemaErrorKeyword(code));
2046 currentError_.AddMember(GetErrorCodeString(), code, *allocator_);
2047 AddErrorInstanceLocation(currentError_, location);
2048 AddError(GValue(GetSchemaErrorKeyword(code)).Move(), currentError_);
2051#define RAPIDJSON_STRING_(name, ...) \
2052 static const StringRefType& Get##name##String() {\
2053 static const Ch s[] = { __VA_ARGS__, '\0' };\
2054 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2058 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2059 RAPIDJSON_STRING_(ErrorCode,
'e',
'r',
'r',
'o',
'r',
'C',
'o',
'd',
'e')
2060 RAPIDJSON_STRING_(
Value,
'v',
'a',
'l',
'u',
'e')
2061 RAPIDJSON_STRING_(Offset,
'o',
'f',
'f',
's',
'e',
't')
2063 RAPIDJSON_STRING_(Null,
'n',
'u',
'l',
'l')
2064 RAPIDJSON_STRING_(SpecUnknown,
'S',
'p',
'e',
'c',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2065 RAPIDJSON_STRING_(SpecUnsupported,
'S',
'p',
'e',
'c',
'U',
'n',
's',
'u',
'p',
'p',
'o',
'r',
't',
'e',
'd')
2066 RAPIDJSON_STRING_(SpecIllegal,
'S',
'p',
'e',
'c',
'I',
'l',
'l',
'e',
'g',
'a',
'l')
2067 RAPIDJSON_STRING_(StartUnknown,
'S',
't',
'a',
'r',
't',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2068 RAPIDJSON_STRING_(RefPlainName,
'R',
'e',
'f',
'P',
'l',
'a',
'i',
'n',
'N',
'a',
'm',
'e')
2069 RAPIDJSON_STRING_(RefInvalid,
'R',
'e',
'f',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2070 RAPIDJSON_STRING_(RefPointerInvalid,
'R',
'e',
'f',
'P',
'o',
'i',
'n',
't',
'e',
'r',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2071 RAPIDJSON_STRING_(RefUnknown,
'R',
'e',
'f',
'U',
'n',
'k',
'n',
'o',
'w',
'n')
2072 RAPIDJSON_STRING_(RefCyclical,
'R',
'e',
'f',
'C',
'y',
'c',
'l',
'i',
'c',
'a',
'l')
2073 RAPIDJSON_STRING_(RefNoRemoteProvider,
'R',
'e',
'f',
'N',
'o',
'R',
'e',
'm',
'o',
't',
'e',
'P',
'r',
'o',
'v',
'i',
'd',
'e',
'r')
2074 RAPIDJSON_STRING_(RefNoRemoteSchema,
'R',
'e',
'f',
'N',
'o',
'R',
'e',
'm',
'o',
't',
'e',
'S',
'c',
'h',
'e',
'm',
'a')
2075 RAPIDJSON_STRING_(ReadOnlyAndWriteOnly,
'R',
'e',
'a',
'd',
'O',
'n',
'l',
'y',
'A',
'n',
'd',
'W',
'r',
'i',
't',
'e',
'O',
'n',
'l',
'y')
2076 RAPIDJSON_STRING_(RegexInvalid,
'R',
'e',
'g',
'e',
'x',
'I',
'n',
'v',
'a',
'l',
'i',
'd')
2078#undef RAPIDJSON_STRING_
2081 static SchemaDraft GetSchemaDraft(
const ValueType& document) {
2082 static const Ch kDraft03String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'3',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2083 static const Ch kDraft04String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'4',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2084 static const Ch kDraft05String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'5',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2085 static const Ch kDraft06String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'6',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2086 static const Ch kDraft07String[] = {
'h',
't',
't',
'p',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'-',
'0',
'7',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'#',
'\0' };
2087 static const Ch kDraft2019_09String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'1',
'9',
'-',
'0',
'9',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2088 static const Ch kDraft2020_12String[] = {
'h',
't',
't',
'p',
's',
':',
'/',
'/',
'j',
's',
'o',
'n',
'-',
's',
'c',
'h',
'e',
'm',
'a',
'.',
'o',
'r',
'g',
'/',
'd',
'r',
'a',
'f',
't',
'/',
'2',
'0',
'2',
'0',
'-',
'1',
'2',
'/',
's',
'c',
'h',
'e',
'm',
'a',
'\0' };
2090 if (!document.IsObject()) {
2095 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSchemaString());
2096 if (itr != document.MemberEnd()) {
2097 if (!itr->value.IsString())
return kDraftUnknown;
2098 const UriType draftUri(itr->value);
2100 if (draftUri.Match(UriType(kDraft04String),
false))
return kDraft04;
2101 if (draftUri.Match(UriType(kDraft05String),
false))
return kDraft05;
2102 if (draftUri.Match(UriType(kDraft06String),
false))
return kDraft06;
2103 if (draftUri.Match(UriType(kDraft07String),
false))
return kDraft07;
2104 if (draftUri.Match(UriType(kDraft03String),
false))
return kDraft03;
2105 if (draftUri.Match(UriType(kDraft2019_09String),
false))
return kDraft2019_09;
2106 if (draftUri.Match(UriType(kDraft2020_12String),
false))
return kDraft2020_12;
2107 return kDraftUnknown;
2115 static OpenApiVersion GetOpenApiVersion(
const ValueType& document) {
2116 static const Ch kVersion20String[] = {
'2',
'.',
'0',
'\0' };
2117 static const Ch kVersion30String[] = {
'3',
'.',
'0',
'.',
'\0' };
2118 static const Ch kVersion31String[] = {
'3',
'.',
'1',
'.',
'\0' };
2119 static SizeType len = internal::StrLen<Ch>(kVersion30String);
2121 if (!document.IsObject()) {
2122 return kVersionNone;
2126 typename ValueType::ConstMemberIterator itr = document.FindMember(SchemaType::GetSwaggerString());
2127 if (itr == document.MemberEnd()) itr = document.FindMember(SchemaType::GetOpenApiString());
2128 if (itr != document.MemberEnd()) {
2129 if (!itr->value.IsString())
return kVersionUnknown;
2130 const ValueType kVersion20Value(kVersion20String);
2131 if (kVersion20Value == itr->value)
return kVersion20;
2132 const ValueType kVersion30Value(kVersion30String);
2133 if (itr->value.GetStringLength() > len && kVersion30Value == ValueType(itr->value.GetString(), len))
return kVersion30;
2134 const ValueType kVersion31Value(kVersion31String);
2135 if (itr->value.GetStringLength() > len && kVersion31Value == ValueType(itr->value.GetString(), len))
return kVersion31;
2136 return kVersionUnknown;
2139 return kVersionNone;
2144 void SetSchemaSpecification(
const ValueType& document) {
2146 SchemaDraft docDraft = GetSchemaDraft(document);
2147 OpenApiVersion docOapi = GetOpenApiVersion(document);
2149 if (docDraft != kDraftNone && docOapi != kVersionNone)
2152 if (docDraft != kDraftNone)
2153 spec_ = Specification(docDraft);
2154 else if (docOapi != kVersionNone)
2155 spec_ = Specification(docOapi);
2157 if (spec_.draft == kDraftUnknown || spec_.oapi == kVersionUnknown)
2159 else if (!spec_.IsSupported())
2164 void CreateSchemaRecursive(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2166 UriType newid = UriType(CreateSchema(schema, pointer, v, document,
id), allocator_);
2168 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
2169 CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document, newid);
2172 for (
SizeType i = 0; i < v.Size(); i++)
2173 CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document,
id);
2177 const UriType& CreateSchema(
const SchemaType** schema,
const PointerType& pointer,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2179 GenericStringBuffer<EncodingType> sb;
2180 pointer.StringifyUriFragment(sb);
2181 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::CreateSchema", sb.GetString(),
id.GetString());
2183 if (
const SchemaType* sc = GetSchema(pointer)) {
2186 AddSchemaRefs(
const_cast<SchemaType*
>(sc));
2188 else if (!HandleRefSchema(pointer, schema, v, document,
id)) {
2190 SchemaType* s =
new (allocator_->Malloc(
sizeof(SchemaType))) SchemaType(
this, pointer, v, document, allocator_,
id);
2198 *schema = typeless_;
2199 AddSchemaRefs(typeless_);
2206 bool HandleRefSchema(
const PointerType& source,
const SchemaType** schema,
const ValueType& v,
const ValueType& document,
const UriType&
id) {
2207 typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
2208 if (itr == v.MemberEnd())
2211 GenericStringBuffer<EncodingType> sb;
2212 source.StringifyUriFragment(sb);
2213 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::HandleRefSchema", sb.GetString(),
id.GetString());
2215 new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&source);
2217 if (itr->value.IsString()) {
2223 UriType scopeId = UriType(
id, allocator_);
2224 UriType ref = UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
2225 RAPIDJSON_SCHEMA_PRINT(SchemaIds,
id.GetString(), itr->value.GetString(), ref.GetString());
2228 PointerType basePointer = PointerType();
2229 const ValueType *base =
FindId(document, ref, basePointer, docId_,
false);
2232 if (!remoteProvider_)
2236 const Ch* s = ref.GetFragString();
2237 len = ref.GetFragStringLength();
2238 if (len <= 1 || s[1] ==
'/') {
2240 const PointerType pointer(s, len, allocator_);
2241 if (!pointer.IsValid())
2245 if (
const SchemaType *sc = remoteDocument->GetSchema(pointer)) {
2248 AddSchemaRefs(
const_cast<SchemaType *
>(sc));
2261 const Ch* s = ref.GetFragString();
2262 len = ref.GetFragStringLength();
2263 if (len <= 1 || s[1] ==
'/') {
2265 const PointerType relPointer(s, len, allocator_);
2266 if (!relPointer.IsValid())
2270 if (
const ValueType *pv = relPointer.Get(*base)) {
2272 PointerType pointer(basePointer, allocator_);
2273 for (
SizeType i = 0; i < relPointer.GetTokenCount(); i++)
2274 pointer = pointer.Append(relPointer.GetTokens()[i], allocator_);
2275 if (IsCyclicRef(pointer))
2280 size_t unresolvedTokenIndex;
2281 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2282 CreateSchema(schema, pointer, *pv, document, scopeId);
2291 PointerType pointer(allocator_);
2292 if (spec_.oapi == kVersion20 || spec_.oapi == kVersion30)
2296 else if (
const ValueType *pv =
FindId(*base, ref, pointer, UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_),
true, basePointer)) {
2297 if (IsCyclicRef(pointer))
2302 size_t unresolvedTokenIndex;
2303 scopeId = pointer.GetUri(document, docId_, &unresolvedTokenIndex, allocator_);
2304 CreateSchema(schema, pointer, *pv, document, scopeId);
2316 *schema = typeless_;
2317 AddSchemaRefs(typeless_);
2325 ValueType*
FindId(
const ValueType& doc,
const UriType& finduri, PointerType& resptr,
const UriType& baseuri,
bool full,
const PointerType& here = PointerType())
const {
2327 ValueType* resval = 0;
2328 UriType tempuri = UriType(finduri, allocator_);
2329 UriType localuri = UriType(baseuri, allocator_);
2333 if (m != doc.MemberEnd() && m->value.GetType() ==
kStringType) {
2334 localuri = UriType(m->value, allocator_).
Resolve(baseuri, allocator_);
2337 if (localuri.Match(finduri, full)) {
2338 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::FindId (match)", full ? localuri.GetString() : localuri.GetBaseString());
2339 resval =
const_cast<ValueType *
>(&doc);
2344 for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
2346 resval =
FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
2354 resval =
FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
2364 void AddSchemaRefs(SchemaType* schema) {
2365 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaDocument::AddSchemaRefs");
2366 while (!schemaRef_.Empty()) {
2367 SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
2368 SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
2369 new (entry) SchemaEntry(**ref, schema,
false, allocator_);
2374 bool IsCyclicRef(
const PointerType& pointer)
const {
2375 for (
const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
2376 if (pointer == **ref)
2381 const SchemaType* GetSchema(
const PointerType& pointer)
const {
2382 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2383 if (pointer == target->pointer)
2384 return target->schema;
2388 PointerType GetPointer(
const SchemaType* schema)
const {
2389 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
2390 if (schema == target->schema)
2391 return target->pointer;
2392 return PointerType();
2395 const SchemaType* GetTypeless()
const {
return typeless_; }
2397 static const size_t kInitialSchemaMapSize = 64;
2398 static const size_t kInitialSchemaRefSize = 64;
2400 IRemoteSchemaDocumentProviderType* remoteProvider_;
2401 Allocator *allocator_;
2402 Allocator *ownAllocator_;
2404 SchemaType* typeless_;
2411 GValue currentError_;
2443 typedef typename SchemaDocumentType::SchemaType SchemaType;
2444 typedef typename SchemaDocumentType::PointerType PointerType;
2445 typedef typename SchemaType::EncodingType EncodingType;
2446 typedef typename SchemaType::SValue SValue;
2447 typedef typename EncodingType::Ch Ch;
2459 const SchemaDocumentType& schemaDocument,
2460 StateAllocator* allocator = 0,
2461 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2462 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2464 schemaDocument_(&schemaDocument),
2465 root_(schemaDocument.GetRoot()),
2466 stateAllocator_(allocator),
2467 ownStateAllocator_(0),
2473 missingDependents_(),
2475 flags_(kValidateDefaultFlags),
2478 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator");
2489 const SchemaDocumentType& schemaDocument,
2490 OutputHandler& outputHandler,
2491 StateAllocator* allocator = 0,
2492 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2493 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2495 schemaDocument_(&schemaDocument),
2496 root_(schemaDocument.GetRoot()),
2497 stateAllocator_(allocator),
2498 ownStateAllocator_(0),
2501 outputHandler_(&outputHandler),
2504 missingDependents_(),
2506 flags_(kValidateDefaultFlags),
2509 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (output handler)");
2529 currentError_.SetNull();
2530 missingDependents_.SetNull();
2538 virtual unsigned GetValidateFlags()
const {
2542 virtual bool IsValid()
const {
2543 if (!valid_)
return false;
2544 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return false;
2551 const ValueType&
GetError()
const {
return error_; }
2556 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
2562 if (!
schemaStack_.Empty())
return CurrentContext().invalidKeyword;
2563 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return static_cast<const Ch*
>(GetErrorsString());
2570 if (!
schemaStack_.Empty())
return CurrentContext().invalidCode;
2571 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return kValidateErrors;
2579 return PointerType();
2586 void NotMultipleOf(int64_t actual,
const SValue& expected) {
2589 void NotMultipleOf(uint64_t actual,
const SValue& expected) {
2592 void NotMultipleOf(
double actual,
const SValue& expected) {
2595 void AboveMaximum(int64_t actual,
const SValue& expected,
bool exclusive) {
2597 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2599 void AboveMaximum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2601 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2603 void AboveMaximum(
double actual,
const SValue& expected,
bool exclusive) {
2605 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2607 void BelowMinimum(int64_t actual,
const SValue& expected,
bool exclusive) {
2609 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2611 void BelowMinimum(uint64_t actual,
const SValue& expected,
bool exclusive) {
2613 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2615 void BelowMinimum(
double actual,
const SValue& expected,
bool exclusive) {
2617 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2622 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2626 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
2628 void DoesNotMatch(
const Ch* str,
SizeType length) {
2629 currentError_.SetObject();
2630 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2634 void DisallowedItem(
SizeType index) {
2635 currentError_.SetObject();
2636 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
2641 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2645 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2649 duplicates.PushBack(index1, GetStateAllocator());
2650 duplicates.PushBack(index2, GetStateAllocator());
2651 currentError_.SetObject();
2652 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2658 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2662 ValueType(actualCount).Move(), SValue(expectedCount).Move());
2664 void StartMissingProperties() {
2665 currentError_.SetArray();
2667 void AddMissingProperty(
const SValue& name) {
2668 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
2670 bool EndMissingProperties() {
2671 if (currentError_.Empty())
2674 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2675 currentError_ = error;
2679 void PropertyViolations(ISchemaValidator** subvalidators,
SizeType count) {
2680 for (
SizeType i = 0; i < count; ++i)
2683 void DisallowedProperty(
const Ch* name,
SizeType length) {
2684 currentError_.SetObject();
2685 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
2689 void StartDependencyErrors() {
2690 currentError_.SetObject();
2692 void StartMissingDependentProperties() {
2693 missingDependents_.SetArray();
2695 void AddMissingDependentProperty(
const SValue& targetName) {
2696 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2698 void EndMissingDependentProperties(
const SValue& sourceName) {
2699 if (!missingDependents_.Empty()) {
2703 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2704 AddErrorCode(error, code);
2705 AddErrorInstanceLocation(error,
false);
2708 AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &
GetInvalidSchemaPointer().GetAllocator()));
2710 wrapper.AddMember(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2711 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2714 void AddDependencySchemaError(
const SValue& sourceName, ISchemaValidator* subvalidator) {
2715 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2718 bool EndDependencyErrors() {
2719 if (currentError_.ObjectEmpty())
2722 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2723 currentError_ = error;
2729 currentError_.SetObject();
2730 AddCurrentError(code);
2732 void StartDisallowedType() {
2733 currentError_.SetArray();
2735 void AddExpectedType(
const typename SchemaType::ValueType& expectedType) {
2736 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2738 void EndDisallowedType(
const typename SchemaType::ValueType& actualType) {
2740 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2741 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2742 currentError_ = error;
2745 void NotAllOf(ISchemaValidator** subvalidators,
SizeType count) {
2752 void NoneOf(ISchemaValidator** subvalidators,
SizeType count) {
2755 void NotOneOf(ISchemaValidator** subvalidators,
SizeType count) {
2760 matches.PushBack(index1, GetStateAllocator());
2761 matches.PushBack(index2, GetStateAllocator());
2762 currentError_.SetObject();
2763 currentError_.AddMember(GetMatchesString(), matches, GetStateAllocator());
2767 currentError_.SetObject();
2770 void DisallowedWhenWriting() {
2771 currentError_.SetObject();
2774 void DisallowedWhenReading() {
2775 currentError_.SetObject();
2779#define RAPIDJSON_STRING_(name, ...) \
2780 static const StringRefType& Get##name##String() {\
2781 static const Ch s[] = { __VA_ARGS__, '\0' };\
2782 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2786 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2787 RAPIDJSON_STRING_(SchemaRef,
's',
'c',
'h',
'e',
'm',
'a',
'R',
'e',
'f')
2788 RAPIDJSON_STRING_(Expected,
'e',
'x',
'p',
'e',
'c',
't',
'e',
'd')
2789 RAPIDJSON_STRING_(Actual,
'a',
'c',
't',
'u',
'a',
'l')
2790 RAPIDJSON_STRING_(Disallowed,
'd',
'i',
's',
'a',
'l',
'l',
'o',
'w',
'e',
'd')
2791 RAPIDJSON_STRING_(Missing,
'm',
'i',
's',
's',
'i',
'n',
'g')
2792 RAPIDJSON_STRING_(Errors,
'e',
'r',
'r',
'o',
'r',
's')
2793 RAPIDJSON_STRING_(ErrorCode,
'e',
'r',
'r',
'o',
'r',
'C',
'o',
'd',
'e')
2794 RAPIDJSON_STRING_(ErrorMessage,
'e',
'r',
'r',
'o',
'r',
'M',
'e',
's',
's',
'a',
'g',
'e')
2795 RAPIDJSON_STRING_(Duplicates,
'd',
'u',
'p',
'l',
'i',
'c',
'a',
't',
'e',
's')
2796 RAPIDJSON_STRING_(Matches,
'm',
'a',
't',
'c',
'h',
'e',
's')
2798#undef RAPIDJSON_STRING_
2800#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2801 if (!valid_) return false; \
2802 if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2803 *documentStack_.template Push<Ch>() = '\0';\
2804 documentStack_.template Pop<Ch>(1);\
2805 RAPIDJSON_SCHEMA_PRINT(InvalidDocument, documentStack_.template Bottom<Ch>());\
2810#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2811 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2812 if (context->hasher)\
2813 static_cast<HasherType*>(context->hasher)->method arg2;\
2814 if (context->validators)\
2815 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2816 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2817 if (context->patternPropertiesValidators)\
2818 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2819 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2822#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2823 valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2826#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2827 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2828 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2829 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2831 bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
2832 bool Bool(
bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
2833 bool Int(
int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
2834 bool Uint(
unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
2835 bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
2836 bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
2837 bool Double(
double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
2838 bool RawNumber(
const Ch* str,
SizeType length,
bool copy)
2839 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2840 bool String(
const Ch* str,
SizeType length,
bool copy)
2841 { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2843 bool StartObject() {
2844 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartObject");
2845 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2846 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
2847 valid_ = !outputHandler_ || outputHandler_->StartObject();
2851 bool Key(
const Ch* str,
SizeType len,
bool copy) {
2852 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::Key", str);
2853 if (!valid_)
return false;
2854 AppendToken(str, len);
2855 if (!CurrentSchema().Key(CurrentContext(), str, len, copy) && !GetContinueOnErrors()) {
2859 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
2860 valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
2864 bool EndObject(
SizeType memberCount) {
2865 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndObject");
2866 if (!valid_)
return false;
2867 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
2868 if (!CurrentSchema().EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors()) {
2872 RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
2876 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::StartArray");
2877 RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2878 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
2879 valid_ = !outputHandler_ || outputHandler_->StartArray();
2883 bool EndArray(
SizeType elementCount) {
2884 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndArray");
2885 if (!valid_)
return false;
2886 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
2887 if (!CurrentSchema().EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors()) {
2891 RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
2894#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2895#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2896#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2899 virtual ISchemaValidator* CreateSchemaValidator(
const SchemaType& root,
const bool inheritContinueOnErrors) {
2904 &GetStateAllocator());
2905 sv->SetValidateFlags(inheritContinueOnErrors ? GetValidateFlags() : GetValidateFlags() & ~
static_cast<unsigned>(kValidateContinueOnErrorFlag));
2909 virtual void DestroySchemaValidator(ISchemaValidator* validator) {
2912 StateAllocator::Free(v);
2915 virtual void* CreateHasher() {
2916 return new (GetStateAllocator().Malloc(
sizeof(HasherType))) HasherType(&GetStateAllocator());
2919 virtual uint64_t GetHashCode(
void* hasher) {
2920 return static_cast<HasherType*
>(hasher)->GetHashCode();
2923 virtual void DestroryHasher(
void* hasher) {
2924 HasherType* h =
static_cast<HasherType*
>(hasher);
2926 StateAllocator::Free(h);
2929 virtual void* MallocState(
size_t size) {
2930 return GetStateAllocator().Malloc(size);
2933 virtual void FreeState(
void* p) {
2934 StateAllocator::Free(p);
2939 typedef typename SchemaType::Context Context;
2940 typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
2941 typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
2944 const SchemaDocumentType& schemaDocument,
2945 const SchemaType& root,
2946 const char* basePath,
size_t basePathSize,
2948 StateAllocator* allocator = 0,
2949 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2950 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2952 schemaDocument_(&schemaDocument),
2954 stateAllocator_(allocator),
2955 ownStateAllocator_(0),
2961 missingDependents_(),
2963 flags_(kValidateDefaultFlags),
2966 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::GenericSchemaValidator (internal)", basePath && basePathSize ? basePath :
"");
2967 if (basePath && basePathSize)
2968 memcpy(
documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2971 StateAllocator& GetStateAllocator() {
2972 if (!stateAllocator_)
2973 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2974 return *stateAllocator_;
2977 bool GetContinueOnErrors()
const {
2978 return flags_ & kValidateContinueOnErrorFlag;
2982 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::BeginValue");
2986 if (CurrentContext().inArray)
2987 internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(
documentStack_, CurrentContext().arrayElementIndex);
2989 if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2992 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2993 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2994 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2995 bool valueUniqueness = CurrentContext().valueUniqueness;
2997 PushSchema(*CurrentContext().valueSchema);
3000 CurrentContext().objectPatternValidatorType = patternValidatorType;
3001 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
3002 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
3003 va =
static_cast<ISchemaValidator**
>(MallocState(
sizeof(ISchemaValidator*) * count));
3004 std::memset(va, 0,
sizeof(ISchemaValidator*) * count);
3005 for (
SizeType i = 0; i < count; i++)
3006 va[validatorCount++] = CreateSchemaValidator(*sa[i],
true);
3009 CurrentContext().arrayUniqueness = valueUniqueness;
3015 RAPIDJSON_SCHEMA_PRINT(Method,
"GenericSchemaValidator::EndValue");
3016 if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
3019 GenericStringBuffer<EncodingType> sb;
3020 schemaDocument_->GetPointer(&CurrentSchema()).StringifyUriFragment(sb);
3023 RAPIDJSON_SCHEMA_PRINT(ValidatorPointers, sb.GetString(),
documentStack_.template Bottom<Ch>(), depth_);
3024 void* hasher = CurrentContext().hasher;
3025 uint64_t h = hasher && CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(hasher)->GetHashCode() : 0;
3030 Context& context = CurrentContext();
3032 if (hasher && context.valueUniqueness) {
3033 HashCodeArray* a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
3035 CurrentContext().arrayElementHashCodes = a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
3037 if (itr->GetUint64() == h) {
3038 DuplicateItems(
static_cast<SizeType>(itr - a->Begin()), a->Size());
3040 if (GetContinueOnErrors()) {
3041 a->PushBack(h, GetStateAllocator());
3046 a->PushBack(h, GetStateAllocator());
3057 void AppendToken(
const Ch* str,
SizeType len) {
3061 if (str[i] ==
'~') {
3065 else if (str[i] ==
'/') {
3074 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (
schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema, flags_); }
3076 RAPIDJSON_FORCEINLINE
void PopSchema() {
3078 if (HashCodeArray* a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
3079 a->~HashCodeArray();
3080 StateAllocator::Free(a);
3085 void AddErrorInstanceLocation(ValueType& result,
bool parent) {
3086 GenericStringBuffer<EncodingType> sb;
3088 ((parent && instancePointer.GetTokenCount() > 0)
3089 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
3090 : instancePointer).StringifyUriFragment(sb);
3091 ValueType instanceRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
3092 GetStateAllocator());
3093 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
3096 void AddErrorSchemaLocation(ValueType& result, PointerType schema = PointerType()) {
3097 GenericStringBuffer<EncodingType> sb;
3098 SizeType len = CurrentSchema().GetURI().GetStringLength();
3099 if (len) memcpy(sb.Push(len), CurrentSchema().GetURI().GetString(), len *
sizeof(Ch));
3100 if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
3102 ValueType schemaRef(sb.GetString(),
static_cast<SizeType>(sb.
GetSize() /
sizeof(Ch)),
3103 GetStateAllocator());
3104 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
3108 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
3111 void AddError(ValueType& keyword, ValueType& error) {
3113 if (member == error_.MemberEnd())
3114 error_.AddMember(keyword, error, GetStateAllocator());
3116 if (member->value.IsObject()) {
3118 errors.PushBack(member->value, GetStateAllocator());
3119 member->value = errors;
3121 member->value.PushBack(error, GetStateAllocator());
3126 AddErrorCode(currentError_, code);
3127 AddErrorInstanceLocation(currentError_, parent);
3128 AddErrorSchemaLocation(currentError_);
3129 AddError(ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(),
false).Move(), currentError_);
3132 void MergeError(ValueType& other) {
3134 AddError(it->name, it->value);
3138 void AddNumberError(
const ValidateErrorCode code, ValueType& actual,
const SValue& expected,
3139 const typename SchemaType::ValueType& (*exclusive)() = 0) {
3140 currentError_.SetObject();
3141 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
3142 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
3144 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
3145 AddCurrentError(code);
3149 ISchemaValidator** subvalidators,
SizeType count) {
3151 for (
SizeType i = 0; i < count; ++i)
3152 errors.PushBack(
static_cast<GenericSchemaValidator*
>(subvalidators[i])->GetError(), GetStateAllocator());
3153 currentError_.SetObject();
3154 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
3155 AddCurrentError(code);
3158 const SchemaType& CurrentSchema()
const {
return *
schemaStack_.template Top<Context>()->schema; }
3159 Context& CurrentContext() {
return *
schemaStack_.template Top<Context>(); }
3160 const Context& CurrentContext()
const {
return *
schemaStack_.template Top<Context>(); }
3162 static const size_t kDefaultSchemaStackCapacity = 1024;
3163 static const size_t kDefaultDocumentStackCapacity = 256;
3164 const SchemaDocumentType* schemaDocument_;
3165 const SchemaType& root_;
3166 StateAllocator* stateAllocator_;
3167 StateAllocator* ownStateAllocator_;
3170 OutputHandler* outputHandler_;
3172 ValueType currentError_;
3173 ValueType missingDependents_;