diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h index e51b369..5a81854 100644 --- a/include/rapidjson/schema.h +++ b/include/rapidjson/schema.h @@ -349,6 +349,7 @@ public: Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), + uri_(schemaDocument->GetURI(), *allocator), pointer_(p), typeless_(schemaDocument->GetTypeless()), enum_(), @@ -597,6 +598,10 @@ public: #endif } + const SValue& GetURI() const { + return uri_; + } + const PointerType& GetPointer() const { return pointer_; } @@ -1220,6 +1225,7 @@ private: }; AllocatorType* allocator_; + SValue uri_; PointerType pointer_; const SchemaType* typeless_; uint64_t* enum_; @@ -1330,6 +1336,7 @@ public: typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; + typedef GenericValue URIType; friend class internal::Schema; template friend class GenericSchemaValidator; @@ -1339,10 +1346,13 @@ public: Compile a JSON document into schema document. \param document A JSON document as source. + \param uri The base URI of this schema document for purposes of violation reporting. + \param uriLength Length of \c name, in code points. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. */ - explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0, + IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), @@ -1354,8 +1364,11 @@ public: if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + Ch noUri[1] = {0}; + uri_.SetString(uri ? uri : noUri, uriLength, *allocator_); + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); - new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. @@ -1393,7 +1406,8 @@ public: root_(rhs.root_), typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), - schemaRef_(std::move(rhs.schemaRef_)) + schemaRef_(std::move(rhs.schemaRef_)), + uri_(std::move(rhs.uri_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; @@ -1415,6 +1429,8 @@ public: RAPIDJSON_DELETE(ownAllocator_); } + const URIType& GetURI() const { return uri_; } + //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } @@ -1545,6 +1561,7 @@ private: SchemaType* typeless_; internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref + URIType uri_; }; //! GenericSchemaDocument using Value type. diff --git a/test/unittest/schematest.cpp b/test/unittest/schematest.cpp index 6c395d1..34436ac 100644 --- a/test/unittest/schematest.cpp +++ b/test/unittest/schematest.cpp @@ -1071,6 +1071,12 @@ public: "jsonschema/remotes/folder/folderInteger.json", "draft-04/schema" }; + const char* uris[kCount] = { + "http://localhost:1234/integer.json", + "http://localhost:1234/subSchemas.json", + "http://localhost:1234/folder/folderInteger.json", + "http://json-schema.org/draft-04/schema" + }; for (size_t i = 0; i < kCount; i++) { sd_[i] = 0; @@ -1087,7 +1093,7 @@ public: MemoryPoolAllocator<> stackAllocator(stackBuffer, sizeof(stackBuffer)); DocumentType d(&documentAllocator_, 1024, &stackAllocator); d.Parse(json); - sd_[i] = new SchemaDocumentType(d, 0, &schemaAllocator_); + sd_[i] = new SchemaDocumentType(d, uris[i], static_cast(strlen(uris[i])), 0, &schemaAllocator_); MemoryPoolAllocator<>::Free(json); } }; @@ -1099,15 +1105,8 @@ public: } virtual const SchemaDocumentType* 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", - "http://json-schema.org/draft-04/schema" - }; - for (size_t i = 0; i < kCount; i++) - if (strncmp(uri, uris[i], length) == 0 && strlen(uris[i]) == length) + if (typename SchemaDocumentType::URIType(uri, length) == sd_[i]->GetURI()) return sd_[i]; return 0; } @@ -1196,7 +1195,7 @@ TEST(SchemaValidator, TestSuite) { else { for (Value::ConstValueIterator schemaItr = d.Begin(); schemaItr != d.End(); ++schemaItr) { { - SchemaDocumentType schema((*schemaItr)["schema"], &provider, &schemaAllocator); + SchemaDocumentType schema((*schemaItr)["schema"], filenames[i], static_cast(strlen(filenames[i])), &provider, &schemaAllocator); GenericSchemaValidator >, MemoryPoolAllocator<> > validator(schema, &validatorAllocator); const char* description1 = (*schemaItr)["description"].GetString(); const Value& tests = (*schemaItr)["tests"]; @@ -1359,7 +1358,7 @@ TEST(SchemaValidator, Ref_remote) { RemoteSchemaDocumentProvider provider; Document sd; sd.Parse("{\"$ref\": \"http://localhost:1234/subSchemas.json#/integer\"}"); - SchemaDocumentType s(sd, &provider); + SchemaDocumentType s(sd, 0, 0, &provider); typedef GenericSchemaValidator >, MemoryPoolAllocator<> > SchemaValidatorType; typedef GenericPointer > PointerType; INVALIDATE_(s, "null", "/integer", "type", "", SchemaValidatorType, PointerType);