Make schema working for UTF-16 and other encodings
This commit is contained in:
parent
332c226f5e
commit
a92c3b6995
@ -48,9 +48,48 @@ RAPIDJSON_DIAG_PUSH
|
|||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Verbose Utilities
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
||||||
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) \
|
|
||||||
printf("Fail keyword: %s\n", keyword)
|
namespace internal {
|
||||||
|
|
||||||
|
inline void PrintInvalidKeyword(const char* keyword) {
|
||||||
|
printf("Fail keyword: %s\n", keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintInvalidKeyword(const wchar_t* keyword) {
|
||||||
|
wprintf(L"Fail keyword: %ls\n", keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintInvalidDocument(const char* document) {
|
||||||
|
printf("Fail document: %s\n\n", document);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintInvalidDocument(const wchar_t* document) {
|
||||||
|
wprintf(L"Fail document: %ls\n\n", document);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
|
||||||
|
printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
|
||||||
|
wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_SCHEMA_VERBOSE
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_INVALID_KEYWORD_RETURN
|
||||||
|
|
||||||
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
||||||
|
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
|
#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
|
||||||
#endif
|
#endif
|
||||||
@ -62,8 +101,6 @@ RAPIDJSON_MULTILINEMACRO_BEGIN\
|
|||||||
return false;\
|
return false;\
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
|
|
||||||
RAPIDJSON_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
|
|
||||||
@ -195,6 +232,7 @@ struct SchemaValidationContext {
|
|||||||
typedef ISchemaValidatorFactory<SchemaType> SchemaValidatorFactoryType;
|
typedef ISchemaValidatorFactory<SchemaType> SchemaValidatorFactoryType;
|
||||||
typedef GenericValue<UTF8<>, CrtAllocator> HashCodeArray;
|
typedef GenericValue<UTF8<>, CrtAllocator> HashCodeArray;
|
||||||
typedef typename SchemaType::ValueType ValueType;
|
typedef typename SchemaType::ValueType ValueType;
|
||||||
|
typedef typename ValueType::Ch Ch;
|
||||||
typedef Hasher<ValueType, typename SchemaDocumentType::AllocatorType> HasherType;
|
typedef Hasher<ValueType, typename SchemaDocumentType::AllocatorType> HasherType;
|
||||||
|
|
||||||
enum PatternValidatorType {
|
enum PatternValidatorType {
|
||||||
@ -244,7 +282,7 @@ struct SchemaValidationContext {
|
|||||||
CrtAllocator* allocator; // For allocating memory for context
|
CrtAllocator* allocator; // For allocating memory for context
|
||||||
const SchemaType* schema;
|
const SchemaType* schema;
|
||||||
const SchemaType* valueSchema;
|
const SchemaType* valueSchema;
|
||||||
const char* invalidKeyword;
|
const Ch* invalidKeyword;
|
||||||
HasherType* hasher;
|
HasherType* hasher;
|
||||||
SchemaValidatorArray allOfValidators;
|
SchemaValidatorArray allOfValidators;
|
||||||
SchemaValidatorArray anyOfValidators;
|
SchemaValidatorArray anyOfValidators;
|
||||||
@ -320,7 +358,7 @@ public:
|
|||||||
if (!value.IsObject())
|
if (!value.IsObject())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "type")) {
|
if (const ValueType* v = GetMember(value, GetTypeString())) {
|
||||||
type_ = 0;
|
type_ = 0;
|
||||||
if (v->IsString())
|
if (v->IsString())
|
||||||
AddType(*v);
|
AddType(*v);
|
||||||
@ -329,7 +367,7 @@ public:
|
|||||||
AddType(*itr);
|
AddType(*itr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "enum"))
|
if (const ValueType* v = GetMember(value, GetEnumString()))
|
||||||
if (v->IsArray() && v->Size() > 0) {
|
if (v->IsArray() && v->Size() > 0) {
|
||||||
enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
|
enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
|
||||||
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
|
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
|
||||||
@ -339,21 +377,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssigIfExist(allOf_, document, p, value, "allOf");
|
AssignIfExist(allOf_, document, p, value, GetAllOfString());
|
||||||
AssigIfExist(anyOf_, document, p, value, "anyOf");
|
AssignIfExist(anyOf_, document, p, value, GetAnyOfString());
|
||||||
AssigIfExist(oneOf_, document, p, value, "oneOf");
|
AssignIfExist(oneOf_, document, p, value, GetOneOfString());
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "not"))
|
if (const ValueType* v = GetMember(value, GetNotString()))
|
||||||
document->CreateSchema(¬_, p.Append("not"), *v);
|
document->CreateSchema(¬_, p.Append(GetNotString()), *v);
|
||||||
|
|
||||||
//if (const ValueType* v = GetMember(value, "$ref"))
|
|
||||||
// document->AddRefSchema(this, *v);
|
|
||||||
|
|
||||||
// Object
|
// Object
|
||||||
|
|
||||||
const ValueType* properties = GetMember(value, "properties");
|
const ValueType* properties = GetMember(value, GetPropertiesString());
|
||||||
const ValueType* required = GetMember(value, "required");
|
const ValueType* required = GetMember(value, GetRequiredString());
|
||||||
const ValueType* dependencies = GetMember(value, "dependencies");
|
const ValueType* dependencies = GetMember(value, GetDependenciesString());
|
||||||
{
|
{
|
||||||
// Gather properties from properties/required/dependencies
|
// Gather properties from properties/required/dependencies
|
||||||
SValue allProperties(kArrayType);
|
SValue allProperties(kArrayType);
|
||||||
@ -388,7 +423,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (properties && properties->IsObject()) {
|
if (properties && properties->IsObject()) {
|
||||||
PointerType q = p.Append("properties");
|
PointerType q = p.Append(GetPropertiesString());
|
||||||
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
|
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
|
||||||
SizeType index;
|
SizeType index;
|
||||||
if (FindPropertyIndex(itr->name, &index))
|
if (FindPropertyIndex(itr->name, &index))
|
||||||
@ -396,8 +431,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "patternProperties")) {
|
if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
|
||||||
PointerType q = p.Append("patternProperties");
|
PointerType q = p.Append(GetPatternPropertiesString());
|
||||||
patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
|
patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
|
||||||
patternPropertyCount_ = 0;
|
patternPropertyCount_ = 0;
|
||||||
|
|
||||||
@ -420,7 +455,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dependencies && dependencies->IsObject()) {
|
if (dependencies && dependencies->IsObject()) {
|
||||||
PointerType q = p.Append("dependencies");
|
PointerType q = p.Append(GetDependenciesString());
|
||||||
hasDependencies_ = true;
|
hasDependencies_ = true;
|
||||||
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
|
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
|
||||||
SizeType sourceIndex;
|
SizeType sourceIndex;
|
||||||
@ -442,19 +477,19 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "additionalProperties")) {
|
if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
|
||||||
if (v->IsBool())
|
if (v->IsBool())
|
||||||
additionalProperties_ = v->GetBool();
|
additionalProperties_ = v->GetBool();
|
||||||
else if (v->IsObject())
|
else if (v->IsObject())
|
||||||
document->CreateSchema(&additionalPropertiesSchema_, p.Append("additionalProperties"), *v);
|
document->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString()), *v);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssignIfExist(minProperties_, value, "minProperties");
|
AssignIfExist(minProperties_, value, GetMinPropertiesString());
|
||||||
AssignIfExist(maxProperties_, value, "maxProperties");
|
AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
|
||||||
|
|
||||||
// Array
|
// Array
|
||||||
if (const ValueType* v = GetMember(value, "items")) {
|
if (const ValueType* v = GetMember(value, GetItemsString())) {
|
||||||
PointerType q = p.Append("items");
|
PointerType q = p.Append(GetItemsString());
|
||||||
if (v->IsObject()) // List validation
|
if (v->IsObject()) // List validation
|
||||||
document->CreateSchema(&itemsList_, q, *v);
|
document->CreateSchema(&itemsList_, q, *v);
|
||||||
else if (v->IsArray()) { // Tuple validation
|
else if (v->IsArray()) { // Tuple validation
|
||||||
@ -465,38 +500,38 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssignIfExist(minItems_, value, "minItems");
|
AssignIfExist(minItems_, value, GetMinItemsString());
|
||||||
AssignIfExist(maxItems_, value, "maxItems");
|
AssignIfExist(maxItems_, value, GetMaxItemsString());
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "additionalItems")) {
|
if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
|
||||||
if (v->IsBool())
|
if (v->IsBool())
|
||||||
additionalItems_ = v->GetBool();
|
additionalItems_ = v->GetBool();
|
||||||
else if (v->IsObject())
|
else if (v->IsObject())
|
||||||
document->CreateSchema(&additionalItemsSchema_, p.Append("additionalItems"), *v);
|
document->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString()), *v);
|
||||||
}
|
}
|
||||||
|
|
||||||
AssignIfExist(uniqueItems_, value, "uniqueItems");
|
AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
|
||||||
|
|
||||||
// String
|
// String
|
||||||
AssignIfExist(minLength_, value, "minLength");
|
AssignIfExist(minLength_, value, GetMinLengthString());
|
||||||
AssignIfExist(maxLength_, value, "maxLength");
|
AssignIfExist(maxLength_, value, GetMaxLengthString());
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "pattern"))
|
if (const ValueType* v = GetMember(value, GetPatternString()))
|
||||||
pattern_ = CreatePattern(*v);
|
pattern_ = CreatePattern(*v);
|
||||||
|
|
||||||
// Number
|
// Number
|
||||||
if (const ValueType* v = GetMember(value, "minimum"))
|
if (const ValueType* v = GetMember(value, GetMinimumString()))
|
||||||
if (v->IsNumber())
|
if (v->IsNumber())
|
||||||
minimum_.CopyFrom(*v, *allocator_);
|
minimum_.CopyFrom(*v, *allocator_);
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "maximum"))
|
if (const ValueType* v = GetMember(value, GetMaximumString()))
|
||||||
if (v->IsNumber())
|
if (v->IsNumber())
|
||||||
maximum_.CopyFrom(*v, *allocator_);
|
maximum_.CopyFrom(*v, *allocator_);
|
||||||
|
|
||||||
AssignIfExist(exclusiveMinimum_, value, "exclusiveMinimum");
|
AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
|
||||||
AssignIfExist(exclusiveMaximum_, value, "exclusiveMaximum");
|
AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
|
||||||
|
|
||||||
if (const ValueType* v = GetMember(value, "multipleOf"))
|
if (const ValueType* v = GetMember(value, GetMultipleOfString()))
|
||||||
if (v->IsNumber() && v->GetDouble() > 0.0)
|
if (v->IsNumber() && v->GetDouble() > 0.0)
|
||||||
multipleOf_.CopyFrom(*v, *allocator_);
|
multipleOf_.CopyFrom(*v, *allocator_);
|
||||||
}
|
}
|
||||||
@ -537,7 +572,7 @@ public:
|
|||||||
else if (additionalItems_)
|
else if (additionalItems_)
|
||||||
context.valueSchema = GetTypeless();
|
context.valueSchema = GetTypeless();
|
||||||
else
|
else
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("items");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
context.valueSchema = GetTypeless();
|
context.valueSchema = GetTypeless();
|
||||||
@ -563,14 +598,14 @@ public:
|
|||||||
|
|
||||||
if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
|
if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
|
||||||
if (!patternValid)
|
if (!patternValid)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("patternProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
|
||||||
}
|
}
|
||||||
else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
|
else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
|
||||||
if (!patternValid || !otherValid)
|
if (!patternValid || !otherValid)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("patternProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
|
||||||
}
|
}
|
||||||
else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
|
else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("patternProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enum_) {
|
if (enum_) {
|
||||||
@ -578,20 +613,20 @@ public:
|
|||||||
for (SizeType i = 0; i < enumCount_; i++)
|
for (SizeType i = 0; i < enumCount_; i++)
|
||||||
if (enum_[i] == h)
|
if (enum_[i] == h)
|
||||||
goto foundEnum;
|
goto foundEnum;
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("enum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
|
||||||
foundEnum:;
|
foundEnum:;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allOf_.schemas)
|
if (allOf_.schemas)
|
||||||
for (SizeType i = 0; i < allOf_.count; i++)
|
for (SizeType i = 0; i < allOf_.count; i++)
|
||||||
if (!context.allOfValidators.validators[i]->IsValid())
|
if (!context.allOfValidators.validators[i]->IsValid())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("allOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
|
||||||
|
|
||||||
if (anyOf_.schemas) {
|
if (anyOf_.schemas) {
|
||||||
for (SizeType i = 0; i < anyOf_.count; i++)
|
for (SizeType i = 0; i < anyOf_.count; i++)
|
||||||
if (context.anyOfValidators.validators[i]->IsValid())
|
if (context.anyOfValidators.validators[i]->IsValid())
|
||||||
goto foundAny;
|
goto foundAny;
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("anyOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
|
||||||
foundAny:;
|
foundAny:;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,29 +635,29 @@ public:
|
|||||||
for (SizeType i = 0; i < oneOf_.count; i++)
|
for (SizeType i = 0; i < oneOf_.count; i++)
|
||||||
if (context.oneOfValidators.validators[i]->IsValid()) {
|
if (context.oneOfValidators.validators[i]->IsValid()) {
|
||||||
if (oneValid)
|
if (oneValid)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("oneOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
|
||||||
else
|
else
|
||||||
oneValid = true;
|
oneValid = true;
|
||||||
}
|
}
|
||||||
if (!oneValid)
|
if (!oneValid)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("oneOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not_ && context.notValidator->IsValid())
|
if (not_ && context.notValidator->IsValid())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("not");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Null(Context& context) const {
|
bool Null(Context& context) const {
|
||||||
if (!(type_ & (1 << kNullSchemaType)))
|
if (!(type_ & (1 << kNullSchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bool(Context& context, bool) const {
|
bool Bool(Context& context, bool) const {
|
||||||
if (!(type_ & (1 << kBooleanSchemaType)))
|
if (!(type_ & (1 << kBooleanSchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,7 +687,7 @@ public:
|
|||||||
|
|
||||||
bool Double(Context& context, double d) const {
|
bool Double(Context& context, double d) const {
|
||||||
if (!(type_ & (1 << kNumberSchemaType)))
|
if (!(type_ & (1 << kNumberSchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
|
if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
|
||||||
return false;
|
return false;
|
||||||
@ -668,27 +703,27 @@ public:
|
|||||||
|
|
||||||
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
bool String(Context& context, const Ch* str, SizeType length, bool) const {
|
||||||
if (!(type_ & (1 << kStringSchemaType)))
|
if (!(type_ & (1 << kStringSchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
|
if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
|
||||||
SizeType count;
|
SizeType count;
|
||||||
if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
|
if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
|
||||||
if (count < minLength_)
|
if (count < minLength_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minLength");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
|
||||||
if (count > maxLength_)
|
if (count > maxLength_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maxLength");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pattern_ && !IsPatternMatch(pattern_, str, length))
|
if (pattern_ && !IsPatternMatch(pattern_, str, length))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("pattern");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
|
||||||
|
|
||||||
return CreateParallelValidator(context);
|
return CreateParallelValidator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartObject(Context& context) const {
|
bool StartObject(Context& context) const {
|
||||||
if (!(type_ & (1 << kObjectSchemaType)))
|
if (!(type_ & (1 << kObjectSchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
context.objectRequiredCount = 0;
|
context.objectRequiredCount = 0;
|
||||||
if (hasDependencies_) {
|
if (hasDependencies_) {
|
||||||
@ -715,7 +750,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
SizeType index;
|
SizeType index;
|
||||||
if (FindPropertyIndex(str, len, &index)) {
|
if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
|
||||||
if (context.patternPropertiesSchemaCount > 0) {
|
if (context.patternPropertiesSchemaCount > 0) {
|
||||||
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
|
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
|
||||||
context.valueSchema = GetTypeless();
|
context.valueSchema = GetTypeless();
|
||||||
@ -749,20 +784,20 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
|
if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("additionalProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EndObject(Context& context, SizeType memberCount) const {
|
bool EndObject(Context& context, SizeType memberCount) const {
|
||||||
if (context.objectRequiredCount != requiredCount_)
|
if (context.objectRequiredCount != requiredCount_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("required");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
|
||||||
|
|
||||||
if (memberCount < minProperties_)
|
if (memberCount < minProperties_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
|
||||||
|
|
||||||
if (memberCount > maxProperties_)
|
if (memberCount > maxProperties_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maxProperties");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
|
||||||
|
|
||||||
if (hasDependencies_) {
|
if (hasDependencies_) {
|
||||||
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
|
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
|
||||||
@ -770,11 +805,11 @@ public:
|
|||||||
if (properties_[sourceIndex].dependencies) {
|
if (properties_[sourceIndex].dependencies) {
|
||||||
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
|
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
|
||||||
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
|
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("dependencies");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
|
||||||
}
|
}
|
||||||
else if (properties_[sourceIndex].dependenciesSchema)
|
else if (properties_[sourceIndex].dependenciesSchema)
|
||||||
if (!context.dependencyValidators.validators[sourceIndex]->IsValid())
|
if (!context.dependencyValidators.validators[sourceIndex]->IsValid())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("dependencies");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +818,7 @@ public:
|
|||||||
|
|
||||||
bool StartArray(Context& context) const {
|
bool StartArray(Context& context) const {
|
||||||
if (!(type_ & (1 << kArraySchemaType)))
|
if (!(type_ & (1 << kArraySchemaType)))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
if (uniqueItems_)
|
if (uniqueItems_)
|
||||||
context.arrayElementHashCodes.SetArray();
|
context.arrayElementHashCodes.SetArray();
|
||||||
@ -798,14 +833,57 @@ public:
|
|||||||
context.inArray = false;
|
context.inArray = false;
|
||||||
|
|
||||||
if (elementCount < minItems_)
|
if (elementCount < minItems_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minItems");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
|
||||||
|
|
||||||
if (elementCount > maxItems_)
|
if (elementCount > maxItems_)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maxItems");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate functions for string literal according to Ch
|
||||||
|
#define RAPIDJSON_STRING_(name, ...) \
|
||||||
|
static const Ch* Get##name##String() {\
|
||||||
|
static const Ch s[] = { __VA_ARGS__, '\0' };\
|
||||||
|
return s;\
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l');
|
||||||
|
RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n');
|
||||||
|
RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't');
|
||||||
|
RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y');
|
||||||
|
RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g');
|
||||||
|
RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r');
|
||||||
|
RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r');
|
||||||
|
RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e');
|
||||||
|
RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm');
|
||||||
|
RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f');
|
||||||
|
RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f');
|
||||||
|
RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f');
|
||||||
|
RAPIDJSON_STRING_(Not, 'n', 'o', 't');
|
||||||
|
RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd');
|
||||||
|
RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's');
|
||||||
|
RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's');
|
||||||
|
RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's');
|
||||||
|
RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's');
|
||||||
|
RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's');
|
||||||
|
RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's');
|
||||||
|
RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h');
|
||||||
|
RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h');
|
||||||
|
RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n');
|
||||||
|
RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm');
|
||||||
|
RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm');
|
||||||
|
RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm');
|
||||||
|
RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm');
|
||||||
|
RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f');
|
||||||
|
|
||||||
|
#undef RAPIDJSON_STRING_
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SchemaValueType {
|
enum SchemaValueType {
|
||||||
kNullSchemaType,
|
kNullSchemaType,
|
||||||
@ -832,7 +910,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const SchemaType* GetTypeless() {
|
static const SchemaType* GetTypeless() {
|
||||||
static SchemaType typeless(0, PointerType(), Value(kObjectType).Move(), 0);
|
static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), 0);
|
||||||
return &typeless;
|
return &typeless;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -846,27 +924,27 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
static const ValueType* GetMember(const ValueType& value, const char* name) {
|
static const ValueType* GetMember(const ValueType& value, const Ch* name) {
|
||||||
typename ValueType::ConstMemberIterator itr = value.FindMember(name);
|
typename ValueType::ConstMemberIterator itr = value.FindMember(name);
|
||||||
return itr != value.MemberEnd() ? &(itr->value) : 0;
|
return itr != value.MemberEnd() ? &(itr->value) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
static void AssignIfExist(bool& out, const ValueType& value, const char* name) {
|
static void AssignIfExist(bool& out, const ValueType& value, const Ch* name) {
|
||||||
if (const ValueType* v = GetMember(value, name))
|
if (const ValueType* v = GetMember(value, name))
|
||||||
if (v->IsBool())
|
if (v->IsBool())
|
||||||
out = v->GetBool();
|
out = v->GetBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
static void AssignIfExist(SizeType& out, const ValueType& value, const char* name) {
|
static void AssignIfExist(SizeType& out, const ValueType& value, const Ch* name) {
|
||||||
if (const ValueType* v = GetMember(value, name))
|
if (const ValueType* v = GetMember(value, name))
|
||||||
if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
|
if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
|
||||||
out = static_cast<SizeType>(v->GetUint64());
|
out = static_cast<SizeType>(v->GetUint64());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DocumentType, typename ValueType, typename PointerType>
|
template <typename DocumentType, typename ValueType, typename PointerType>
|
||||||
void AssigIfExist(SchemaArray& out, const DocumentType& document, const PointerType& p, const ValueType& value, const char* name) {
|
void AssignIfExist(SchemaArray& out, const DocumentType& document, const PointerType& p, const ValueType& value, const Ch* name) {
|
||||||
if (const ValueType* v = GetMember(value, name)) {
|
if (const ValueType* v = GetMember(value, name)) {
|
||||||
if (v->IsArray() && v->Size() > 0) {
|
if (v->IsArray() && v->Size() > 0) {
|
||||||
PointerType q = p.Append(name);
|
PointerType q = p.Append(name);
|
||||||
@ -902,14 +980,14 @@ private:
|
|||||||
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
|
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
|
||||||
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
|
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
|
||||||
|
|
||||||
void AddType(const Value& type) {
|
void AddType(const ValueType& type) {
|
||||||
if (type == "null" ) type_ |= 1 << kNullSchemaType;
|
if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
|
||||||
else if (type == "boolean") type_ |= 1 << kBooleanSchemaType;
|
else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
|
||||||
else if (type == "object" ) type_ |= 1 << kObjectSchemaType;
|
else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
|
||||||
else if (type == "array" ) type_ |= 1 << kArraySchemaType;
|
else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
|
||||||
else if (type == "string" ) type_ |= 1 << kStringSchemaType;
|
else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
|
||||||
else if (type == "integer") type_ |= 1 << kIntegerSchemaType;
|
else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
|
||||||
else if (type == "number" ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
|
else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateParallelValidator(Context& context) const {
|
bool CreateParallelValidator(Context& context) const {
|
||||||
@ -957,24 +1035,14 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// O(n)
|
|
||||||
bool FindPropertyIndex(const Ch* str, SizeType length, SizeType* outIndex) const {
|
|
||||||
for (SizeType index = 0; index < propertyCount_; index++)
|
|
||||||
if (properties_[index].name.GetStringLength() == length && std::memcmp(properties_[index].name.GetString(), str, length) == 0) {
|
|
||||||
*outIndex = index;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckInt(Context& context, int64_t i) const {
|
bool CheckInt(Context& context, int64_t i) const {
|
||||||
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
|
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
if (!minimum_.IsNull()) {
|
if (!minimum_.IsNull()) {
|
||||||
if (minimum_.IsInt64()) {
|
if (minimum_.IsInt64()) {
|
||||||
if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
|
if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
|
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -983,7 +1051,7 @@ private:
|
|||||||
if (!maximum_.IsNull()) {
|
if (!maximum_.IsNull()) {
|
||||||
if (maximum_.IsInt64()) {
|
if (maximum_.IsInt64()) {
|
||||||
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
|
if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
|
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -992,7 +1060,7 @@ private:
|
|||||||
if (!multipleOf_.IsNull()) {
|
if (!multipleOf_.IsNull()) {
|
||||||
if (multipleOf_.IsUint64()) {
|
if (multipleOf_.IsUint64()) {
|
||||||
if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
|
if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -1003,12 +1071,12 @@ private:
|
|||||||
|
|
||||||
bool CheckUint(Context& context, uint64_t i) const {
|
bool CheckUint(Context& context, uint64_t i) const {
|
||||||
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
|
if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("type");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
|
||||||
|
|
||||||
if (!minimum_.IsNull()) {
|
if (!minimum_.IsNull()) {
|
||||||
if (minimum_.IsUint64()) {
|
if (minimum_.IsUint64()) {
|
||||||
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
|
if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
|
else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -1017,7 +1085,7 @@ private:
|
|||||||
if (!maximum_.IsNull()) {
|
if (!maximum_.IsNull()) {
|
||||||
if (maximum_.IsUint64()) {
|
if (maximum_.IsUint64()) {
|
||||||
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
|
if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
|
else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -1026,7 +1094,7 @@ private:
|
|||||||
if (!multipleOf_.IsNull()) {
|
if (!multipleOf_.IsNull()) {
|
||||||
if (multipleOf_.IsUint64()) {
|
if (multipleOf_.IsUint64()) {
|
||||||
if (i % multipleOf_.GetUint64() != 0)
|
if (i % multipleOf_.GetUint64() != 0)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
|
||||||
}
|
}
|
||||||
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
|
||||||
return false;
|
return false;
|
||||||
@ -1037,13 +1105,13 @@ private:
|
|||||||
|
|
||||||
bool CheckDoubleMinimum(Context& context, double d) const {
|
bool CheckDoubleMinimum(Context& context, double d) const {
|
||||||
if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
|
if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("minimum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckDoubleMaximum(Context& context, double d) const {
|
bool CheckDoubleMaximum(Context& context, double d) const {
|
||||||
if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
|
if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("maximum");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1052,7 +1120,7 @@ private:
|
|||||||
double q = std::floor(a / b);
|
double q = std::floor(a / b);
|
||||||
double r = a - q * b;
|
double r = a - q * b;
|
||||||
if (r > 0.0)
|
if (r > 0.0)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("multipleOf");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1245,8 +1313,10 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HandleRefSchema(const Pointer& source, const SchemaType** schema, const ValueType& v) {
|
bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v) {
|
||||||
typename ValueType::ConstMemberIterator itr = v.FindMember("$ref");
|
static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
|
||||||
|
|
||||||
|
typename ValueType::ConstMemberIterator itr = v.FindMember(kRefString);
|
||||||
if (itr == v.MemberEnd())
|
if (itr == v.MemberEnd())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1386,7 +1456,7 @@ public:
|
|||||||
return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
|
return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetInvalidSchemaKeyword() const {
|
const Ch* GetInvalidSchemaKeyword() const {
|
||||||
return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
|
return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1399,7 +1469,7 @@ public:
|
|||||||
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
RAPIDJSON_MULTILINEMACRO_BEGIN\
|
||||||
*documentStack_.template Push<Ch>() = '\0';\
|
*documentStack_.template Push<Ch>() = '\0';\
|
||||||
documentStack_.template Pop<Ch>(1);\
|
documentStack_.template Pop<Ch>(1);\
|
||||||
printf("Fail document: %s\n\n", documentStack_.template Bottom<Ch>());\
|
internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
|
||||||
RAPIDJSON_MULTILINEMACRO_END
|
RAPIDJSON_MULTILINEMACRO_END
|
||||||
#else
|
#else
|
||||||
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
|
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
|
||||||
@ -1563,12 +1633,12 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
#if RAPIDJSON_SCHEMA_VERBOSE
|
#if RAPIDJSON_SCHEMA_VERBOSE
|
||||||
StringBuffer sb;
|
GenericStringBuffer<EncodingType> sb;
|
||||||
schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
|
schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
|
||||||
|
|
||||||
*documentStack_.template Push<Ch>() = '\0';
|
*documentStack_.template Push<Ch>() = '\0';
|
||||||
documentStack_.template Pop<Ch>(1);
|
documentStack_.template Pop<Ch>(1);
|
||||||
printf("S: %*s%s\nD: %*s%s\n\n", depth_ * 4, " ", sb.GetString(), depth_ * 4, " ", documentStack_.template Bottom<Ch>());
|
internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
uint64_t h = CurrentContext().arrayUniqueness ? CurrentContext().hasher->GetHashCode() : 0;
|
uint64_t h = CurrentContext().arrayUniqueness ? CurrentContext().hasher->GetHashCode() : 0;
|
||||||
@ -1580,7 +1650,7 @@ private:
|
|||||||
if (context.valueUniqueness) {
|
if (context.valueUniqueness) {
|
||||||
for (typename Context::HashCodeArray::ConstValueIterator itr = context.arrayElementHashCodes.Begin(); itr != context.arrayElementHashCodes.End(); ++itr)
|
for (typename Context::HashCodeArray::ConstValueIterator itr = context.arrayElementHashCodes.Begin(); itr != context.arrayElementHashCodes.End(); ++itr)
|
||||||
if (itr->GetUint64() == h)
|
if (itr->GetUint64() == h)
|
||||||
RAPIDJSON_INVALID_KEYWORD_RETURN("uniqueItems");
|
RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
|
||||||
context.arrayElementHashCodes.PushBack(h, *context.allocator);
|
context.arrayElementHashCodes.PushBack(h, *context.allocator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1624,7 +1694,7 @@ private:
|
|||||||
|
|
||||||
static const size_t kDefaultSchemaStackCapacity = 1024;
|
static const size_t kDefaultSchemaStackCapacity = 1024;
|
||||||
static const size_t kDefaultDocumentStackCapacity = 256;
|
static const size_t kDefaultDocumentStackCapacity = 256;
|
||||||
const SchemaDocument* schemaDocument_;
|
const SchemaDocumentType* schemaDocument_;
|
||||||
const SchemaType& root_;
|
const SchemaType& root_;
|
||||||
BaseReaderHandler<EncodingType> nullOutputHandler_;
|
BaseReaderHandler<EncodingType> nullOutputHandler_;
|
||||||
OutputHandler& outputHandler_;
|
OutputHandler& outputHandler_;
|
||||||
|
@ -386,8 +386,8 @@ TEST(SchemaValidator, Integer_MultipleOf) {
|
|||||||
sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
|
sd.Parse("{\"type\":\"integer\",\"multipleOf\":10}");
|
||||||
SchemaDocument s(sd);
|
SchemaDocument s(sd);
|
||||||
|
|
||||||
// VALIDATE(s, "0", true);
|
VALIDATE(s, "0", true);
|
||||||
// VALIDATE(s, "10", true);
|
VALIDATE(s, "10", true);
|
||||||
VALIDATE(s, "-10", true);
|
VALIDATE(s, "-10", true);
|
||||||
VALIDATE(s, "20", true);
|
VALIDATE(s, "20", true);
|
||||||
INVALIDATE(s, "23", "", "multipleOf", "");
|
INVALIDATE(s, "23", "", "multipleOf", "");
|
||||||
@ -882,7 +882,33 @@ TEST(SchemaValidator, ValidateMetaSchema) {
|
|||||||
sb.Clear();
|
sb.Clear();
|
||||||
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
||||||
printf("Invalid document: %s\n", sb.GetString());
|
printf("Invalid document: %s\n", sb.GetString());
|
||||||
//ADD_FAILURE();
|
ADD_FAILURE();
|
||||||
|
}
|
||||||
|
free(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(SchemaValidator, ValidateMetaSchema_UTF16) {
|
||||||
|
typedef GenericDocument<UTF16<> > D;
|
||||||
|
typedef GenericSchemaDocument<D::ValueType> SD;
|
||||||
|
typedef GenericSchemaValidator<SD> SV;
|
||||||
|
|
||||||
|
char* json = ReadFile("draft-04/schema");
|
||||||
|
|
||||||
|
D d;
|
||||||
|
StringStream ss(json);
|
||||||
|
d.ParseStream<0, UTF8<> >(ss);
|
||||||
|
ASSERT_FALSE(d.HasParseError());
|
||||||
|
SD sd(d);
|
||||||
|
SV validator(sd);
|
||||||
|
if (!d.Accept(validator)) {
|
||||||
|
GenericStringBuffer<UTF16<> > sb;
|
||||||
|
validator.GetInvalidSchemaPointer().StringifyUriFragment(sb);
|
||||||
|
wprintf(L"Invalid schema: %ls\n", sb.GetString());
|
||||||
|
wprintf(L"Invalid keyword: %ls\n", validator.GetInvalidSchemaKeyword());
|
||||||
|
sb.Clear();
|
||||||
|
validator.GetInvalidDocumentPointer().StringifyUriFragment(sb);
|
||||||
|
wprintf(L"Invalid document: %ls\n", sb.GetString());
|
||||||
|
ADD_FAILURE();
|
||||||
}
|
}
|
||||||
free(json);
|
free(json);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user