1065 lines
40 KiB
C
Raw Normal View History

2015-05-01 17:59:31 +08:00
// Tencent is pleased to support the open source community by making RapidJSON available->
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License-> You may obtain a copy of the License at
//
// http://opensource->org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
// specific language governing permissions and limitations under the License->
#ifndef RAPIDJSON_SCHEMA_H_
#define RAPIDJSON_SCHEMA_H_
#include "document.h"
2015-05-07 16:42:41 +08:00
#include <cmath> // HUGE_VAL, abs, floor
2015-05-01 17:59:31 +08:00
2015-05-06 18:11:57 +08:00
#if !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
2015-05-05 00:08:36 +08:00
#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
2015-05-08 13:44:52 +08:00
#else
#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
2015-05-05 00:08:36 +08:00
#endif
#if RAPIDJSON_SCHEMA_USE_STDREGEX
#include <regex>
#endif
#if RAPIDJSON_SCHEMA_USE_STDREGEX
#define RAPIDJSON_SCHEMA_HAS_REGEX 1
#else
#define RAPIDJSON_SCHEMA_HAS_REGEX 0
#endif
2015-05-01 22:38:00 +08:00
#if defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
2015-05-01 17:59:31 +08:00
RAPIDJSON_NAMESPACE_BEGIN
2015-05-02 17:46:55 +08:00
enum SchemaType {
kNullSchemaType,
kBooleanSchemaType,
kObjectSchemaType,
kArraySchemaType,
kStringSchemaType,
kNumberSchemaType,
kIntegerSchemaType,
2015-05-07 00:59:51 +08:00
kTotalSchemaType
2015-05-02 17:46:55 +08:00
};
2015-05-01 17:59:31 +08:00
template <typename Encoding>
class BaseSchema;
2015-05-07 10:26:13 +08:00
template <typename Encoding, typename OutputHandler, typename Allocator>
class GenericSchemaValidator;
2015-05-05 16:44:05 +08:00
template <typename Encoding>
struct SchemaValidatorArray {
SchemaValidatorArray() : validators(), count() {}
~SchemaValidatorArray() {
for (SizeType i = 0; i < count; i++)
delete validators[i];
delete[] validators;
}
2015-05-07 10:26:13 +08:00
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>** validators;
SizeType count;
};
template <typename Encoding>
struct BaseSchemaArray {
BaseSchemaArray() : schemas(), count() {}
~BaseSchemaArray() {
for (SizeType i = 0; i < count; i++)
delete schemas[i];
delete[] schemas;
}
BaseSchema<Encoding>** schemas;
SizeType count;
};
2015-05-08 13:37:30 +08:00
enum PatternValidatorType {
kPatternValidatorOnly,
kPatternValidatorWithProperty,
kPatternValidatorWithAdditionalProperty
};
2015-05-01 17:59:31 +08:00
template <typename Encoding>
struct SchemaValidationContext {
2015-05-07 15:05:55 +08:00
SchemaValidationContext(const BaseSchema<Encoding>* s) :
2015-05-08 14:03:05 +08:00
schema(s),
valueSchema(),
2015-05-08 13:37:30 +08:00
patternPropertiesSchemas(),
2015-05-08 14:03:05 +08:00
notValidator(),
2015-05-08 13:37:30 +08:00
patternPropertiesSchemaCount(),
valuePatternValidatorType(kPatternValidatorOnly),
2015-05-08 14:03:05 +08:00
objectDependencies(),
2015-05-08 13:37:30 +08:00
inArray(false)
2015-05-05 16:44:05 +08:00
{
}
2015-05-01 17:59:31 +08:00
~SchemaValidationContext() {
delete notValidator;
2015-05-08 15:07:31 +08:00
delete[] patternPropertiesSchemas;
delete[] objectDependencies;
}
2015-05-01 17:59:31 +08:00
const BaseSchema<Encoding>* schema;
const BaseSchema<Encoding>* valueSchema;
SchemaValidatorArray<Encoding> allOfValidators;
SchemaValidatorArray<Encoding> anyOfValidators;
SchemaValidatorArray<Encoding> oneOfValidators;
SchemaValidatorArray<Encoding> dependencyValidators;
2015-05-08 13:37:30 +08:00
SchemaValidatorArray<Encoding> patternPropertiesValidators;
const BaseSchema<Encoding>** patternPropertiesSchemas;
2015-05-08 14:03:05 +08:00
GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator>* notValidator;
2015-05-08 13:37:30 +08:00
SizeType patternPropertiesSchemaCount;
PatternValidatorType valuePatternValidatorType;
PatternValidatorType objectPatternValidatorType;
2015-05-01 17:59:31 +08:00
SizeType objectRequiredCount;
SizeType arrayElementIndex;
bool* objectDependencies;
2015-05-07 00:59:51 +08:00
bool inArray;
2015-05-01 17:59:31 +08:00
};
template <typename Encoding>
class BaseSchema {
public:
2015-05-01 20:16:41 +08:00
typedef typename Encoding::Ch Ch;
2015-05-01 17:59:31 +08:00
typedef SchemaValidationContext<Encoding> Context;
template <typename ValueType>
2015-05-07 00:59:51 +08:00
BaseSchema(const ValueType& value) :
not_(),
2015-05-07 15:05:55 +08:00
type_((1 << kTotalSchemaType) - 1), // typeless
2015-05-07 00:59:51 +08:00
properties_(),
additionalPropertiesSchema_(),
2015-05-07 00:59:51 +08:00
patternProperties_(),
patternPropertyCount_(),
propertyCount_(),
requiredCount_(),
minProperties_(),
maxProperties_(SizeType(~0)),
additionalProperties_(true),
2015-05-07 00:59:51 +08:00
hasDependencies_(),
hasSchemaDependencies_(),
additionalItemsSchema_(),
2015-05-07 00:59:51 +08:00
itemsList_(),
itemsTuple_(),
itemsTupleCount_(),
minItems_(),
maxItems_(SizeType(~0)),
additionalItems_(true),
pattern_(),
minLength_(0),
maxLength_(~SizeType(0)),
minimum_(-HUGE_VAL),
maximum_(HUGE_VAL),
multipleOf_(0),
hasMultipleOf_(false),
exclusiveMinimum_(false),
exclusiveMaximum_(false)
{
2015-05-07 15:05:55 +08:00
typedef typename ValueType::ConstValueIterator ConstValueIterator;
typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
if (!value.IsObject())
return;
if (const ValueType* v = GetMember(value, "type")) {
type_ = 0;
if (v->IsString())
AddType(*v);
else if (v->IsArray())
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
2015-05-07 00:59:51 +08:00
AddType(*itr);
}
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "enum"))
if (v->IsArray() && v->Size() > 0)
enum_.CopyFrom(*v, allocator_);
2015-05-05 16:44:05 +08:00
2015-05-07 15:05:55 +08:00
AssigIfExist(allOf_, value, "allOf");
AssigIfExist(anyOf_, value, "anyOf");
AssigIfExist(oneOf_, value, "oneOf");
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "not"))
not_ = new BaseSchema<Encoding>(*v);
2015-05-01 20:16:41 +08:00
2015-05-07 00:59:51 +08:00
// Object
2015-05-07 23:05:05 +08:00
const ValueType* properties = GetMember(value, "properties");
const ValueType* required = GetMember(value, "required");
const ValueType* dependencies = GetMember(value, "dependencies");
{
// Gather properties from properties/required/dependencies
typedef GenericValue<Encoding, MemoryPoolAllocator<> > SValue;
SValue allProperties(kArrayType);
if (properties && properties->IsObject())
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
AddUniqueElement(allProperties, itr->name);
if (required && required->IsArray())
for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
if (itr->IsString())
AddUniqueElement(allProperties, *itr);
if (dependencies && dependencies->IsObject())
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
AddUniqueElement(allProperties, itr->name);
if (itr->value.IsArray())
for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
if (i->IsString())
AddUniqueElement(allProperties, *i);
}
if (allProperties.Size() > 0) {
propertyCount_ = allProperties.Size();
properties_ = new Property[propertyCount_];
for (SizeType i = 0; i < propertyCount_; i++) {
2015-05-07 23:37:05 +08:00
properties_[i].name = allProperties[i];
2015-05-07 15:05:55 +08:00
}
2015-05-01 17:59:31 +08:00
}
2015-05-07 23:05:05 +08:00
}
if (properties && properties->IsObject())
for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
SizeType index;
2015-05-08 15:22:28 +08:00
if (FindPropertyIndex(itr->name, &index)) {
2015-05-07 23:05:05 +08:00
properties_[index].schema = new BaseSchema(itr->value);
properties_[index].typeless = false;
2015-05-08 15:22:28 +08:00
}
2015-05-07 23:05:05 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "patternProperties")) {
patternProperties_ = new PatternProperty[v->MemberCount()];
2015-05-05 00:47:06 +08:00
patternPropertyCount_ = 0;
2015-05-07 15:05:55 +08:00
for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
patternProperties_[patternPropertyCount_].schema = new BaseSchema<Encoding>(itr->value);
2015-05-05 00:47:06 +08:00
patternPropertyCount_++;
}
}
2015-05-07 23:05:05 +08:00
if (required && required->IsArray())
for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
if (itr->IsString()) {
SizeType index;
if (FindPropertyIndex(*itr, &index)) {
properties_[index].required = true;
requiredCount_++;
2015-05-01 17:59:31 +08:00
}
2015-05-07 23:05:05 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 23:05:05 +08:00
if (dependencies && dependencies->IsObject()) {
hasDependencies_ = true;
for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
SizeType sourceIndex;
if (FindPropertyIndex(itr->name, &sourceIndex)) {
if (itr->value.IsArray()) {
properties_[sourceIndex].dependencies = new bool[propertyCount_];
std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
SizeType targetIndex;
if (FindPropertyIndex(*targetItr, &targetIndex))
properties_[sourceIndex].dependencies[targetIndex] = true;
}
}
2015-05-07 23:05:05 +08:00
else if (itr->value.IsObject()) {
hasSchemaDependencies_ = true;
properties_[sourceIndex].dependenciesSchema = new BaseSchema<Encoding>(itr->value);
}
2015-05-01 17:59:31 +08:00
}
}
2015-05-07 23:05:05 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "additionalProperties")) {
if (v->IsBool())
additionalProperties_ = v->GetBool();
2015-05-07 15:05:55 +08:00
else if (v->IsObject())
additionalPropertiesSchema_ = new BaseSchema<Encoding>(*v);
2015-05-01 17:59:31 +08:00
}
2015-05-07 15:05:55 +08:00
AssignIfExist(minProperties_, value, "minProperties");
AssignIfExist(maxProperties_, value, "maxProperties");
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
// Array
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "items")) {
if (v->IsObject()) // List validation
itemsList_ = new BaseSchema<Encoding>(*v);
else if (v->IsArray()) { // Tuple validation
itemsTuple_ = new BaseSchema<Encoding>*[v->Size()];
for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
itemsTuple_[itemsTupleCount_++] = new BaseSchema<Encoding>(*itr);
2015-05-07 00:59:51 +08:00
}
}
2015-05-02 17:46:55 +08:00
2015-05-07 15:05:55 +08:00
AssignIfExist(minItems_, value, "minItems");
AssignIfExist(maxItems_, value, "maxItems");
if (const ValueType* v = GetMember(value, "additionalItems")) {
if (v->IsBool())
additionalItems_ = v->GetBool();
else if (v->IsObject())
additionalItemsSchema_ = new BaseSchema<Encoding>(*v);
}
2015-05-05 16:44:05 +08:00
2015-05-07 00:59:51 +08:00
// String
2015-05-07 15:05:55 +08:00
AssignIfExist(minLength_, value, "minLength");
AssignIfExist(maxLength_, value, "maxLength");
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
if (const ValueType* v = GetMember(value, "pattern"))
pattern_ = CreatePattern(*v);
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
// Number
2015-05-07 15:05:55 +08:00
ConstMemberIterator minimumItr = value.FindMember("minimum");
if (minimumItr != value.MemberEnd())
2015-05-07 00:59:51 +08:00
if (minimumItr->value.IsNumber())
minimum_ = minimumItr->value.GetDouble();
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
ConstMemberIterator maximumItr = value.FindMember("maximum");
if (maximumItr != value.MemberEnd())
2015-05-07 00:59:51 +08:00
if (maximumItr->value.IsNumber())
maximum_ = maximumItr->value.GetDouble();
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
AssignIfExist(exclusiveMinimum_, value, "exclusiveMinimum");
AssignIfExist(exclusiveMaximum_, value, "exclusiveMaximum");
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
ConstMemberIterator multipleOfItr = value.FindMember("multipleOf");
2015-05-07 00:59:51 +08:00
if (multipleOfItr != value.MemberEnd()) {
if (multipleOfItr->value.IsNumber()) {
multipleOf_ = multipleOfItr->value.GetDouble();
hasMultipleOf_ = true;
}
2015-05-02 10:06:48 +08:00
}
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
~BaseSchema() {
delete not_;
delete [] properties_;
delete additionalPropertiesSchema_;
2015-05-07 00:59:51 +08:00
delete [] patternProperties_;
delete additionalItemsSchema_;
2015-05-01 17:59:31 +08:00
delete itemsList_;
for (SizeType i = 0; i < itemsTupleCount_; i++)
delete itemsTuple_[i];
2015-05-01 21:42:26 +08:00
delete [] itemsTuple_;
2015-05-07 00:59:51 +08:00
#if RAPIDJSON_SCHEMA_USE_STDREGEX
delete pattern_;
#endif
}
2015-05-02 17:46:55 +08:00
2015-05-07 00:59:51 +08:00
bool BeginValue(Context& context) const {
if (context.inArray) {
if (itemsList_)
context.valueSchema = itemsList_;
else if (itemsTuple_) {
if (context.arrayElementIndex < itemsTupleCount_)
context.valueSchema = itemsTuple_[context.arrayElementIndex];
else if (additionalItemsSchema_)
context.valueSchema = additionalItemsSchema_;
2015-05-07 00:59:51 +08:00
else if (additionalItems_)
context.valueSchema = GetTypeless();
else
return false;
}
2015-05-02 10:06:48 +08:00
else
2015-05-07 00:59:51 +08:00
context.valueSchema = GetTypeless();
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
context.arrayElementIndex++;
}
2015-05-02 10:06:48 +08:00
return true;
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool EndValue(Context& context) const {
2015-05-08 13:37:30 +08:00
if (context.patternPropertiesValidators.count > 0) {
bool otherValid = false;
SizeType count = context.patternPropertiesValidators.count;
if (context.objectPatternValidatorType != kPatternValidatorOnly)
otherValid = context.patternPropertiesValidators.validators[--count]->IsValid();
bool patternValid = true;
for (SizeType i = 0; i < count; i++)
if (!context.patternPropertiesValidators.validators[i]->IsValid()) {
patternValid = false;
break;
}
2015-05-08 15:07:31 +08:00
if (context.objectPatternValidatorType == kPatternValidatorOnly) {
2015-05-08 13:37:30 +08:00
if (!patternValid)
return false;
2015-05-08 15:07:31 +08:00
}
else if (context.objectPatternValidatorType == kPatternValidatorWithProperty) {
2015-05-08 13:37:30 +08:00
if (!patternValid || !otherValid)
return false;
}
2015-05-08 15:07:31 +08:00
else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
return false;
2015-05-08 13:37:30 +08:00
}
2015-05-07 15:05:55 +08:00
if (allOf_.schemas)
2015-05-08 13:37:30 +08:00
for (SizeType i = 0; i < allOf_.count; i++)
if (!context.allOfValidators.validators[i]->IsValid())
2015-05-07 00:59:51 +08:00
return false;
2015-05-07 15:05:55 +08:00
2015-05-07 00:59:51 +08:00
if (anyOf_.schemas) {
2015-05-08 13:37:30 +08:00
for (SizeType i = 0; i < anyOf_.count; i++)
if (context.anyOfValidators.validators[i]->IsValid())
2015-05-07 15:05:55 +08:00
goto foundAny;
return false;
foundAny:;
2015-05-07 00:59:51 +08:00
}
2015-05-07 15:05:55 +08:00
2015-05-07 00:59:51 +08:00
if (oneOf_.schemas) {
bool oneValid = false;
2015-05-08 13:37:30 +08:00
for (SizeType i = 0; i < oneOf_.count; i++)
if (context.oneOfValidators.validators[i]->IsValid()) {
2015-05-07 00:59:51 +08:00
if (oneValid)
return false;
else
oneValid = true;
}
if (!oneValid)
return false;
}
2015-05-07 15:05:55 +08:00
return !not_ || !context.notValidator->IsValid();
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool Null(Context& context) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
return
(type_ & (1 << kNullSchemaType)) &&
(!enum_.IsArray() || CheckEnum(GenericValue<Encoding>().Move()));
}
bool Bool(Context& context, bool b) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
return
(type_ & (1 << kBooleanSchemaType)) &&
(!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(b).Move()));
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool Int(Context& context, int i) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false;
2015-05-01 20:16:41 +08:00
2015-05-07 00:59:51 +08:00
return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(i).Move()));
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
bool Uint(Context& context, unsigned u) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false;
2015-05-05 00:08:36 +08:00
2015-05-07 00:59:51 +08:00
return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(u).Move()));
2015-05-05 00:08:36 +08:00
}
2015-05-07 00:59:51 +08:00
bool Int64(Context& context, int64_t i) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false;
return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(i).Move()));
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool Uint64(Context& context, uint64_t u) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0)
return false;
return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(u).Move()));
}
2015-05-02 17:46:55 +08:00
2015-05-07 00:59:51 +08:00
bool Double(Context& context, double d) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & (1 << kNumberSchemaType)) == 0)
return false;
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
return CheckDouble(d) && (!enum_.IsArray() || CheckEnum(GenericValue<Encoding>(d).Move()));
}
bool String(Context& context, const Ch* str, SizeType length, bool) const {
(void)str;
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & (1 << kStringSchemaType)) == 0)
2015-05-05 00:08:36 +08:00
return false;
2015-05-05 16:44:05 +08:00
//if (length < minLength_ || length > maxLength_)
// return false;
if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
SizeType count;
if (internal::CountStringCodePoint<Encoding>(str, length, &count) && (count < minLength_ || count > maxLength_))
return false;
}
2015-05-05 00:08:36 +08:00
2015-05-08 13:44:52 +08:00
if (pattern_ && !IsPatternMatch(pattern_, str, length))
2015-05-07 15:05:55 +08:00
return false;
2015-05-05 00:08:36 +08:00
2015-05-07 00:59:51 +08:00
return !enum_.IsArray() || CheckEnum(GenericValue<Encoding>(str, length).Move());
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool StartObject(Context& context) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & (1 << kObjectSchemaType)) == 0)
return false;
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
context.objectRequiredCount = 0;
if (hasDependencies_) {
context.objectDependencies = new bool[propertyCount_];
std::memset(context.objectDependencies, 0, sizeof(bool) * propertyCount_);
2015-05-01 17:59:31 +08:00
}
2015-05-08 13:37:30 +08:00
if (patternProperties_) { // pre-allocate schema array
SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
context.patternPropertiesSchemas = new const BaseSchema<Encoding>*[count];
context.patternPropertiesSchemaCount = 0;
std::memset(context.patternPropertiesSchemas, 0, sizeof(BaseSchema<Encoding>*) * count);
}
2015-05-08 15:07:31 +08:00
return true;
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool Key(Context& context, const Ch* str, SizeType len, bool) const {
2015-05-08 13:37:30 +08:00
if (patternProperties_) {
context.patternPropertiesSchemaCount = 0;
for (SizeType i = 0; i < patternPropertyCount_; i++)
2015-05-08 13:44:52 +08:00
if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
2015-05-08 13:37:30 +08:00
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
}
2015-05-07 00:59:51 +08:00
SizeType index;
if (FindPropertyIndex(str, len, &index)) {
2015-05-08 13:37:30 +08:00
const BaseSchema<Encoding>* propertySchema = properties_[index].typeless ? GetTypeless() : properties_[index].schema;
if (context.patternPropertiesSchemaCount > 0) {
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = propertySchema;
context.valueSchema = GetTypeless();
context.valuePatternValidatorType = kPatternValidatorWithProperty;
}
else
context.valueSchema = propertySchema;
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
if (properties_[index].required)
context.objectRequiredCount++;
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
if (hasDependencies_)
context.objectDependencies[index] = true;
return true;
2015-05-01 17:59:31 +08:00
}
if (additionalPropertiesSchema_) {
2015-05-08 13:37:30 +08:00
if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
context.valueSchema = GetTypeless();
context.valuePatternValidatorType = kPatternValidatorWithAdditionalProperty;
}
else
context.valueSchema = additionalPropertiesSchema_;
2015-05-07 00:59:51 +08:00
return true;
}
else if (additionalProperties_) {
2015-05-07 00:59:51 +08:00
context.valueSchema = GetTypeless();
return true;
}
2015-05-08 13:37:30 +08:00
return context.patternPropertiesSchemaCount != 0; // patternProperties are not additional properties
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
bool EndObject(Context& context, SizeType memberCount) const {
if (context.objectRequiredCount != requiredCount_ || memberCount < minProperties_ || memberCount > maxProperties_)
return false;
2015-05-01 17:59:31 +08:00
if (hasDependencies_) {
2015-05-07 00:59:51 +08:00
for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
if (context.objectDependencies[sourceIndex]) {
if (properties_[sourceIndex].dependencies) {
for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
if (properties_[sourceIndex].dependencies[targetIndex] && !context.objectDependencies[targetIndex])
return false;
}
else if (properties_[sourceIndex].dependenciesSchema)
if (!context.dependencyValidators.validators[sourceIndex]->IsValid())
2015-05-07 00:59:51 +08:00
return false;
}
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
return true;
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
bool StartArray(Context& context) const {
2015-05-08 13:37:30 +08:00
CreateParallelValidator(context);
2015-05-07 00:59:51 +08:00
if ((type_ & (1 << kArraySchemaType)) == 0)
return false;
context.arrayElementIndex = 0;
context.inArray = true;
2015-05-01 17:59:31 +08:00
return true;
}
2015-05-07 00:59:51 +08:00
bool EndArray(Context& context, SizeType elementCount) const {
context.inArray = false;
return elementCount >= minItems_ && elementCount <= maxItems_;
}
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
private:
2015-05-08 14:03:05 +08:00
#if RAPIDJSON_SCHEMA_USE_STDREGEX
2015-05-08 14:09:46 +08:00
typedef std::basic_regex<Ch> RegexType;
2015-05-08 14:03:05 +08:00
#else
typedef char RegexType;
#endif
typedef GenericSchemaValidator<Encoding, BaseReaderHandler<>, CrtAllocator> SchemaValidatorType;
2015-05-07 00:59:51 +08:00
static const BaseSchema<Encoding>* GetTypeless() {
static BaseSchema<Encoding> typeless(Value(kObjectType).Move());
return &typeless;
}
2015-05-07 23:05:05 +08:00
template <typename V1, typename V2>
void AddUniqueElement(V1& a, const V2& v) {
for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
if (*itr == v)
return;
V1 c(v, allocator_);
a.PushBack(c, allocator_);
}
2015-05-07 15:05:55 +08:00
template <typename ValueType>
static const ValueType* GetMember(const ValueType& value, const char* name) {
typename ValueType::ConstMemberIterator itr = value.FindMember(name);
return itr != value.MemberEnd() ? &(itr->value) : 0;
2015-05-07 00:59:51 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 15:05:55 +08:00
template <typename ValueType>
static void AssignIfExist(bool& out, const ValueType& value, const char* name) {
if (const ValueType* v = GetMember(value, name))
if (v->IsBool())
out = v->GetBool();
}
template <typename ValueType>
static void AssignIfExist(SizeType& out, const ValueType& value, const char* name) {
if (const ValueType* v = GetMember(value, name))
if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
out = static_cast<SizeType>(v->GetUint64());
}
template <typename ValueType>
static void AssigIfExist(BaseSchemaArray<Encoding>& out, const ValueType& value, const char* name) {
if (const ValueType* v = GetMember(value, name))
if (v->IsArray() && v->Size() > 0) {
out.count = v->Size();
out.schemas = new BaseSchema*[out.count];
memset(out.schemas, 0, sizeof(BaseSchema*)* out.count);
for (SizeType i = 0; i < out.count; i++)
out.schemas[i] = new BaseSchema<Encoding>((*v)[i]);
}
}
#if RAPIDJSON_SCHEMA_USE_STDREGEX
template <typename ValueType>
2015-05-08 14:03:05 +08:00
static RegexType* CreatePattern(const ValueType& value) {
2015-05-07 15:05:55 +08:00
if (value.IsString())
try {
2015-05-08 14:03:05 +08:00
return new RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
2015-05-07 15:05:55 +08:00
}
catch (const std::regex_error&) {
}
return 0;
}
2015-05-08 14:03:05 +08:00
static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
2015-05-07 15:05:55 +08:00
std::match_results<const Ch*> r;
return std::regex_search(str, str + length, r, *pattern);
2015-05-07 15:05:55 +08:00
}
2015-05-08 13:44:52 +08:00
#else
template <typename ValueType>
2015-05-08 14:03:05 +08:00
RegexType* CreatePattern(const ValueType&) { return 0; }
2015-05-08 13:44:52 +08:00
2015-05-08 14:03:05 +08:00
static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
2015-05-07 15:05:55 +08:00
#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
void AddType(const Value& type) {
if (type == "null" ) type_ |= 1 << kNullSchemaType;
else if (type == "boolean") type_ |= 1 << kBooleanSchemaType;
else if (type == "object" ) type_ |= 1 << kObjectSchemaType;
else if (type == "array" ) type_ |= 1 << kArraySchemaType;
else if (type == "string" ) type_ |= 1 << kStringSchemaType;
else if (type == "integer") type_ |= 1 << kIntegerSchemaType;
else if (type == "number" ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
2015-05-07 00:59:51 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
bool CheckEnum(const GenericValue<Encoding>& v) const {
for (typename GenericValue<Encoding>::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr)
if (v == *itr)
return true;
return false;
}
2015-05-08 13:37:30 +08:00
void CreateParallelValidator(Context& context) const {
2015-05-07 15:12:25 +08:00
if (allOf_.schemas) CreateSchemaValidators(context.allOfValidators, allOf_);
if (anyOf_.schemas) CreateSchemaValidators(context.anyOfValidators, anyOf_);
if (oneOf_.schemas) CreateSchemaValidators(context.oneOfValidators, oneOf_);
2015-05-07 00:59:51 +08:00
if (not_ && !context.notValidator)
context.notValidator = new SchemaValidatorType(*not_);
if (hasSchemaDependencies_ && !context.dependencyValidators.validators) {
context.dependencyValidators.validators = new SchemaValidatorType*[propertyCount_];
context.dependencyValidators.count = propertyCount_;
for (SizeType i = 0; i < propertyCount_; i++)
context.dependencyValidators.validators[i] = properties_[i].dependenciesSchema ? new SchemaValidatorType(*properties_[i].dependenciesSchema) : 0;
}
2015-05-07 00:59:51 +08:00
}
2015-05-07 15:12:25 +08:00
void CreateSchemaValidators(SchemaValidatorArray<Encoding>& validators, const BaseSchemaArray<Encoding>& schemas) const {
2015-05-07 00:59:51 +08:00
if (!validators.validators) {
validators.validators = new SchemaValidatorType*[schemas.count];
2015-05-07 00:59:51 +08:00
validators.count = schemas.count;
for (SizeType i = 0; i < schemas.count; i++)
validators.validators[i] = new SchemaValidatorType(*schemas.schemas[i]);
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
// O(n)
template <typename ValueType>
bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
2015-05-07 15:05:55 +08:00
for (SizeType index = 0; index < propertyCount_; index++)
2015-05-07 00:59:51 +08:00
if (properties_[index].name == name) {
*outIndex = index;
return true;
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
return false;
}
2015-05-01 17:59:31 +08:00
2015-05-07 00:59:51 +08:00
// O(n)
bool FindPropertyIndex(const Ch* str, SizeType length, SizeType* outIndex) const {
2015-05-07 15:05:55 +08:00
for (SizeType index = 0; index < propertyCount_; index++)
if (properties_[index].name.GetStringLength() == length && std::memcmp(properties_[index].name.GetString(), str, length) == 0) {
2015-05-07 00:59:51 +08:00
*outIndex = index;
return true;
2015-05-01 17:59:31 +08:00
}
2015-05-07 00:59:51 +08:00
return false;
2015-05-01 17:59:31 +08:00
}
bool CheckDouble(double d) const {
if (exclusiveMinimum_ ? d <= minimum_ : d < minimum_) return false;
if (exclusiveMaximum_ ? d >= maximum_ : d > maximum_) return false;
2015-05-07 16:42:41 +08:00
if (hasMultipleOf_) {
double a = std::abs(d), b = std::abs(multipleOf_);
double q = std::floor(a / b);
double r = a - q * b;
if (r > 0.0)
return false;
}
2015-05-01 17:59:31 +08:00
return true;
}
2015-05-07 00:59:51 +08:00
struct Property {
2015-05-07 23:05:05 +08:00
Property() : schema(), dependenciesSchema(), dependencies(), required(false), typeless(true) {}
2015-05-07 00:59:51 +08:00
~Property() {
delete schema;
delete dependenciesSchema;
2015-05-07 00:59:51 +08:00
delete[] dependencies;
}
GenericValue<Encoding> name;
2015-05-07 23:05:05 +08:00
const BaseSchema<Encoding>* schema;
const BaseSchema<Encoding>* dependenciesSchema;
2015-05-07 00:59:51 +08:00
bool* dependencies;
bool required;
2015-05-07 23:05:05 +08:00
bool typeless;
2015-05-07 00:59:51 +08:00
};
struct PatternProperty {
PatternProperty() : schema(), pattern() {}
~PatternProperty() {
delete schema;
delete pattern;
}
BaseSchema<Encoding>* schema;
2015-05-08 14:03:05 +08:00
RegexType* pattern;
2015-05-07 00:59:51 +08:00
};
MemoryPoolAllocator<> allocator_;
GenericValue<Encoding> enum_;
BaseSchemaArray<Encoding> allOf_;
BaseSchemaArray<Encoding> anyOf_;
BaseSchemaArray<Encoding> oneOf_;
BaseSchema<Encoding>* not_;
unsigned type_; // bitmask of kSchemaType
Property* properties_;
BaseSchema<Encoding>* additionalPropertiesSchema_;
2015-05-07 00:59:51 +08:00
PatternProperty* patternProperties_;
SizeType patternPropertyCount_;
SizeType propertyCount_;
SizeType requiredCount_;
SizeType minProperties_;
SizeType maxProperties_;
bool additionalProperties_;
2015-05-07 00:59:51 +08:00
bool hasDependencies_;
bool hasSchemaDependencies_;
2015-05-07 00:59:51 +08:00
BaseSchema<Encoding>* additionalItemsSchema_;
2015-05-07 00:59:51 +08:00
BaseSchema<Encoding>* itemsList_;
BaseSchema<Encoding>** itemsTuple_;
SizeType itemsTupleCount_;
SizeType minItems_;
SizeType maxItems_;
bool additionalItems_;
2015-05-08 14:03:05 +08:00
RegexType* pattern_;
2015-05-07 00:59:51 +08:00
SizeType minLength_;
SizeType maxLength_;
2015-05-01 17:59:31 +08:00
double minimum_;
double maximum_;
double multipleOf_;
bool hasMultipleOf_;
bool exclusiveMinimum_;
bool exclusiveMaximum_;
};
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
class GenericSchema {
public:
2015-05-01 20:16:41 +08:00
template <typename T1, typename T2, typename T3>
2015-05-01 17:59:31 +08:00
friend class GenericSchemaValidator;
template <typename DocumentType>
GenericSchema(const DocumentType& document) : root_() {
2015-05-07 00:59:51 +08:00
root_ = new BaseSchema<Encoding>(static_cast<const typename DocumentType::ValueType&>(document));
2015-05-01 17:59:31 +08:00
}
~GenericSchema() {
delete root_;
}
private:
BaseSchema<Encoding>* root_;
};
typedef GenericSchema<UTF8<> > Schema;
template <typename Encoding, typename OutputHandler = BaseReaderHandler<Encoding>, typename Allocator = CrtAllocator >
2015-05-07 10:26:13 +08:00
class GenericSchemaValidator {
2015-05-01 17:59:31 +08:00
public:
typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
2015-05-02 17:46:55 +08:00
typedef GenericSchema<Encoding> SchemaT;
2015-05-07 10:26:13 +08:00
friend class BaseSchema<Encoding>;
2015-05-01 17:59:31 +08:00
GenericSchemaValidator(
2015-05-02 17:46:55 +08:00
const SchemaT& schema,
2015-05-01 17:59:31 +08:00
Allocator* allocator = 0,
2015-05-05 16:44:05 +08:00
size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*,
size_t documentStackCapacity = kDefaultDocumentStackCapacity*/)
2015-05-01 17:59:31 +08:00
:
2015-05-05 16:44:05 +08:00
root_(*schema.root_),
2015-05-01 17:59:31 +08:00
outputHandler_(nullOutputHandler_),
schemaStack_(allocator, schemaStackCapacity),
// documentStack_(allocator, documentStackCapacity),
valid_(true)
2015-05-01 17:59:31 +08:00
{
}
GenericSchemaValidator(
2015-05-02 17:46:55 +08:00
const SchemaT& schema,
2015-05-01 17:59:31 +08:00
OutputHandler& outputHandler,
Allocator* allocator = 0,
2015-05-05 16:44:05 +08:00
size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*,
size_t documentStackCapacity = kDefaultDocumentStackCapacity*/)
2015-05-01 17:59:31 +08:00
:
2015-05-05 16:44:05 +08:00
root_(*schema.root_),
2015-05-01 17:59:31 +08:00
outputHandler_(outputHandler),
schemaStack_(allocator, schemaStackCapacity),
// documentStack_(allocator, documentStackCapacity),
valid_(true)
2015-05-01 17:59:31 +08:00
{
}
~GenericSchemaValidator() {
2015-05-01 17:59:31 +08:00
Reset();
}
void Reset() {
while (!schemaStack_.Empty())
PopSchema();
2015-05-05 16:44:05 +08:00
//documentStack_.Clear();
valid_ = true;
2015-05-01 17:59:31 +08:00
};
2015-05-07 10:26:13 +08:00
bool IsValid() { return valid_; }
2015-05-07 00:59:51 +08:00
#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
if (!valid_) return false; \
2015-05-07 00:59:51 +08:00
if (!BeginValue() || !CurrentSchema().method arg1) return valid_ = false;
2015-05-08 13:37:30 +08:00
#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
for (Context* context = schemaStack_.template Bottom<Context>(); context <= schemaStack_.template Top<Context>(); context++) {\
if (context->allOfValidators.validators)\
for (SizeType i_ = 0; i_ < context->allOfValidators.count; i_++)\
context->allOfValidators.validators[i_]->method arg2;\
if (context->anyOfValidators.validators)\
for (SizeType i_ = 0; i_ < context->anyOfValidators.count; i_++)\
context->anyOfValidators.validators[i_]->method arg2;\
if (context->oneOfValidators.validators)\
for (SizeType i_ = 0; i_ < context->oneOfValidators.count; i_++)\
context->oneOfValidators.validators[i_]->method arg2;\
if (context->notValidator)\
context->notValidator->method arg2;\
if (context->dependencyValidators.validators)\
for (SizeType i_ = 0; i_ < context->dependencyValidators.count; i_++)\
if (context->dependencyValidators.validators[i_])\
context->dependencyValidators.validators[i_]->method arg2;\
2015-05-08 13:37:30 +08:00
if (context->patternPropertiesValidators.validators)\
for (SizeType i_ = 0; i_ < context->patternPropertiesValidators.count; i_++)\
if (context->patternPropertiesValidators.validators[i_])\
context->patternPropertiesValidators.validators[i_]->method arg2; \
}
#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
return valid_ = EndValue() && outputHandler_.method arg2
2015-05-07 00:59:51 +08:00
#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
2015-05-07 10:26:13 +08:00
bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
bool String(const Ch* str, SizeType length, bool copy)
2015-05-07 00:59:51 +08:00
{ RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
2015-05-07 10:26:13 +08:00
bool StartObject() {
2015-05-07 00:59:51 +08:00
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
return valid_ = outputHandler_.StartObject();
}
2015-05-07 10:26:13 +08:00
bool Key(const Ch* str, SizeType len, bool copy) {
if (!valid_) return false;
if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
return valid_ = outputHandler_.Key(str, len, copy);
}
2015-05-07 10:26:13 +08:00
bool EndObject(SizeType memberCount) {
if (!valid_) return false;
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
}
2015-05-07 10:26:13 +08:00
bool StartArray() {
2015-05-07 00:59:51 +08:00
RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
return valid_ = outputHandler_.StartArray();
}
2015-05-07 10:26:13 +08:00
bool EndArray(SizeType elementCount) {
if (!valid_) return false;
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
2015-05-08 13:37:30 +08:00
RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
}
#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
2015-05-08 13:37:30 +08:00
#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
2015-05-05 16:44:05 +08:00
// Implementation of ISchemaValidatorFactory<Encoding>
2015-05-07 10:26:13 +08:00
GenericSchemaValidator<Encoding>* CreateSchemaValidator(const BaseSchema<Encoding>& root) {
2015-05-05 16:44:05 +08:00
return new GenericSchemaValidator(root);
}
2015-05-01 17:59:31 +08:00
private:
typedef BaseSchema<Encoding> BaseSchemaType;
typedef typename BaseSchemaType::Context Context;
2015-05-05 16:44:05 +08:00
GenericSchemaValidator(
const BaseSchemaType& root,
Allocator* allocator = 0,
size_t schemaStackCapacity = kDefaultSchemaStackCapacity/*,
size_t documentStackCapacity = kDefaultDocumentStackCapacity*/)
:
root_(root),
outputHandler_(nullOutputHandler_),
schemaStack_(allocator, schemaStackCapacity),
// documentStack_(allocator, documentStackCapacity),
valid_(true)
2015-05-05 16:44:05 +08:00
{
}
2015-05-07 00:59:51 +08:00
bool BeginValue() {
2015-05-02 17:46:55 +08:00
if (schemaStack_.Empty())
2015-05-05 16:44:05 +08:00
PushSchema(root_);
2015-05-01 17:59:31 +08:00
else {
2015-05-02 10:06:48 +08:00
if (!CurrentSchema().BeginValue(CurrentContext()))
return false;
2015-05-08 13:37:30 +08:00
SizeType count = CurrentContext().patternPropertiesSchemaCount;
const BaseSchemaType** sa = CurrentContext().patternPropertiesSchemas;
PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
2015-05-01 17:59:31 +08:00
if (CurrentContext().valueSchema)
PushSchema(*CurrentContext().valueSchema);
2015-05-08 13:37:30 +08:00
if (count > 0) {
CurrentContext().objectPatternValidatorType = patternValidatorType;
SchemaValidatorArray<Encoding>& va = CurrentContext().patternPropertiesValidators;
va.validators = new GenericSchemaValidator*[count];
for (SizeType i = 0; i < count; i++)
va.validators[va.count++] = CreateSchemaValidator(*sa[i]);
}
2015-05-01 17:59:31 +08:00
}
2015-05-02 17:46:55 +08:00
return true;
2015-05-01 17:59:31 +08:00
}
2015-05-02 12:24:23 +08:00
bool EndValue() {
if (!CurrentSchema().EndValue(CurrentContext()))
return false;
2015-05-02 12:24:23 +08:00
PopSchema();
return true;
}
2015-05-07 10:26:13 +08:00
void PushSchema(const BaseSchemaType& schema) { *schemaStack_.template Push<Context>() = Context(&schema); }
void PopSchema() { schemaStack_.template Pop<Context>(1)->~Context(); }
2015-05-01 20:16:41 +08:00
const BaseSchemaType& CurrentSchema() { return *schemaStack_.template Top<Context>()->schema; }
Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
2015-05-01 17:59:31 +08:00
2015-05-08 13:37:30 +08:00
static const size_t kDefaultSchemaStackCapacity = 1024;
2015-05-05 16:44:05 +08:00
//static const size_t kDefaultDocumentStackCapacity = 256;
const BaseSchemaType& root_;
2015-05-01 17:59:31 +08:00
BaseReaderHandler<Encoding> nullOutputHandler_;
OutputHandler& outputHandler_;
internal::Stack<Allocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
2015-05-05 16:44:05 +08:00
//internal::Stack<Allocator> documentStack_; //!< stack to store the current path of validating document (Value *)
bool valid_;
2015-05-01 17:59:31 +08:00
};
typedef GenericSchemaValidator<UTF8<> > SchemaValidator;
RAPIDJSON_NAMESPACE_END
2015-05-01 22:38:00 +08:00
#if defined(__GNUC__)
RAPIDJSON_DIAG_POP
#endif
2015-05-01 17:59:31 +08:00
#endif // RAPIDJSON_SCHEMA_H_