diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index 4c8e39f..002d760 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -45,12 +45,12 @@ RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Forward declarations -template +template class GenericSchemaDocument; namespace internal { -template +template class Schema; /////////////////////////////////////////////////////////////////////////////// @@ -75,9 +75,9 @@ public: /////////////////////////////////////////////////////////////////////////////// // SchemaValidationContext -template +template struct SchemaValidationContext { - typedef Schema SchemaType; + typedef Schema SchemaType; typedef ISchemaValidatorFactory SchemaValidatorFactoryType; enum PatternValidatorType { @@ -142,19 +142,18 @@ struct SchemaValidationContext { /////////////////////////////////////////////////////////////////////////////// // Schema -template +template class Schema { public: - typedef Encoding EncodingType; - typedef typename Encoding::Ch Ch; - typedef SchemaValidationContext Context; - typedef GenericSchemaDocument SchemaDocumentType; - typedef Schema SchemaType; - typedef GenericValue ValueType; - // typedef GenericPointer PointerType; - friend class GenericSchemaDocument; + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + friend SchemaDocumentType; - template Schema(SchemaDocumentType* document, const PointerType& p, const ValueType& value) : not_(), ref_(), @@ -187,6 +186,7 @@ public: exclusiveMinimum_(false), exclusiveMaximum_(false) { + typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; @@ -223,7 +223,7 @@ public: const ValueType* dependencies = GetMember(value, "dependencies"); { // Gather properties from properties/required/dependencies - typedef GenericValue > SValue; + typedef ValueType SValue; SValue allProperties(kArrayType); if (properties && properties->IsObject()) @@ -465,14 +465,14 @@ public: CreateParallelValidator(context); return (type_ & (1 << kNullSchemaType)) && - (!enum_.IsArray() || CheckEnum(GenericValue().Move())); + (!enum_.IsArray() || CheckEnum(ValueType().Move())); } bool Bool(Context& context, bool b) const { CreateParallelValidator(context); return (type_ & (1 << kBooleanSchemaType)) && - (!enum_.IsArray() || CheckEnum(GenericValue(b).Move())); + (!enum_.IsArray() || CheckEnum(ValueType(b).Move())); } bool Int(Context& context, int i) const { @@ -480,7 +480,7 @@ public: if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) return false; - return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue(i).Move())); + return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(ValueType(i).Move())); } bool Uint(Context& context, unsigned u) const { @@ -488,7 +488,7 @@ public: if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) return false; - return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue(u).Move())); + return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(ValueType(u).Move())); } bool Int64(Context& context, int64_t i) const { @@ -496,7 +496,7 @@ public: if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) return false; - return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(GenericValue(i).Move())); + return CheckDouble(i) && (!enum_.IsArray() || CheckEnum(ValueType(i).Move())); } bool Uint64(Context& context, uint64_t u) const { @@ -504,7 +504,7 @@ public: if ((type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))) == 0) return false; - return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(GenericValue(u).Move())); + return CheckDouble(u) && (!enum_.IsArray() || CheckEnum(ValueType(u).Move())); } bool Double(Context& context, double d) const { @@ -512,7 +512,7 @@ public: if ((type_ & (1 << kNumberSchemaType)) == 0) return false; - return CheckDouble(d) && (!enum_.IsArray() || CheckEnum(GenericValue(d).Move())); + return CheckDouble(d) && (!enum_.IsArray() || CheckEnum(ValueType(d).Move())); } bool String(Context& context, const Ch* str, SizeType length, bool) const { @@ -525,14 +525,14 @@ public: // return false; if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; - if (internal::CountStringCodePoint(str, length, &count) && (count < minLength_ || count > maxLength_)) + if (internal::CountStringCodePoint(str, length, &count) && (count < minLength_ || count > maxLength_)) return false; } if (pattern_ && !IsPatternMatch(pattern_, str, length)) return false; - return !enum_.IsArray() || CheckEnum(GenericValue(str, length).Move()); + return !enum_.IsArray() || CheckEnum(ValueType(str, length).Move()); } bool StartObject(Context& context) const { @@ -659,7 +659,7 @@ private: struct SchemaArray { SchemaArray() : schemas(), count() {} ~SchemaArray() { delete[] schemas; } - const Schema** schemas; + const SchemaType** schemas; SizeType count; }; @@ -744,8 +744,8 @@ private: else if (type == "number" ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); } - bool CheckEnum(const GenericValue& v) const { - for (typename GenericValue::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr) + bool CheckEnum(const ValueType& v) const { + for (typename ValueType::ConstValueIterator itr = enum_.Begin(); itr != enum_.End(); ++itr) if (v == *itr) return true; return false; @@ -814,7 +814,7 @@ private: struct Property { Property() : schema(), dependenciesSchema(), dependencies(), required(false), typeless(true) {} ~Property() { delete[] dependencies; } - GenericValue name; + ValueType name; const SchemaType* schema; const SchemaType* dependenciesSchema; bool* dependencies; @@ -829,8 +829,8 @@ private: const RegexType* pattern; }; - Allocator allocator_; - GenericValue enum_; + AllocatorType allocator_; + ValueType enum_; SchemaArray allOf_; SchemaArray anyOf_; SchemaArray oneOf_; @@ -872,20 +872,42 @@ private: } // namespace internal +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template > +class IGenericRemoteSchemaDocumentProvider { +public: + typedef GenericSchemaDocument SchemaDocumentType; + typedef typename ValueType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; +}; + +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + /////////////////////////////////////////////////////////////////////////////// // GenericSchemaDocument -template > +template > class GenericSchemaDocument { public: - typedef internal::Schema SchemaType; - friend class internal::Schema; + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + friend class internal::Schema; - template - GenericSchemaDocument(const DocumentType& document, Allocator* allocator = 0) : root_(), schemas_(), schemaCount_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { - typedef typename DocumentType::ValueType ValueType; - typedef SchemaEntry SchemaEntryType; - typedef GenericPointer PointerType; + GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + remoteProvider_(remoteProvider), + root_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. @@ -893,13 +915,13 @@ public: // Resolve $ref while (!schemaRef_.Empty()) { - SchemaEntryType* refEntry = schemaRef_.template Pop(1); + SchemaEntry* refEntry = schemaRef_.template Pop(1); PointerType p = refEntry->pointer; // Due to re-entrance, SchemaType* source = refEntry->schema; // backup the entry first, - refEntry->~SchemaEntryType(); // and then destruct it. + refEntry->~SchemaEntry(); // and then destruct it. bool resolved = false; - for (SchemaEntryType* target = schemaMap_.template Bottom(); target <= schemaMap_.template Top(); ++target) + for (SchemaEntry* target = schemaMap_.template Bottom(); target <= schemaMap_.template Top(); ++target) if (p == target->pointer) { source->ref_ = target->schema; resolved = true; @@ -911,73 +933,89 @@ public: if (const ValueType* v = p.Get(document)) source->ref_ = CreateSchema(p, *v); // cause re-entrance (modifying schemaRef_) } - } - // Copy to schemas_ and destroy schemaMap_ entries. - schemas_ = new SchemaType*[schemaCount_]; - size_t i = schemaCount_; - while (!schemaMap_.Empty()) { - SchemaEntryType* e = schemaMap_.template Pop(1); - schemas_[--i] = e->schema; - e->~SchemaEntryType(); } } ~GenericSchemaDocument() { - for (size_t i = 0; i < schemaCount_; i++) - delete schemas_[i]; - delete [] schemas_; + while (!schemaMap_.Empty()) { + SchemaEntry* e = schemaMap_.template Pop(1); + delete e->schema; + e->~SchemaEntry(); + } } const SchemaType& GetRoot() const { return *root_; } private: - template struct SchemaEntry { SchemaEntry(const GenericPointer& p, SchemaType* s) : pointer(p), schema(s) {} GenericPointer pointer; SchemaType* schema; }; - template const SchemaType* CreateSchema(const GenericPointer& pointer, const ValueType& v) { RAPIDJSON_ASSERT(pointer.IsValid()); SchemaType* schema = new SchemaType(this, pointer, v); - new (schemaMap_.template Push >()) SchemaEntry(pointer, schema); - schemaCount_++; + new (schemaMap_.template Push()) SchemaEntry(pointer, schema); return schema; } - template void AddRefSchema(SchemaType* schema, const ValueType& v) { if (v.IsString()) { - GenericPointer pointer(v.GetString(), v.GetStringLength()); - if (pointer.IsValid()) - new (schemaRef_.template Push >()) SchemaEntry(pointer, schema); + SizeType len = v.GetStringLength(); + if (len > 0) { + const Ch* s = v.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (s[i] == '#') { + if (i > 0) { // Remote reference, resolve immediately + if (remoteProvider_) { + GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i); + GenericPointer pointer(s, len - i); + schema->ref_ = remoteDocument->GetSchema(pointer); + } + } + else { // Local reference, defer resolution + GenericPointer pointer(v.GetString(), v.GetStringLength()); + if (pointer.IsValid()) + new (schemaRef_.template Push()) SchemaEntry(pointer, schema); + } + } + } } } + const SchemaType* GetSchema(const GenericPointer& pointer) { + (void)pointer; + return 0; + } + static const size_t kInitialSchemaMapSize = 1024; static const size_t kInitialSchemaRefSize = 1024; + IRemoteSchemaDocumentProviderType* remoteProvider_; const SchemaType* root_; //!< Root schema. - SchemaType** schemas_; //!< ALl schemas are owned by SchemaDocument - size_t schemaCount_; //!< Number of schemas owned internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref }; -typedef GenericSchemaDocument > SchemaDocument; +typedef GenericSchemaDocument SchemaDocument; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaValidator -template , typename StateAllocator = CrtAllocator > -class GenericSchemaValidator : public internal::ISchemaValidatorFactory, public internal::ISchemaValidator { +template , typename StateAllocator = CrtAllocator > +class GenericSchemaValidator : + public internal::ISchemaValidatorFactory, + public internal::ISchemaValidator +{ public: + typedef typename SchemaDocumentType::SchemaType SchemaType; typedef typename SchemaType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; - typedef GenericSchemaDocument SchemaDocumentType; GenericSchemaValidator( const SchemaDocumentType& schemaDocument, @@ -1176,7 +1214,7 @@ private: bool valid_; }; -typedef GenericSchemaValidator SchemaValidator; +typedef GenericSchemaValidator SchemaValidator; RAPIDJSON_NAMESPACE_END