diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h index bb31cc0d..f911588d 100644 --- a/include/rapidjson/internal/stack.h +++ b/include/rapidjson/internal/stack.h @@ -121,9 +121,24 @@ public: return reinterpret_cast(stackTop_ - sizeof(T)); } + template + const T* Top() const { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* End() { return reinterpret_cast(stackTop_); } + + template + const T* End() const { return reinterpret_cast(stackTop_); } + template T* Bottom() { return (T*)stack_; } + template + const T* Bottom() const { return (T*)stack_; } + Allocator& GetAllocator() { return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index f42f9c91..b3939c2f 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -882,7 +882,7 @@ public: typedef typename ValueType::Ch Ch; virtual ~IGenericRemoteSchemaDocumentProvider() {} - virtual SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; }; typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; @@ -909,10 +909,10 @@ public: schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { - // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. - root_ = CreateSchema(PointerType(), static_cast(document)); + //root_ = CreateSchema(PointerType(), static_cast(document)); + root_ = CreateSchemaRecursive(Pointer(), static_cast(document)); // Resolve $ref while (!schemaRef_.Empty()) { @@ -936,12 +936,27 @@ public: private: struct SchemaEntry { - SchemaEntry(const GenericPointer& p, SchemaType* s) : pointer(p), schema(s) {} - GenericPointer pointer; + SchemaEntry(const PointerType& p, SchemaType* s) : pointer(p), schema(s) {} + PointerType pointer; SchemaType* schema; }; - const SchemaType* CreateSchema(const GenericPointer& pointer, const ValueType& v) { + const SchemaType* CreateSchemaRecursive(const PointerType& pointer, const ValueType& v) { + if (v.GetType() == kObjectType) { + const SchemaType* s = GetSchema(pointer); + if (!s) + s = CreateSchema(pointer, v); + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(pointer.Append(itr->name), itr->value); + return s; + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(pointer.Append(i), v[i]); + return 0; + } + + const SchemaType* CreateSchema(const PointerType& pointer, const ValueType& v) { RAPIDJSON_ASSERT(pointer.IsValid()); SchemaType* schema = new SchemaType(this, pointer, v); new (schemaMap_.template Push()) SchemaEntry(pointer, schema); @@ -959,8 +974,7 @@ private: if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { - if (GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { - printf("remote fragment: %*s\n", len - i, &s[i]); + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { GenericPointer pointer(&s[i], len - i); if (pointer.IsValid()) schema->ref_ = remoteDocument->GetSchema(pointer); @@ -968,7 +982,6 @@ private: } } else if (s[i] == '#') { // Local reference, defer resolution - printf("local fragment: %*s\n", len - i, &s[i]); GenericPointer pointer(&s[i], len - i); if (pointer.IsValid()) new (schemaRef_.template Push()) SchemaEntry(pointer, schema); @@ -977,15 +990,11 @@ private: } } - const SchemaType* GetSchema(const GenericPointer& pointer) { - for (SchemaEntry* target = schemaMap_.template Bottom(); target <= schemaMap_.template Top(); ++target) + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) if (pointer == target->pointer) return target->schema; - - if (const ValueType* v = pointer.Get(document_)) - return CreateSchema(pointer, *v); - else - return 0; + return 0; } static const size_t kInitialSchemaMapSize = 1024; @@ -1061,7 +1070,7 @@ public: if (!BeginValue() || !CurrentSchema().method arg1) return valid_ = false; #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ - for (Context* context = schemaStack_.template Bottom(); context <= schemaStack_.template Top(); context++) {\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ if (context->allOfValidators.validators)\ for (SizeType i_ = 0; i_ < context->allOfValidators.count; i_++)\ static_cast(context->allOfValidators.validators[i_])->method arg2;\ diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 5e318b28..d2fcd73c 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -763,17 +763,16 @@ public: } } - virtual SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { + virtual const SchemaDocument* GetRemoteDocument(const char* uri, SizeType length) { const char* uris[kCount] = { "http://localhost:1234/integer.json", "http://localhost:1234/subSchemas.json", "http://localhost:1234/folder/folderInteger.json" }; - for (size_t i = 0; i < kCount; i++) { + for (size_t i = 0; i < kCount; i++) if (strncmp(uri, uris[i], length) == 0) return sd_[i]; - } return 0; } @@ -809,7 +808,7 @@ TEST(SchemaValidator, TestSuite) { "patternProperties.json", "properties.json", "ref.json", - //"refRemote.json", + "refRemote.json", "required.json", "type.json", //"uniqueItems.json" @@ -854,7 +853,7 @@ TEST(SchemaValidator, TestSuite) { validator.Reset(); bool actual = data.Accept(validator); if (expected != actual) - printf("Fail: %30s \"%s, %s\"\n", filename, description1, description2); + printf("Fail: %30s \"%s\" \"%s\"\n", filename, description1, description2); else passCount++; }