15 #ifndef RAPIDJSON_SCHEMA_H_
16 #define RAPIDJSON_SCHEMA_H_
25 #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
26 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
28 #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
31 #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
32 #define RAPIDJSON_SCHEMA_USE_STDREGEX 1
34 #define RAPIDJSON_SCHEMA_USE_STDREGEX 0
37 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
39 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
43 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
44 #define RAPIDJSON_SCHEMA_HAS_REGEX 1
46 #define RAPIDJSON_SCHEMA_HAS_REGEX 0
49 #ifndef RAPIDJSON_SCHEMA_VERBOSE
50 #define RAPIDJSON_SCHEMA_VERBOSE 0
53 #if RAPIDJSON_SCHEMA_VERBOSE
60 RAPIDJSON_DIAG_OFF(effc++)
64 RAPIDJSON_DIAG_OFF(weak-vtables)
65 RAPIDJSON_DIAG_OFF(exit-time-destructors)
66 RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
67 RAPIDJSON_DIAG_OFF(variadic-macros)
68 #elif defined(_MSC_VER)
69 RAPIDJSON_DIAG_OFF(4512)
77 #if RAPIDJSON_SCHEMA_VERBOSE
81 inline void PrintInvalidKeyword(
const char* keyword) {
82 printf(
"Fail keyword: %s\n", keyword);
85 inline void PrintInvalidKeyword(
const wchar_t* keyword) {
86 wprintf(L
"Fail keyword: %ls\n", keyword);
89 inline void PrintInvalidDocument(
const char*
document) {
90 printf(
"Fail document: %s\n\n",
document);
93 inline void PrintInvalidDocument(
const wchar_t*
document) {
94 wprintf(L
"Fail document: %ls\n\n",
document);
97 inline void PrintValidatorPointers(
unsigned depth,
const char* s,
const char* d) {
98 printf(
"S: %*s%s\nD: %*s%s\n\n", depth * 4,
" ", s, depth * 4,
" ", d);
101 inline void PrintValidatorPointers(
unsigned depth,
const wchar_t* s,
const wchar_t* d) {
102 wprintf(L
"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L
" ", s, depth * 4, L
" ", d);
107 #endif // RAPIDJSON_SCHEMA_VERBOSE
112 #if RAPIDJSON_SCHEMA_VERBOSE
113 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
115 #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
118 #define RAPIDJSON_INVALID_KEYWORD_RETURN(code)\
119 RAPIDJSON_MULTILINEMACRO_BEGIN\
120 context.invalidCode = code;\
121 context.invalidKeyword = SchemaType::GetValidateErrorKeyword(code).GetString();\
122 RAPIDJSON_INVALID_KEYWORD_VERBOSE(context.invalidKeyword);\
124 RAPIDJSON_MULTILINEMACRO_END
135 #ifndef RAPIDJSON_VALIDATE_DEFAULT_FLAGS
136 #define RAPIDJSON_VALIDATE_DEFAULT_FLAGS kValidateNoFlags
151 template <
typename ValueType,
typename Allocator>
156 template <
typename SchemaDocumentType>
165 virtual bool IsValid()
const = 0;
173 template <
typename SchemaType>
189 template <
typename SchemaType>
192 typedef typename SchemaType::Ch
Ch;
193 typedef typename SchemaType::SValue
SValue;
233 virtual void AddExpectedType(
const typename SchemaType::ValueType& expectedType) = 0;
234 virtual void EndDisallowedType(
const typename SchemaType::ValueType& actualType) = 0;
246 template<
typename Encoding,
typename Allocator>
249 typedef typename Encoding::Ch
Ch;
255 bool Int(
int i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
256 bool Uint(
unsigned u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
257 bool Int64(
int64_t i) { Number n; n.u.i = i; n.d =
static_cast<double>(i);
return WriteNumber(n); }
258 bool Uint64(
uint64_t u) { Number n; n.u.u = u; n.d =
static_cast<double>(u);
return WriteNumber(n); }
261 if (d < 0) n.u.i =
static_cast<int64_t>(d);
262 else n.u.u =
static_cast<uint64_t>(d);
264 return WriteNumber(n);
281 uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
282 for (
SizeType i = 0; i < memberCount; i++)
283 h ^= Hash(kv[i * 2], kv[i * 2 + 1]);
284 *stack_.template Push<uint64_t>() = h;
291 uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
292 for (
SizeType i = 0; i < elementCount; i++)
294 *stack_.template Push<uint64_t>() = h;
302 return *stack_.template Top<uint64_t>();
306 static const size_t kDefaultSize = 256;
315 bool WriteType(
Type type) {
return WriteBuffer(type, 0, 0); }
317 bool WriteNumber(
const Number& n) {
return WriteBuffer(
kNumberType, &n,
sizeof(n)); }
319 bool WriteBuffer(
Type type,
const void* data,
size_t len) {
322 const unsigned char* d =
static_cast<const unsigned char*
>(data);
323 for (
size_t i = 0; i < len; i++)
325 *stack_.template Push<uint64_t>() = h;
336 Stack<Allocator> stack_;
342 template <
typename SchemaDocumentType>
348 typedef typename ValueType::Ch
Ch;
424 template <
typename SchemaDocumentType>
427 typedef typename SchemaDocumentType::ValueType
ValueType;
431 typedef typename EncodingType::Ch
Ch;
444 typeless_(schemaDocument->GetTypeless()),
448 type_((1 << kTotalSchemaType) - 1),
450 notValidatorIndex_(),
452 additionalPropertiesSchema_(),
453 patternProperties_(),
454 patternPropertyCount_(),
458 additionalProperties_(true),
461 hasSchemaDependencies_(),
462 additionalItemsSchema_(),
468 additionalItems_(true),
473 exclusiveMinimum_(false),
474 exclusiveMaximum_(false),
475 defaultValueLength_(0)
477 typedef typename ValueType::ConstValueIterator ConstValueIterator;
478 typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
484 if (
this != typeless_) {
485 typedef typename SchemaDocumentType::SchemaEntry SchemaEntry;
486 SchemaEntry *entry = schemaDocument->schemaMap_.template Push<SchemaEntry>();
487 new (entry) SchemaEntry(pointer_,
this,
true, allocator_);
488 schemaDocument->AddSchemaRefs(
this);
491 if (!
value.IsObject())
506 else if (v->IsArray())
507 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
512 if (v->IsArray() && v->Size() > 0) {
513 enum_ =
static_cast<uint64_t*
>(allocator_->Malloc(
sizeof(
uint64_t) * v->Size()));
514 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
516 char buffer[256u + 24];
518 EnumHasherType h(&hasherAllocator, 256);
520 enum_[enumCount_++] = h.GetHashCode();
525 if (schemaDocument) {
526 AssignIfExist(allOf_, *schemaDocument, p,
value, GetAllOfString(),
document);
527 AssignIfExist(anyOf_, *schemaDocument, p,
value, GetAnyOfString(),
document);
528 AssignIfExist(oneOf_, *schemaDocument, p,
value, GetOneOfString(),
document);
531 schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v,
document, id_);
532 notValidatorIndex_ = validatorCount_;
539 const ValueType* properties = GetMember(
value, GetPropertiesString());
540 const ValueType* required = GetMember(
value, GetRequiredString());
541 const ValueType* dependencies = GetMember(
value, GetDependenciesString());
546 if (properties && properties->IsObject())
547 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
548 AddUniqueElement(allProperties, itr->name);
550 if (required && required->IsArray())
551 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
553 AddUniqueElement(allProperties, *itr);
555 if (dependencies && dependencies->IsObject())
556 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
557 AddUniqueElement(allProperties, itr->name);
558 if (itr->value.IsArray())
559 for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
561 AddUniqueElement(allProperties, *i);
564 if (allProperties.Size() > 0) {
565 propertyCount_ = allProperties.Size();
566 properties_ =
static_cast<Property*
>(allocator_->Malloc(
sizeof(Property) * propertyCount_));
567 for (
SizeType i = 0; i < propertyCount_; i++) {
568 new (&properties_[i]) Property();
569 properties_[i].name = allProperties[i];
570 properties_[i].schema = typeless_;
575 if (properties && properties->IsObject()) {
576 PointerType q = p.Append(GetPropertiesString(), allocator_);
577 for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
579 if (FindPropertyIndex(itr->name, &index))
580 schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value,
document, id_);
584 if (
const ValueType* v = GetMember(
value, GetPatternPropertiesString())) {
585 PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
586 patternProperties_ =
static_cast<PatternProperty*
>(allocator_->Malloc(
sizeof(PatternProperty) * v->MemberCount()));
587 patternPropertyCount_ = 0;
589 for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
590 new (&patternProperties_[patternPropertyCount_]) PatternProperty();
591 patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
592 schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value,
document, id_);
593 patternPropertyCount_++;
597 if (required && required->IsArray())
598 for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
599 if (itr->IsString()) {
601 if (FindPropertyIndex(*itr, &index)) {
602 properties_[index].required =
true;
607 if (dependencies && dependencies->IsObject()) {
608 PointerType q = p.Append(GetDependenciesString(), allocator_);
609 hasDependencies_ =
true;
610 for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
612 if (FindPropertyIndex(itr->name, &sourceIndex)) {
613 if (itr->value.IsArray()) {
614 properties_[sourceIndex].dependencies =
static_cast<bool*
>(allocator_->Malloc(
sizeof(
bool) * propertyCount_));
615 std::memset(properties_[sourceIndex].dependencies, 0,
sizeof(
bool)* propertyCount_);
616 for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
618 if (FindPropertyIndex(*targetItr, &targetIndex))
619 properties_[sourceIndex].dependencies[targetIndex] =
true;
622 else if (itr->value.IsObject()) {
623 hasSchemaDependencies_ =
true;
624 schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value,
document, id_);
625 properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
632 if (
const ValueType* v = GetMember(
value, GetAdditionalPropertiesString())) {
634 additionalProperties_ = v->GetBool();
635 else if (v->IsObject())
636 schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v,
document, id_);
639 AssignIfExist(minProperties_,
value, GetMinPropertiesString());
640 AssignIfExist(maxProperties_,
value, GetMaxPropertiesString());
644 PointerType q = p.Append(GetItemsString(), allocator_);
646 schemaDocument->CreateSchema(&itemsList_, q, *v,
document, id_);
647 else if (v->IsArray()) {
648 itemsTuple_ =
static_cast<const Schema**
>(allocator_->Malloc(
sizeof(
const Schema*) * v->Size()));
650 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
651 schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr,
document, id_);
655 AssignIfExist(minItems_,
value, GetMinItemsString());
656 AssignIfExist(maxItems_,
value, GetMaxItemsString());
658 if (
const ValueType* v = GetMember(
value, GetAdditionalItemsString())) {
660 additionalItems_ = v->GetBool();
661 else if (v->IsObject())
662 schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v,
document, id_);
665 AssignIfExist(uniqueItems_,
value, GetUniqueItemsString());
668 AssignIfExist(minLength_,
value, GetMinLengthString());
669 AssignIfExist(maxLength_,
value, GetMaxLengthString());
672 pattern_ = CreatePattern(*v);
677 minimum_.CopyFrom(*v, *allocator_);
681 maximum_.CopyFrom(*v, *allocator_);
683 AssignIfExist(exclusiveMinimum_,
value, GetExclusiveMinimumString());
684 AssignIfExist(exclusiveMaximum_,
value, GetExclusiveMaximumString());
687 if (v->IsNumber() && v->GetDouble() > 0.0)
688 multipleOf_.CopyFrom(*v, *allocator_);
691 if (
const ValueType* v = GetMember(
value, GetDefaultValueString()))
693 defaultValueLength_ = v->GetStringLength();
700 for (
SizeType i = 0; i < propertyCount_; i++)
701 properties_[i].~Property();
704 if (patternProperties_) {
705 for (
SizeType i = 0; i < patternPropertyCount_; i++)
706 patternProperties_[i].~PatternProperty();
710 #if RAPIDJSON_SCHEMA_HAS_REGEX
712 pattern_->~RegexType();
737 else if (itemsTuple_) {
740 else if (additionalItemsSchema_)
742 else if (additionalItems_)
764 bool otherValid =
false;
769 bool patternValid =
true;
770 for (
SizeType i = 0; i < count; i++)
772 patternValid =
false;
783 if (!patternValid || !otherValid) {
788 else if (!patternValid && !otherValid) {
795 if (enum_ && context.
hasher) {
797 for (
SizeType i = 0; i < enumCount_; i++)
808 for (
SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
814 if (anyOf_.schemas) {
815 for (
SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
823 if (oneOf_.schemas) {
824 bool oneValid =
false;
825 for (
SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
849 if (!(type_ & (1 << kNullSchemaType))) {
850 DisallowedType(context, GetNullString());
853 return CreateParallelValidator(context);
857 if (!(type_ & (1 << kBooleanSchemaType))) {
858 DisallowedType(context, GetBooleanString());
861 return CreateParallelValidator(context);
865 if (!CheckInt(context, i))
867 return CreateParallelValidator(context);
871 if (!CheckUint(context, u))
873 return CreateParallelValidator(context);
877 if (!CheckInt(context, i))
879 return CreateParallelValidator(context);
883 if (!CheckUint(context, u))
885 return CreateParallelValidator(context);
889 if (!(type_ & (1 << kNumberSchemaType))) {
890 DisallowedType(context, GetNumberString());
894 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
897 if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
900 if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
903 return CreateParallelValidator(context);
907 if (!(type_ & (1 << kStringSchemaType))) {
908 DisallowedType(context, GetStringString());
912 if (minLength_ != 0 || maxLength_ !=
SizeType(~0)) {
914 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
915 if (count < minLength_) {
919 if (count > maxLength_) {
926 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
931 return CreateParallelValidator(context);
935 if (!(type_ & (1 << kObjectSchemaType))) {
936 DisallowedType(context, GetObjectString());
940 if (hasDependencies_ || hasRequired_) {
942 std::memset(context.
propertyExist, 0,
sizeof(
bool) * propertyCount_);
945 if (patternProperties_) {
946 SizeType count = patternPropertyCount_ + 1;
952 return CreateParallelValidator(context);
956 if (patternProperties_) {
958 for (
SizeType i = 0; i < patternPropertyCount_; i++)
959 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
966 if (FindPropertyIndex(
ValueType(str, len).Move(), &index)) {
981 if (additionalPropertiesSchema_) {
991 else if (additionalProperties_) {
1009 for (
SizeType index = 0; index < propertyCount_; index++)
1010 if (properties_[index].required && !context.
propertyExist[index])
1011 if (properties_[index].schema->defaultValueLength_ == 0 )
1017 if (memberCount < minProperties_) {
1022 if (memberCount > maxProperties_) {
1027 if (hasDependencies_) {
1029 for (
SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
1030 const Property&
source = properties_[sourceIndex];
1032 if (
source.dependencies) {
1034 for (
SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
1039 else if (
source.dependenciesSchema) {
1041 if (!dependenciesValidator->
IsValid())
1057 if (!(type_ & (1 << kArraySchemaType))) {
1058 DisallowedType(context, GetArrayString());
1062 return CreateParallelValidator(context);
1068 if (elementCount < minItems_) {
1073 if (elementCount > maxItems_) {
1082 switch (validateErrorCode) {
1114 default:
return GetNullString();
1120 #define RAPIDJSON_STRING_(name, ...) \
1121 static const ValueType& Get##name##String() {\
1122 static const Ch s[] = { __VA_ARGS__, '\0' };\
1123 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
1140 RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1142 RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
1143 RAPIDJSON_STRING_(PatternProperties, 'p', '
a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1144 RAPIDJSON_STRING_(AdditionalProperties, '
a', 'd', 'd', 'i', 't', 'i', 'o', 'n', '
a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1145 RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1146 RAPIDJSON_STRING_(MaxProperties, 'm', '
a', '
x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
1150 RAPIDJSON_STRING_(AdditionalItems, '
a', 'd', 'd', 'i', 't', 'i', 'o', 'n', '
a', 'l', 'I', 't', 'e', 'm', 's')
1151 RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
1157 RAPIDJSON_STRING_(ExclusiveMinimum, 'e', '
x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
1158 RAPIDJSON_STRING_(ExclusiveMaximum, 'e', '
x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', '
a', '
x', 'i', 'm', 'u', 'm')
1159 RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1171 #undef RAPIDJSON_STRING_
1174 enum SchemaValueType {
1185 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1187 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1188 typedef std::basic_regex<Ch> RegexType;
1190 typedef char RegexType;
1193 struct SchemaArray {
1194 SchemaArray() : schemas(), count() {}
1201 template <
typename V1,
typename V2>
1202 void AddUniqueElement(V1&
a,
const V2& v) {
1203 for (
typename V1::ConstValueIterator itr =
a.Begin(); itr !=
a.End(); ++itr)
1206 V1 c(v, *allocator_);
1207 a.PushBack(c, *allocator_);
1211 typename ValueType::ConstMemberIterator itr =
value.FindMember(
name);
1212 return itr !=
value.MemberEnd() ? &(itr->value) : 0;
1223 if (v->IsUint64() && v->GetUint64() <=
SizeType(~0))
1224 out =
static_cast<SizeType>(v->GetUint64());
1229 if (v->IsArray() && v->Size() > 0) {
1231 out.count = v->Size();
1232 out.schemas =
static_cast<const Schema**
>(allocator_->Malloc(out.count *
sizeof(
const Schema*)));
1233 memset(out.schemas, 0,
sizeof(
Schema*)* out.count);
1234 for (
SizeType i = 0; i < out.count; i++)
1235 schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i],
document, id_);
1236 out.begin = validatorCount_;
1237 validatorCount_ += out.count;
1242 #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
1243 template <
typename ValueType>
1245 if (
value.IsString()) {
1246 RegexType* r =
new (allocator_->Malloc(
sizeof(RegexType))) RegexType(
value.GetString(), allocator_);
1247 if (!r->IsValid()) {
1257 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType) {
1258 GenericRegexSearch<RegexType> rs(*pattern);
1259 return rs.Search(str);
1261 #elif RAPIDJSON_SCHEMA_USE_STDREGEX
1262 template <
typename ValueType>
1264 if (
value.IsString()) {
1265 RegexType *r =
static_cast<RegexType*
>(allocator_->Malloc(
sizeof(RegexType)));
1267 return new (r) RegexType(
value.GetString(), std::size_t(
value.GetStringLength()), std::regex_constants::ECMAScript);
1269 catch (
const std::regex_error&) {
1276 static bool IsPatternMatch(
const RegexType* pattern,
const Ch *str,
SizeType length) {
1277 std::match_results<const Ch*> r;
1278 return std::regex_search(str, str + length, r, *pattern);
1281 template <
typename ValueType>
1282 RegexType* CreatePattern(
const ValueType&) {
return 0; }
1284 static bool IsPatternMatch(
const RegexType*,
const Ch *,
SizeType) {
return true; }
1285 #endif // RAPIDJSON_SCHEMA_USE_STDREGEX
1288 if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
1289 else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
1290 else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
1291 else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
1292 else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
1293 else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
1294 else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
1297 bool CreateParallelValidator(
Context& context)
const {
1298 if (enum_ || context.arrayUniqueness)
1299 context.hasher = context.factory.CreateHasher();
1301 if (validatorCount_) {
1303 context.validators =
static_cast<ISchemaValidator**
>(context.factory.MallocState(
sizeof(ISchemaValidator*) * validatorCount_));
1304 context.validatorCount = validatorCount_;
1308 CreateSchemaValidators(context, allOf_,
false);
1311 CreateSchemaValidators(context, anyOf_,
false);
1314 CreateSchemaValidators(context, oneOf_,
false);
1317 context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_,
false);
1319 if (hasSchemaDependencies_) {
1320 for (
SizeType i = 0; i < propertyCount_; i++)
1321 if (properties_[i].dependenciesSchema)
1322 context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema,
false);
1329 void CreateSchemaValidators(
Context& context,
const SchemaArray& schemas,
const bool inheritContinueOnErrors)
const {
1330 for (
SizeType i = 0; i < schemas.count; i++)
1331 context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i], inheritContinueOnErrors);
1337 const Ch* str =
name.GetString();
1338 for (
SizeType index = 0; index < propertyCount_; index++)
1339 if (properties_[index].
name.GetStringLength() == len &&
1340 (std::memcmp(properties_[index].name.GetString(), str,
sizeof(
Ch) * len) == 0))
1349 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1350 DisallowedType(context, GetIntegerString());
1354 if (!minimum_.IsNull()) {
1355 if (minimum_.IsInt64()) {
1356 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1357 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1361 else if (minimum_.IsUint64()) {
1362 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1365 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1369 if (!maximum_.IsNull()) {
1370 if (maximum_.IsInt64()) {
1371 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1372 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1376 else if (maximum_.IsUint64()) { }
1378 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1382 if (!multipleOf_.IsNull()) {
1383 if (multipleOf_.IsUint64()) {
1384 if (
static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1385 context.error_handler.NotMultipleOf(i, multipleOf_);
1389 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1397 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1398 DisallowedType(context, GetIntegerString());
1402 if (!minimum_.IsNull()) {
1403 if (minimum_.IsUint64()) {
1404 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1405 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
1409 else if (minimum_.IsInt64())
1411 else if (!CheckDoubleMinimum(context,
static_cast<double>(i)))
1415 if (!maximum_.IsNull()) {
1416 if (maximum_.IsUint64()) {
1417 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1418 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1422 else if (maximum_.IsInt64()) {
1423 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
1426 else if (!CheckDoubleMaximum(context,
static_cast<double>(i)))
1430 if (!multipleOf_.IsNull()) {
1431 if (multipleOf_.IsUint64()) {
1432 if (i % multipleOf_.GetUint64() != 0) {
1433 context.error_handler.NotMultipleOf(i, multipleOf_);
1437 else if (!CheckDoubleMultipleOf(context,
static_cast<double>(i)))
1444 bool CheckDoubleMinimum(
Context& context,
double d)
const {
1445 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1446 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
1452 bool CheckDoubleMaximum(
Context& context,
double d)
const {
1453 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1454 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
1460 bool CheckDoubleMultipleOf(
Context& context,
double d)
const {
1461 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
1462 double q = std::floor(
a / b);
1463 double r =
a - q * b;
1465 context.error_handler.NotMultipleOf(d, multipleOf_);
1473 eh.StartDisallowedType();
1475 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1476 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1477 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1478 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1479 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1481 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1482 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1484 eh.EndDisallowedType(actualType);
1488 Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
1493 SizeType dependenciesValidatorIndex;
1498 struct PatternProperty {
1499 PatternProperty() : schema(), pattern() {}
1500 ~PatternProperty() {
1502 pattern->~RegexType();
1525 Property* properties_;
1526 const SchemaType* additionalPropertiesSchema_;
1527 PatternProperty* patternProperties_;
1532 bool additionalProperties_;
1533 bool hasDependencies_;
1535 bool hasSchemaDependencies_;
1543 bool additionalItems_;
1546 RegexType* pattern_;
1553 bool exclusiveMinimum_;
1554 bool exclusiveMaximum_;
1559 template<
typename Stack,
typename Ch>
1562 *documentStack.template Push<Ch>() =
'/';
1564 size_t length =
static_cast<size_t>((
sizeof(
SizeType) == 4 ?
u32toa(index, buffer) :
u64toa(index, buffer)) - buffer);
1565 for (
size_t i = 0; i < length; i++)
1566 *documentStack.template Push<Ch>() =
static_cast<Ch
>(buffer[i]);
1571 template <
typename Stack>
1575 char *buffer = documentStack.template Push<char>(1 + 10);
1578 documentStack.template Pop<char>(
static_cast<size_t>(10 - (end - buffer)));
1581 char *buffer = documentStack.template Push<char>(1 + 20);
1584 documentStack.template Pop<char>(
static_cast<size_t>(20 - (end - buffer)));
1594 template <
typename SchemaDocumentType>
1597 typedef typename SchemaDocumentType::Ch
Ch;
1618 template <
typename ValueT,
typename Allocator = CrtAllocator>
1625 typedef typename EncodingType::Ch
Ch;
1631 template <
typename,
typename,
typename>
1648 remoteProvider_(remoteProvider),
1653 schemaMap_(
allocator, kInitialSchemaMapSize),
1654 schemaRef_(
allocator, kInitialSchemaRefSize)
1660 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1661 docId_ =
UriType(uri_, allocator_);
1670 if (
pointer.GetTokenCount() == 0) {
1679 schemaRef_.ShrinkToFit();
1682 #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
1685 remoteProvider_(rhs.remoteProvider_),
1686 allocator_(rhs.allocator_),
1687 ownAllocator_(rhs.ownAllocator_),
1689 typeless_(rhs.typeless_),
1690 schemaMap_(std::move(rhs.schemaMap_)),
1691 schemaRef_(std::move(rhs.schemaRef_)),
1692 uri_(std::move(rhs.uri_)),
1695 rhs.remoteProvider_ = 0;
1697 rhs.ownAllocator_ = 0;
1704 while (!schemaMap_.Empty())
1705 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
1708 typeless_->~SchemaType();
1728 struct SchemaEntry {
1732 schema->~SchemaType();
1746 for (
typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
1747 CreateSchemaRecursive(0,
pointer.Append(itr->name, allocator_), itr->value,
document, newid);
1750 for (
SizeType i = 0; i < v.Size(); i++)
1751 CreateSchemaRecursive(0,
pointer.Append(i, allocator_), v[i],
document,
id);
1773 *schema = typeless_;
1774 AddSchemaRefs(typeless_);
1782 typename ValueType::ConstMemberIterator itr = v.FindMember(SchemaType::GetRefString());
1783 if (itr == v.MemberEnd())
1787 new (schemaRef_.template Push<SchemaRefPtr>()) SchemaRefPtr(&
source);
1789 if (itr->value.IsString()) {
1790 SizeType len = itr->value.GetStringLength();
1794 UriType ref =
UriType(itr->value, allocator_).Resolve(scopeId, allocator_);
1801 if (remoteProvider_) {
1803 const Ch* s = ref.GetFragString();
1804 len = ref.GetFragStringLength();
1805 if (len <= 1 || s[1] ==
'/') {
1824 const Ch* s = ref.GetFragString();
1825 len = ref.GetFragStringLength();
1826 if (len <= 1 || s[1] ==
'/') {
1829 if (relPointer.IsValid()) {
1831 if (
const ValueType *pv = relPointer.Get(*base)) {
1834 for (
SizeType i = 0; i < relPointer.GetTokenCount(); i++)
1841 size_t unresolvedTokenIndex;
1842 scopeId =
pointer.GetUri(
document, docId_, &unresolvedTokenIndex, allocator_);
1853 if (
const ValueType *pv = FindId(*base, ref,
pointer,
UriType(ref.GetBaseString(), ref.GetBaseStringLength(), allocator_),
true, basePointer)) {
1859 size_t unresolvedTokenIndex;
1860 scopeId =
pointer.GetUri(
document, docId_, &unresolvedTokenIndex, allocator_);
1872 *schema = typeless_;
1873 AddSchemaRefs(typeless_);
1888 typename ValueType::ConstMemberIterator m = doc.FindMember(SchemaType::GetIdString());
1889 if (m != doc.MemberEnd() && m->value.GetType() ==
kStringType) {
1890 localuri =
UriType(m->value, allocator_).Resolve(baseuri, allocator_);
1893 if (localuri.Match(finduri, full)) {
1899 for (m = doc.MemberBegin(); m != doc.MemberEnd(); ++m) {
1901 resval = FindId(m->value, finduri, resptr, localuri, full, here.Append(m->name.GetString(), m->name.GetStringLength(), allocator_));
1907 for (
typename ValueType::ConstValueIterator v = doc.Begin(); v != doc.End(); ++v) {
1909 resval = FindId(*v, finduri, resptr, localuri, full, here.Append(i, allocator_));
1920 while (!schemaRef_.Empty()) {
1921 SchemaRefPtr *ref = schemaRef_.template Pop<SchemaRefPtr>(1);
1922 SchemaEntry *entry = schemaMap_.template Push<SchemaEntry>();
1923 new (entry) SchemaEntry(**ref, schema,
false, allocator_);
1929 for (
const SchemaRefPtr* ref = schemaRef_.template Bottom<SchemaRefPtr>(); ref != schemaRef_.template End<SchemaRefPtr>(); ++ref)
1936 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1937 if (
pointer == target->pointer)
1938 return target->schema;
1943 for (
const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
1944 if (schema == target->schema)
1945 return target->pointer;
1949 const SchemaType* GetTypeless()
const {
return typeless_; }
1951 static const size_t kInitialSchemaMapSize = 64;
1952 static const size_t kInitialSchemaRefSize = 64;
1986 typename SchemaDocumentType,
1998 typedef typename EncodingType::Ch
Ch;
2010 const SchemaDocumentType& schemaDocument,
2012 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2013 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2015 schemaDocument_(&schemaDocument),
2016 root_(schemaDocument.GetRoot()),
2018 ownStateAllocator_(0),
2019 schemaStack_(
allocator, schemaStackCapacity),
2020 documentStack_(
allocator, documentStackCapacity),
2024 missingDependents_(),
2041 const SchemaDocumentType& schemaDocument,
2042 OutputHandler& outputHandler,
2044 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2045 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2047 schemaDocument_(&schemaDocument),
2048 root_(schemaDocument.GetRoot()),
2050 ownStateAllocator_(0),
2051 schemaStack_(
allocator, schemaStackCapacity),
2052 documentStack_(
allocator, documentStackCapacity),
2053 outputHandler_(&outputHandler),
2056 missingDependents_(),
2073 while (!schemaStack_.Empty())
2075 documentStack_.Clear();
2082 currentError_.SetNull();
2083 missingDependents_.SetNull();
2098 if (!valid_)
return false;
2099 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return false;
2110 return schemaStack_.Empty() ?
PointerType() : CurrentSchema().GetPointer();
2116 if (!schemaStack_.Empty())
return CurrentContext().invalidKeyword;
2117 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return (
const Ch*)GetErrorsString();
2124 if (!schemaStack_.Empty())
return CurrentContext().invalidCode;
2125 if (GetContinueOnErrors() && !error_.ObjectEmpty())
return kValidateErrors;
2132 if (documentStack_.Empty()) {
2136 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() /
sizeof(
Ch));
2151 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2155 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2159 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
2163 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2167 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2171 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
2176 ValueType(str, length, GetStateAllocator()).Move(),
SValue(expected).Move());
2180 ValueType(str, length, GetStateAllocator()).Move(),
SValue(expected).Move());
2183 currentError_.SetObject();
2184 currentError_.AddMember(GetActualString(),
ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
2189 currentError_.SetObject();
2190 currentError_.AddMember(GetDisallowedString(),
ValueType(index).Move(), GetStateAllocator());
2203 duplicates.PushBack(index1, GetStateAllocator());
2204 duplicates.PushBack(index2, GetStateAllocator());
2205 currentError_.SetObject();
2206 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
2219 currentError_.SetArray();
2222 currentError_.PushBack(
ValueType(
name, GetStateAllocator()).Move(), GetStateAllocator());
2225 if (currentError_.Empty())
2228 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
2229 currentError_ = error;
2234 for (
SizeType i = 0; i < count; ++i)
2238 currentError_.SetObject();
2239 currentError_.AddMember(GetDisallowedString(),
ValueType(
name, length, GetStateAllocator()).Move(), GetStateAllocator());
2244 currentError_.SetObject();
2247 missingDependents_.SetArray();
2250 missingDependents_.PushBack(
ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
2253 if (!missingDependents_.Empty()) {
2257 error.AddMember(GetMissingString(), missingDependents_.Move(), GetStateAllocator());
2258 AddErrorCode(error, code);
2259 AddErrorInstanceLocation(error,
false);
2262 AddErrorSchemaLocation(error, schemaRef.Append(sourceName.GetString(), sourceName.GetStringLength(), &
GetInvalidSchemaPointer().GetAllocator()));
2264 wrapper.AddMember(
ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator()).Move(), error, GetStateAllocator());
2265 currentError_.AddMember(
ValueType(sourceName, GetStateAllocator()).Move(), wrapper, GetStateAllocator());
2269 currentError_.AddMember(
ValueType(sourceName, GetStateAllocator()).Move(),
2273 if (currentError_.ObjectEmpty())
2276 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2277 currentError_ = error;
2283 currentError_.SetObject();
2284 AddCurrentError(code);
2287 currentError_.SetArray();
2290 currentError_.PushBack(
ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2294 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2295 error.AddMember(GetActualString(),
ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2296 currentError_ = error;
2313 currentError_.SetObject();
2317 #define RAPIDJSON_STRING_(name, ...) \
2318 static const StringRefType& Get##name##String() {\
2319 static const Ch s[] = { __VA_ARGS__, '\0' };\
2320 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2324 RAPIDJSON_STRING_(InstanceRef,
'i',
'n',
's',
't',
'a',
'n',
'c',
'e',
'R',
'e',
'f')
2328 RAPIDJSON_STRING_(
Disallowed, 'd', 'i', 's', '
a', 'l', 'l', 'o', 'w', 'e', 'd')
2332 RAPIDJSON_STRING_(ErrorMessage, 'e', 'r', 'r', 'o', 'r', 'M', 'e', 's', 's', '
a', 'g', 'e')
2333 RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', '
a', 't', 'e', 's')
2335 #undef RAPIDJSON_STRING_
2337 #if RAPIDJSON_SCHEMA_VERBOSE
2338 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
2339 RAPIDJSON_MULTILINEMACRO_BEGIN\
2340 *documentStack_.template Push<Ch>() = '\0';\
2341 documentStack_.template Pop<Ch>(1);\
2342 internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
2343 RAPIDJSON_MULTILINEMACRO_END
2345 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
2348 #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
2349 if (!valid_) return false; \
2350 if ((!BeginValue() && !GetContinueOnErrors()) || (!CurrentSchema().method arg1 && !GetContinueOnErrors())) {\
2351 RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
2352 return valid_ = false;\
2355 #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
2356 for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
2357 if (context->hasher)\
2358 static_cast<HasherType*>(context->hasher)->method arg2;\
2359 if (context->validators)\
2360 for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
2361 static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
2362 if (context->patternPropertiesValidators)\
2363 for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
2364 static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
2367 #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
2368 valid_ = (EndValue() || GetContinueOnErrors()) && (!outputHandler_ || outputHandler_->method arg2);\
2371 #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2372 RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
2373 RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
2374 RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2391 return valid_ = !outputHandler_ || outputHandler_->StartObject();
2395 if (!valid_)
return false;
2396 AppendToken(str, len);
2397 if (!CurrentSchema().
Key(CurrentContext(), str, len,
copy) && !GetContinueOnErrors())
return valid_ =
false;
2399 return valid_ = !outputHandler_ || outputHandler_->Key(str, len,
copy);
2403 if (!valid_)
return false;
2405 if (!CurrentSchema().
EndObject(CurrentContext(), memberCount) && !GetContinueOnErrors())
return valid_ =
false;
2412 return valid_ = !outputHandler_ || outputHandler_->StartArray();
2416 if (!valid_)
return false;
2418 if (!CurrentSchema().
EndArray(CurrentContext(), elementCount) && !GetContinueOnErrors())
return valid_ =
false;
2422 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
2423 #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2424 #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
2425 #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2430 #if RAPIDJSON_SCHEMA_VERBOSE
2433 &GetStateAllocator());
2459 return GetStateAllocator().Malloc(size);
2467 typedef typename SchemaType::Context Context;
2472 const SchemaDocumentType& schemaDocument,
2474 const char* basePath,
size_t basePathSize,
2479 size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
2480 size_t documentStackCapacity = kDefaultDocumentStackCapacity)
2482 schemaDocument_(&schemaDocument),
2485 ownStateAllocator_(0),
2486 schemaStack_(
allocator, schemaStackCapacity),
2487 documentStack_(
allocator, documentStackCapacity),
2491 missingDependents_(),
2498 if (basePath && basePathSize)
2499 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
2502 StateAllocator& GetStateAllocator() {
2503 if (!stateAllocator_)
2504 stateAllocator_ = ownStateAllocator_ =
RAPIDJSON_NEW(StateAllocator)();
2505 return *stateAllocator_;
2508 bool GetContinueOnErrors()
const {
2513 if (schemaStack_.Empty())
2516 if (CurrentContext().inArray)
2519 if (!CurrentSchema().BeginValue(CurrentContext()) && !GetContinueOnErrors())
2522 SizeType count = CurrentContext().patternPropertiesSchemaCount;
2523 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
2524 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2525 bool valueUniqueness = CurrentContext().valueUniqueness;
2527 PushSchema(*CurrentContext().valueSchema);
2530 CurrentContext().objectPatternValidatorType = patternValidatorType;
2531 ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
2532 SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
2533 va =
static_cast<ISchemaValidator**
>(
MallocState(
sizeof(ISchemaValidator*) * count));
2534 for (
SizeType i = 0; i < count; i++)
2538 CurrentContext().arrayUniqueness = valueUniqueness;
2544 if (!CurrentSchema().EndValue(CurrentContext()) && !GetContinueOnErrors())
2547 #if RAPIDJSON_SCHEMA_VERBOSE
2549 schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
2551 *documentStack_.template Push<Ch>() =
'\0';
2552 documentStack_.template Pop<Ch>(1);
2553 internal::PrintValidatorPointers(depth_, sb.
GetString(), documentStack_.template Bottom<Ch>());
2555 void* hasher = CurrentContext().hasher;
2556 uint64_t h = hasher && CurrentContext().arrayUniqueness ?
static_cast<HasherType*
>(hasher)->
GetHashCode() : 0;
2560 if (!schemaStack_.Empty()) {
2561 Context& context = CurrentContext();
2563 if (hasher && context.valueUniqueness) {
2564 HashCodeArray*
a =
static_cast<HashCodeArray*
>(context.arrayElementHashCodes);
2566 CurrentContext().arrayElementHashCodes =
a =
new (GetStateAllocator().Malloc(
sizeof(HashCodeArray))) HashCodeArray(
kArrayType);
2568 if (itr->GetUint64() == h) {
2571 if (GetContinueOnErrors()) {
2572 a->PushBack(h, GetStateAllocator());
2573 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/');
2577 a->PushBack(h, GetStateAllocator());
2582 while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) !=
'/')
2588 void AppendToken(
const Ch* str,
SizeType len) {
2589 documentStack_.template Reserve<Ch>(1 + len * 2);
2590 *documentStack_.template PushUnsafe<Ch>() =
'/';
2591 for (
SizeType i = 0; i < len; i++) {
2592 if (str[i] ==
'~') {
2593 *documentStack_.template PushUnsafe<Ch>() =
'~';
2594 *documentStack_.template PushUnsafe<Ch>() =
'0';
2596 else if (str[i] ==
'/') {
2597 *documentStack_.template PushUnsafe<Ch>() =
'~';
2598 *documentStack_.template PushUnsafe<Ch>() =
'1';
2601 *documentStack_.template PushUnsafe<Ch>() = str[i];
2605 RAPIDJSON_FORCEINLINE
void PushSchema(
const SchemaType& schema) {
new (schemaStack_.template Push<Context>()) Context(*
this, *
this, &schema); }
2607 RAPIDJSON_FORCEINLINE
void PopSchema() {
2608 Context* c = schemaStack_.template Pop<Context>(1);
2609 if (HashCodeArray*
a =
static_cast<HashCodeArray*
>(c->arrayElementHashCodes)) {
2610 a->~HashCodeArray();
2619 ((
parent && instancePointer.GetTokenCount() > 0)
2620 ?
PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2621 : instancePointer).StringifyUriFragment(sb);
2623 GetStateAllocator());
2624 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2629 SizeType len = CurrentSchema().GetURI().GetStringLength();
2630 if (len) memcpy(sb.
Push(len), CurrentSchema().GetURI().GetString(), len *
sizeof(
Ch));
2631 if (schema.GetTokenCount()) schema.StringifyUriFragment(sb);
2634 GetStateAllocator());
2635 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2639 result.AddMember(GetErrorCodeString(), code, GetStateAllocator());
2644 if (member == error_.MemberEnd())
2645 error_.AddMember(keyword, error, GetStateAllocator());
2647 if (member->value.IsObject()) {
2649 errors.PushBack(member->value, GetStateAllocator());
2650 member->value = errors;
2652 member->value.PushBack(error, GetStateAllocator());
2657 AddErrorCode(currentError_, code);
2658 AddErrorInstanceLocation(currentError_,
parent);
2659 AddErrorSchemaLocation(currentError_);
2660 AddError(
ValueType(SchemaType::GetValidateErrorKeyword(code), GetStateAllocator(),
false).Move(), currentError_);
2665 AddError(
it->name,
it->value);
2670 const typename SchemaType::ValueType& (*
exclusive)() = 0) {
2671 currentError_.SetObject();
2672 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2673 currentError_.AddMember(GetExpectedString(),
ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2675 currentError_.AddMember(
ValueType(
exclusive(), GetStateAllocator()).Move(),
true, GetStateAllocator());
2676 AddCurrentError(code);
2680 ISchemaValidator** subvalidators,
SizeType count) {
2682 for (
SizeType i = 0; i < count; ++i)
2684 currentError_.SetObject();
2685 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2686 AddCurrentError(code);
2689 const SchemaType& CurrentSchema()
const {
return *schemaStack_.template Top<Context>()->schema; }
2690 Context& CurrentContext() {
return *schemaStack_.template Top<Context>(); }
2691 const Context& CurrentContext()
const {
return *schemaStack_.template Top<Context>(); }
2693 static const size_t kDefaultSchemaStackCapacity = 1024;
2694 static const size_t kDefaultDocumentStackCapacity = 256;
2695 const SchemaDocumentType* schemaDocument_;
2697 StateAllocator* stateAllocator_;
2698 StateAllocator* ownStateAllocator_;
2701 OutputHandler* outputHandler_;
2707 #if RAPIDJSON_SCHEMA_VERBOSE
2728 unsigned parseFlags,
2729 typename InputStream,
2730 typename SourceEncoding,
2736 typedef typename InputStream::Ch
Ch;
2746 template <
typename Handler>
2750 parseResult_ = reader.template Parse<parseFlags>(is_, validator);
2752 isValid_ = validator.
IsValid();
2755 invalidSchemaKeyword_ = 0;
2764 error_.CopyFrom(validator.
GetError(), allocator_);
2767 return parseResult_;
2780 const SchemaDocumentType& sd_;
2784 const Ch* invalidSchemaKeyword_;
2787 StackAllocator allocator_;
2795 #endif // RAPIDJSON_SCHEMA_H_