Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 15 ++++++++++++--- dlls/opcservices/uri.c | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 17b7609739..a0621760b4 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -521,7 +521,7 @@ static void test_rel_part_uri(void) IOpcPartUri *rel_uri2; IOpcUri *source_uri2; IUnknown *unk = NULL; - BOOL ret = FALSE; + BOOL ret; BSTR str;
hr = IOpcPartUri_GetSourceUri(rel_uri, &source_uri); @@ -529,11 +529,20 @@ static void test_rel_part_uri(void) hr = IOpcPartUri_GetSourceUri(rel_uri, &source_uri2); ok(SUCCEEDED(hr), "Failed to get source uri, hr %#x.\n", hr); ok(source_uri != source_uri2, "Unexpected instance.\n"); + + hr = IOpcUri_IsEqual(source_uri, NULL, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + ret = 123; + hr = IOpcUri_IsEqual(source_uri, NULL, &ret); + ok(is_root ? hr == E_POINTER : hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(is_root ? ret == 123 : !ret, "Unexpected result.\n"); + + ret = FALSE; hr = IOpcUri_IsEqual(source_uri, (IUri *)source_uri2, &ret); - todo_wine { ok(SUCCEEDED(hr), "IsEqual failed, hr %#x.\n", hr); ok(ret, "Expected equal uris.\n"); - } + hr = IOpcUri_QueryInterface(source_uri, &IID_IOpcPartUri, (void **)&unk); ok(hr == (is_root ? E_NOINTERFACE : S_OK), "Unexpected hr %#x, %s.\n", hr, rel_part_uri_tests[i].uri); if (unk) diff --git a/dlls/opcservices/uri.c b/dlls/opcservices/uri.c index ddb2c05daf..fa5ddbcde8 100644 --- a/dlls/opcservices/uri.c +++ b/dlls/opcservices/uri.c @@ -312,7 +312,21 @@ static HRESULT WINAPI opc_uri_IsEqual(IOpcPartUri *iface, IUri *comparand, BOOL
TRACE("iface %p, comparand %p, is_equal %p.\n", iface, comparand, is_equal);
- return IUri_IsEqual(uri->uri, comparand, is_equal); + if (!is_equal) + return E_POINTER; + + if (!comparand) + { + if (uri->is_part_uri) + { + *is_equal = FALSE; + return S_OK; + } + + return E_POINTER; + } + + return IUri_IsEqual(comparand, uri->uri, is_equal); }
static HRESULT WINAPI opc_uri_GetRelationshipsPartUri(IOpcPartUri *iface, IOpcPartUri **part_uri)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index a0621760b4..a96a5cf078 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -923,6 +923,86 @@ static void test_rels_enumerator(void) IOpcPackage_Release(package); IOpcFactory_Release(factory); } + +static void test_relative_uri(void) +{ + static const struct + { + const char *part; + const char *combined; + const char *relative; + const char *relative_broken; + } + relative_uri_tests[] = + { + { "/", "/path/path2", "path/path2", "/path/path2" }, + { "/", "/path", "path", "/path" }, + { "/path/path2", "/path/path2/path3", "path2/path3" }, + { "/path/path2", "/path3", "../path3" }, + { "/path", "/path", "" }, + { "/path", "../path", "" }, + { "/path2", "/path", "path" }, + { "../path", "/path", "" }, + { "../../path", "/path", "" }, + }; + IOpcFactory *factory; + unsigned int i; + + factory = create_factory(); + + for (i = 0; i < ARRAY_SIZE(relative_uri_tests); ++i) + { + WCHAR *uriW, *combinedW, *relativeW, *relative_broken_W; + IOpcPartUri *combined_uri; + IUri *relative_uri; + IOpcUri *part_uri; + IUnknown *unk; + HRESULT hr; + BSTR str; + + uriW = strdupAtoW(relative_uri_tests[i].part); + combinedW = strdupAtoW(relative_uri_tests[i].combined); + relativeW = strdupAtoW(relative_uri_tests[i].relative); + relative_broken_W = strdupAtoW(relative_uri_tests[i].relative_broken); + + if (!strcmp(relative_uri_tests[i].part, "/")) + hr = IOpcFactory_CreatePackageRootUri(factory, &part_uri); + else + hr = IOpcFactory_CreatePartUri(factory, uriW, (IOpcPartUri **)&part_uri); + ok(SUCCEEDED(hr), "%u: failed to create part uri, hr %#x.\n", i, hr); + + hr = IOpcFactory_CreatePartUri(factory, combinedW, &combined_uri); + ok(SUCCEEDED(hr), "%u: failed to create part uri, hr %#x.\n", i, hr); + + hr = IOpcUri_GetRelativeUri(part_uri, combined_uri, &relative_uri); + todo_wine + ok(SUCCEEDED(hr), "%u: failed t oget relative uri, hr %#x.\n", i, hr); + + if (SUCCEEDED(hr)) + { + hr = IUri_QueryInterface(relative_uri, &IID_IOpcUri, (void **)&unk); + ok(hr == E_NOINTERFACE, "%u: unexpected hr %#x.\n", i, hr); + + hr = IUri_GetRawUri(relative_uri, &str); + ok(SUCCEEDED(hr), "%u: failed to get raw uri, hr %#x.\n", i, hr); + ok(!lstrcmpW(str, relativeW) || broken(relative_broken_W && !lstrcmpW(str, relative_broken_W)), + "%u: unexpected relative uri %s.\n", i, wine_dbgstr_w(str)); + SysFreeString(str); + + IUri_Release(relative_uri); + } + IOpcUri_Release(part_uri); + IOpcPartUri_Release(combined_uri); + + heap_free(uriW); + heap_free(combinedW); + heap_free(relativeW); + heap_free(relative_broken_W); + } + + IOpcFactory_Release(factory); +} + START_TEST(opcservices) { IOpcFactory *factory; @@ -943,6 +1023,7 @@ START_TEST(opcservices) test_rel_part_uri(); test_part_enumerator(); test_rels_enumerator(); + test_relative_uri();
IOpcFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/factory.c | 26 +++++- dlls/opcservices/tests/opcservices.c | 135 +++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c index 45e7ad71e4..9c04964498 100644 --- a/dlls/opcservices/factory.c +++ b/dlls/opcservices/factory.c @@ -320,19 +320,41 @@ static HRESULT WINAPI opc_factory_CreatePackageRootUri(IOpcFactory *iface, IOpcU
static HRESULT WINAPI opc_factory_CreatePartUri(IOpcFactory *iface, LPCWSTR uri, IOpcPartUri **out) { - IUri *part_uri; + static const WCHAR rootW[] = {'/',0}; + IUri *part_uri, *root_uri, *combined; HRESULT hr;
TRACE("iface %p, uri %s, out %p.\n", iface, debugstr_w(uri), out);
+ if (!out) + return E_POINTER; + + *out = NULL; + if (FAILED(hr = CreateUri(uri, Uri_CREATE_ALLOW_RELATIVE, 0, &part_uri))) { WARN("Failed to create uri, hr %#x.\n", hr); return hr; }
- hr = opc_part_uri_create(part_uri, NULL, out); + if (FAILED(hr = CreateUri(rootW, Uri_CREATE_ALLOW_RELATIVE, 0, &root_uri))) + { + WARN("Failed to create root uri, hr %#x.\n", hr); + IUri_Release(part_uri); + return hr; + } + + hr = CoInternetCombineIUri(root_uri, part_uri, 0, &combined, 0); + IUri_Release(root_uri); IUri_Release(part_uri); + if (FAILED(hr)) + { + WARN("Failed to combine URIs, hr %#x.\n", hr); + return hr; + } + + hr = opc_part_uri_create(combined, NULL, out); + IUri_Release(combined); return hr; }
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index a96a5cf078..986aae468a 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -448,8 +448,15 @@ static void test_rel_part_uri(void) } rel_part_uri_tests[] = { { "/uri", "/_rels/uri.rels" }, + { "/path/uri", "/path/_rels/uri.rels" }, + { "path/uri", "/path/_rels/uri.rels" }, + { "../path/uri", "/path/_rels/uri.rels" }, + { "../../path/uri", "/path/_rels/uri.rels" }, { "/uri.ext", "/_rels/uri.ext.rels" }, { "/", "/_rels/.rels" }, + { "uri", "/_rels/uri.rels" }, + { "/path/../uri", "/_rels/uri.rels" }, + { "/path/path/../../uri", "/_rels/uri.rels" }, { "/_rels/uri.ext.rels", "", OPC_E_NONCONFORMING_URI }, }; static const struct @@ -459,6 +466,7 @@ static void test_rel_part_uri(void) } is_rel_part_tests[] = { { "/uri", FALSE }, + { "uri", FALSE }, { "/_rels/uri", FALSE }, { "/_rels/uri/uri", FALSE }, { "/_rels/uri/uri.rels", FALSE }, @@ -558,6 +566,7 @@ static void test_rel_part_uri(void)
hr = IOpcPartUri_GetRawUri(rel_uri, &str); ok(SUCCEEDED(hr), "Failed to get rel uri, hr %#x.\n", hr); + todo_wine_if(i == 3 || i == 4 || i == 8 || i == 9) ok(!lstrcmpW(str, rel_uriW), "%u: unexpected rel uri %s, expected %s.\n", i, wine_dbgstr_w(str), wine_dbgstr_w(rel_uriW)); SysFreeString(str); @@ -1003,6 +1012,130 @@ static void test_relative_uri(void) IOpcFactory_Release(factory); }
+static void test_combine_uri(void) +{ + static const struct + { + const char *uri; + const char *relative; + const char *combined; + } + combine_tests[] = + { + { "/", "path", "/path" }, + { "/path1", "path2", "/path2" }, + { "/path1", "../path2", "/path2" }, + { "/path1/../path2", "path3", "/path3" }, + }; + IOpcFactory *factory; + unsigned int i; + + factory = create_factory(); + + for (i = 0; i < ARRAY_SIZE(combine_tests); ++i) + { + WCHAR *uriW, *relativeW, *combinedW; + IOpcPartUri *combined_uri; + IUri *relative_uri; + IOpcUri *uri; + HRESULT hr; + BSTR str; + + uriW = strdupAtoW(combine_tests[i].uri); + relativeW = strdupAtoW(combine_tests[i].relative); + combinedW = strdupAtoW(combine_tests[i].combined); + + if (!strcmp(combine_tests[i].uri, "/")) + hr = IOpcFactory_CreatePackageRootUri(factory, &uri); + else + hr = IOpcFactory_CreatePartUri(factory, uriW, (IOpcPartUri **)&uri); + + hr = CreateUri(relativeW, Uri_CREATE_ALLOW_RELATIVE, 0, &relative_uri); + ok(SUCCEEDED(hr), "%u: failed to create relative uri, hr %#x.\n", i, hr); + + hr = IOpcUri_CombinePartUri(uri, relative_uri, &combined_uri); + todo_wine + ok(SUCCEEDED(hr), "%u: failed to combine uris, hr %#x.\n", i, hr); + + if (SUCCEEDED(hr)) + { + hr = IOpcPartUri_GetRawUri(combined_uri, &str); + ok(SUCCEEDED(hr), "%u: failed to get raw uri, hr %#x.\n", i, hr); + ok(!lstrcmpW(str, combinedW), "%u: unexpected uri %s.\n", i, wine_dbgstr_w(str)); + SysFreeString(str); + + IOpcPartUri_Release(combined_uri); + } + heap_free(uriW); + heap_free(relativeW); + heap_free(combinedW); + + IOpcUri_Release(uri); + IUri_Release(relative_uri); + } + + IOpcFactory_Release(factory); +} + +static void test_create_part_uri(void) +{ + static const struct + { + const char *input; + const char *raw_uri; + } + create_part_uri_tests[] = + { + { "path", "/path" }, + { "../path", "/path" }, + { "../../path", "/path" }, + { "/path", "/path" }, + { "/path1/path2/path3/../path4", "/path1/path2/path4" }, + }; + IOpcFactory *factory; + unsigned int i; + HRESULT hr; + + factory = create_factory(); + + for (i = 0; i < ARRAY_SIZE(create_part_uri_tests); ++i) + { + IOpcPartUri *part_uri; + WCHAR *inputW, *rawW; + IUri *uri; + BSTR str; + BOOL ret; + + inputW = strdupAtoW(create_part_uri_tests[i].input); + rawW = strdupAtoW(create_part_uri_tests[i].raw_uri); + + hr = IOpcFactory_CreatePartUri(factory, inputW, &part_uri); + ok(SUCCEEDED(hr), "%u: failed to create part uri, hr %#x.\n", i, hr); + + hr = IOpcPartUri_GetRawUri(part_uri, &str); + ok(SUCCEEDED(hr), "Failed to get raw uri, hr %#x.\n", hr); + todo_wine_if(i == 1 || i == 2 || i == 4) + ok(!lstrcmpW(str, rawW), "%u: unexpected raw uri %s.\n", i, wine_dbgstr_w(str)); + SysFreeString(str); + + hr = CreateUri(rawW, Uri_CREATE_ALLOW_RELATIVE, 0, &uri); + ok(SUCCEEDED(hr), "Failed to create uri, hr %#x.\n", hr); + + ret = FALSE; + hr = IOpcPartUri_IsEqual(part_uri, uri, &ret); + ok(SUCCEEDED(hr), "IsEqual failed, hr %#x.\n", hr); + todo_wine_if(i == 1 || i == 2 || i == 4) + ok(!!ret, "%u: unexpected result %d.\n", i, ret); + + IOpcPartUri_Release(part_uri); + + heap_free(inputW); + heap_free(rawW); + } + + IOpcFactory_Release(factory); +} + START_TEST(opcservices) { IOpcFactory *factory; @@ -1024,6 +1157,8 @@ START_TEST(opcservices) test_part_enumerator(); test_rels_enumerator(); test_relative_uri(); + test_combine_uri(); + test_create_part_uri();
IOpcFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/tests/opcservices.c | 14 ++++++++++---- dlls/opcservices/uri.c | 21 +++++++++++++++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 986aae468a..ab8c2e47a5 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -1053,19 +1053,25 @@ static void test_combine_uri(void) hr = CreateUri(relativeW, Uri_CREATE_ALLOW_RELATIVE, 0, &relative_uri); ok(SUCCEEDED(hr), "%u: failed to create relative uri, hr %#x.\n", i, hr);
+ combined_uri = (void *)0xdeadbeef; + hr = IOpcUri_CombinePartUri(uri, NULL, &combined_uri); + ok(hr == E_POINTER, "%u: failed to combine uris, hr %#x.\n", i, hr); + ok(!combined_uri, "Unexpected instance.\n"); + + hr = IOpcUri_CombinePartUri(uri, relative_uri, NULL); + ok(hr == E_POINTER, "%u: failed to combine uris, hr %#x.\n", i, hr); + hr = IOpcUri_CombinePartUri(uri, relative_uri, &combined_uri); - todo_wine ok(SUCCEEDED(hr), "%u: failed to combine uris, hr %#x.\n", i, hr);
- if (SUCCEEDED(hr)) - { hr = IOpcPartUri_GetRawUri(combined_uri, &str); ok(SUCCEEDED(hr), "%u: failed to get raw uri, hr %#x.\n", i, hr); + todo_wine_if(i == 2 || i == 3) ok(!lstrcmpW(str, combinedW), "%u: unexpected uri %s.\n", i, wine_dbgstr_w(str)); SysFreeString(str);
IOpcPartUri_Release(combined_uri); - } + heap_free(uriW); heap_free(relativeW); heap_free(combinedW); diff --git a/dlls/opcservices/uri.c b/dlls/opcservices/uri.c index fa5ddbcde8..800ae34571 100644 --- a/dlls/opcservices/uri.c +++ b/dlls/opcservices/uri.c @@ -357,9 +357,26 @@ static HRESULT WINAPI opc_uri_GetRelativeUri(IOpcPartUri *iface, IOpcPartUri *pa
static HRESULT WINAPI opc_uri_CombinePartUri(IOpcPartUri *iface, IUri *relative_uri, IOpcPartUri **combined) { - FIXME("iface %p, relative_uri %p, combined %p stub!\n", iface, relative_uri, combined); + struct opc_uri *uri = impl_from_IOpcPartUri(iface); + IUri *combined_uri; + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, relative_uri %p, combined %p.\n", iface, relative_uri, combined); + + if (!combined) + return E_POINTER; + + *combined = NULL; + + if (!relative_uri) + return E_POINTER; + + if (FAILED(hr = CoInternetCombineIUri(uri->uri, relative_uri, 0, &combined_uri, 0))) + return hr; + + hr = opc_part_uri_create(combined_uri, NULL, combined); + IUri_Release(combined_uri); + return hr; }
static HRESULT WINAPI opc_uri_ComparePartUri(IOpcPartUri *iface, IOpcPartUri *part_uri,
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 66 +++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index f3503945b5..5c338f7c13 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -1493,7 +1493,69 @@ static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlW return hr; }
-HRESULT opc_package_write(IOpcPackage *input, OPC_WRITE_FLAGS flags, IStream *stream) +static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *part) +{ + OPC_COMPRESSION_OPTIONS options = OPC_COMPRESSION_NORMAL; + IStream *content = NULL; + IOpcPartUri *name; + BSTR uri = NULL; + HRESULT hr; + + if (FAILED(hr = IOpcPart_GetName(part, &name))) + return hr; + + hr = IOpcPartUri_GetRawUri(name, &uri); + if (SUCCEEDED(hr)) + hr = IOpcPart_GetCompressionOptions(part, &options); + if (SUCCEEDED(hr)) + hr = IOpcPart_GetContentStream(part, &content); + if (SUCCEEDED(hr)) + { + /* Part names always start with root '/', skip it. */ + hr = compress_add_file(archive, uri + 1, content, options); + } + + SysFreeString(uri); + if (content) + IStream_Release(content); + + return hr; +} + +static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage *package) +{ + IOpcPartEnumerator *parts; + IOpcPartSet *part_set; + BOOL got_next; + HRESULT hr; + + if (FAILED(hr = IOpcPackage_GetPartSet(package, &part_set))) + return hr; + + hr = IOpcPartSet_GetEnumerator(part_set, &parts); + IOpcPartSet_Release(part_set); + if (FAILED(hr)) + return hr; + + while (IOpcPartEnumerator_MoveNext(parts, &got_next) == S_OK && got_next) + { + IOpcPart *part; + + if (FAILED(hr = IOpcPartEnumerator_GetCurrent(parts, &part))) + break; + + hr = opc_package_write_part(archive, part); + IOpcPart_Release(part); + if (FAILED(hr)) + break; + } + + IOpcPartEnumerator_Release(parts); + + return hr; +} + +HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *stream) { struct zip_archive *archive; IXmlWriter *writer; @@ -1513,6 +1575,8 @@ HRESULT opc_package_write(IOpcPackage *input, OPC_WRITE_FLAGS flags, IStream *st
/* [Content_Types].xml */ hr = opc_package_write_contenttypes(archive, writer); + if (SUCCEEDED(hr)) + hr = opc_package_write_parts(archive, package);
compress_finalize_archive(archive); IXmlWriter_Release(writer);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 133 +++++++++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 4 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 5c338f7c13..fab337d6f5 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -1493,7 +1493,120 @@ static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlW return hr; }
-static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *part) +static HRESULT opc_package_write_rel(IOpcRelationship *rel, IXmlWriter *writer) +{ + static const WCHAR relationshipW[] = {'R','e','l','a','t','i','o','n','s','h','i','p',0}; + static const WCHAR targetW[] = {'T','a','r','g','e','t',0}; + static const WCHAR typeW[] = {'T','y','p','e',0}; + static const WCHAR idW[] = {'I','d',0}; + BSTR target_uri; + HRESULT hr; + WCHAR *str; + IUri *uri; + + if (FAILED(hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipW, NULL))) + return hr; + + if (FAILED(hr = IOpcRelationship_GetTargetUri(rel, &uri))) + return hr; + + IUri_GetRawUri(uri, &target_uri); + IUri_Release(uri); + + hr = IXmlWriter_WriteAttributeString(writer, NULL, targetW, NULL, target_uri); + SysFreeString(target_uri); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = IOpcRelationship_GetId(rel, &str))) + return hr; + + hr = IXmlWriter_WriteAttributeString(writer, NULL, idW, NULL, str); + CoTaskMemFree(str); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = IOpcRelationship_GetRelationshipType(rel, &str))) + return hr; + + hr = IXmlWriter_WriteAttributeString(writer, NULL, typeW, NULL, str); + CoTaskMemFree(str); + if (FAILED(hr)) + return hr; + + return IXmlWriter_WriteEndElement(writer); +} + +static HRESULT opc_package_write_rels(struct zip_archive *archive, IOpcRelationshipSet *rels, + IOpcUri *uri, IXmlWriter *writer) +{ + static const WCHAR uriW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','o','p','e','n','x','m','l','f','o','r','m','a','t','s','.','o','r','g','/', + 'p','a','c','k','a','g','e','/','2','0','0','6','/','r','e','l','a','t','i','o','n','s','h','i','p','s',0}; + static const WCHAR relationshipsW[] = {'R','e','l','a','t','i','o','n','s','h','i','p','s',0}; + IOpcRelationshipEnumerator *enumerator; + IOpcPartUri *rels_uri; + BSTR rels_part_uri; + IStream *content; + BOOL has_next; + HRESULT hr; + + if (FAILED(hr = IOpcRelationshipSet_GetEnumerator(rels, &enumerator))) + return hr; + + hr = IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next); + if (!has_next) + { + IOpcRelationshipEnumerator_Release(enumerator); + return hr; + } + + if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content))) + { + IOpcRelationshipEnumerator_Release(enumerator); + return hr; + } + + IXmlWriter_SetOutput(writer, (IUnknown *)content); + + hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipsW, uriW); + + while (has_next) + { + IOpcRelationship *rel; + + if (FAILED(hr = IOpcRelationshipEnumerator_GetCurrent(enumerator, &rel))) + break; + + hr = opc_package_write_rel(rel, writer); + IOpcRelationship_Release(rel); + if (FAILED(hr)) + break; + + IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next); + } + + IOpcRelationshipEnumerator_Release(enumerator); + + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteEndDocument(writer); + if (SUCCEEDED(hr)) + hr = IXmlWriter_Flush(writer); + + hr = IOpcUri_GetRelationshipsPartUri(uri, &rels_uri); + if (SUCCEEDED(hr)) + hr = IOpcPartUri_GetRawUri(rels_uri, &rels_part_uri); + if (SUCCEEDED(hr)) + hr = compress_add_file(archive, rels_part_uri, content, OPC_COMPRESSION_NORMAL); + + SysFreeString(rels_part_uri); + IStream_Release(content); + + return hr; +} + +static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *part, IXmlWriter *writer) { OPC_COMPRESSION_OPTIONS options = OPC_COMPRESSION_NORMAL; IStream *content = NULL; @@ -1522,7 +1635,7 @@ static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *par return hr; }
-static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage *package) +static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage *package, IXmlWriter *writer) { IOpcPartEnumerator *parts; IOpcPartSet *part_set; @@ -1544,7 +1657,7 @@ static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage if (FAILED(hr = IOpcPartEnumerator_GetCurrent(parts, &part))) break;
- hr = opc_package_write_part(archive, part); + hr = opc_package_write_part(archive, part, writer); IOpcPart_Release(part); if (FAILED(hr)) break; @@ -1557,7 +1670,9 @@ static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage
HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *stream) { + IOpcRelationshipSet *rels = NULL; struct zip_archive *archive; + IOpcUri *uri = NULL; IXmlWriter *writer; HRESULT hr;
@@ -1575,11 +1690,21 @@ HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *
/* [Content_Types].xml */ hr = opc_package_write_contenttypes(archive, writer); + /* Package relationships. */ + if (SUCCEEDED(hr)) + hr = IOpcPackage_GetRelationshipSet(package, &rels); + if (SUCCEEDED(hr)) + hr = opc_root_uri_create(&uri); + if (SUCCEEDED(hr)) + hr = opc_package_write_rels(archive, rels, uri, writer); + /* Parts. */ if (SUCCEEDED(hr)) - hr = opc_package_write_parts(archive, package); + hr = opc_package_write_parts(archive, package, writer);
+ IOpcRelationshipSet_Release(rels); compress_finalize_archive(archive); IXmlWriter_Release(writer); + IOpcUri_Release(uri);
return hr; }
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index fab337d6f5..c865cf35ad 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -1476,9 +1476,9 @@ static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlW if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content))) return hr;
- IXmlWriter_SetOutput(writer, (IUnknown *)content); - - hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); + hr = IXmlWriter_SetOutput(writer, (IUnknown *)content); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); if (SUCCEEDED(hr)) hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW); if (SUCCEEDED(hr)) @@ -1566,9 +1566,9 @@ static HRESULT opc_package_write_rels(struct zip_archive *archive, IOpcRelations return hr; }
- IXmlWriter_SetOutput(writer, (IUnknown *)content); - - hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes); + hr = IXmlWriter_SetOutput(writer, (IUnknown *)content); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes); if (SUCCEEDED(hr)) hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipsW, uriW);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 52 ++++++++++++++++++++++++---- dlls/opcservices/tests/opcservices.c | 51 +++++++++++++++++++++++++-- include/opcbase.idl | 2 ++ 3 files changed, 96 insertions(+), 9 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index c865cf35ad..6e1a024c19 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -861,9 +861,6 @@ static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, cons { struct opc_part *part;
- if (!name) - return E_POINTER; - if (!opc_array_reserve((void **)&set->parts, &set->size, set->count + 1, sizeof(*set->parts))) return E_OUTOFMEMORY;
@@ -898,6 +895,21 @@ static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, cons return S_OK; }
+static struct opc_part *opc_part_set_get_part(const struct opc_part_set *part_set, IOpcPartUri *name) +{ + BOOL is_equal; + size_t i; + + for (i = 0; i < part_set->count; ++i) + { + is_equal = FALSE; + if (IOpcPartUri_IsEqual(part_set->parts[i]->name, (IUri *)name, &is_equal) == S_OK && is_equal) + return part_set->parts[i]; + } + + return NULL; +} + static HRESULT WINAPI opc_part_set_QueryInterface(IOpcPartSet *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -944,11 +956,28 @@ static ULONG WINAPI opc_part_set_Release(IOpcPartSet *iface) return refcount; }
-static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name, IOpcPart **part) +static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name, IOpcPart **out) { - FIXME("iface %p, name %p, part %p stub!\n", iface, name, part); + struct opc_part_set *part_set = impl_from_IOpcPartSet(iface); + struct opc_part *part;
- return E_NOTIMPL; + TRACE("iface %p, name %p, out %p.\n", iface, name, out); + + if (!out) + return E_POINTER; + + *out = NULL; + + if (!name) + return E_POINTER; + + if ((part = opc_part_set_get_part(part_set, name))) + { + *out = &part->IOpcPart_iface; + IOpcPart_AddRef(*out); + } + + return *out ? S_OK : OPC_E_NO_SUCH_PART; }
static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *name, LPCWSTR content_type, @@ -959,6 +988,17 @@ static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *n TRACE("iface %p, name %p, content_type %s, compression_options %#x, part %p.\n", iface, name, debugstr_w(content_type), compression_options, part);
+ if (!part) + return E_POINTER; + + *part = NULL; + + if (!name) + return E_POINTER; + + if (opc_part_set_get_part(part_set, name)) + return OPC_E_DUPLICATE_PART; + return opc_part_create(part_set, name, content_type, compression_options, part); }
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index ab8c2e47a5..2bcf46fb9b 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -42,16 +42,17 @@ static void test_package(void) static const WCHAR uriW[] = {'/','u','r','i',0}; static const WCHAR rootW[] = {'/',0}; IOpcRelationshipSet *relset, *relset2; + IOpcPartUri *part_uri, *part_uri2; IOpcPartSet *partset, *partset2; + OPC_COMPRESSION_OPTIONS options; IStream *stream, *stream2; + IOpcPart *part, *part2; IOpcRelationship *rel; - IOpcPartUri *part_uri; IOpcFactory *factory; IOpcPackage *package; LARGE_INTEGER move; ULARGE_INTEGER pos; IUri *target_uri; - IOpcPart *part; char buff[16]; IOpcUri *uri; HRESULT hr; @@ -80,11 +81,55 @@ static void test_package(void) hr = IOpcFactory_CreatePartUri(factory, uriW, &part_uri); ok(SUCCEEDED(hr), "Failed to create part uri, hr %#x.\n", hr);
+ hr = IOpcFactory_CreatePartUri(factory, uriW, &part_uri2); + ok(SUCCEEDED(hr), "Failed to create part uri, hr %#x.\n", hr); + + part = (void *)0xdeadbeef; hr = IOpcPartSet_CreatePart(partset, NULL, typeW, OPC_COMPRESSION_NONE, &part); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + ok(part == NULL, "Unexpected pointer %p.\n", part); + + hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, OPC_COMPRESSION_NONE, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
- hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, OPC_COMPRESSION_NONE, &part); + hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, 0xdeadbeef, &part); ok(SUCCEEDED(hr), "Failed to create a part, hr %#x.\n", hr); + hr = IOpcPart_GetCompressionOptions(part, &options); + ok(SUCCEEDED(hr), "Failed to get compression options, hr %#x.\n", hr); + ok(options == 0xdeadbeef, "Unexpected compression options %#x.\n", options); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, OPC_COMPRESSION_NONE, &part2); + ok(hr == OPC_E_DUPLICATE_PART, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected instance %p.\n", part2); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartSet_CreatePart(partset, part_uri2, typeW, OPC_COMPRESSION_NONE, &part2); + ok(hr == OPC_E_DUPLICATE_PART, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected instance %p.\n", part2); + IOpcPartUri_Release(part_uri2); + + hr = IOpcPartSet_GetPart(partset, NULL, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + part2 = (void *)0xdeadbeef; + hr = IOpcPartSet_GetPart(partset, NULL, &part2); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + ok(part2 == NULL, "Unexpected pointer %p.\n", part2); + + hr = IOpcPartSet_GetPart(partset, part_uri, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartSet_GetPart(partset, part_uri, &part2); + ok(SUCCEEDED(hr), "Failed to get part, hr %#x.\n", hr); + IOpcPart_Release(part2); + + hr = IOpcFactory_CreatePartUri(factory, targetW, &part_uri2); + ok(SUCCEEDED(hr), "Failed to create part uri, hr %#x.\n", hr); + + hr = IOpcPartSet_GetPart(partset, part_uri2, &part2); + ok(hr == OPC_E_NO_SUCH_PART, "Unexpected hr %#x.\n", hr); + IOpcPartUri_Release(part_uri2);
hr = IOpcPart_GetContentStream(part, NULL); ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); diff --git a/include/opcbase.idl b/include/opcbase.idl index 8523271217..d850753563 100644 --- a/include/opcbase.idl +++ b/include/opcbase.idl @@ -43,7 +43,9 @@ typedef [v1_enum] enum
cpp_quote("#define OPC_E_NONCONFORMING_URI MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x1)") cpp_quote("#define OPC_E_RELATIONSHIP_URI_REQUIRED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x3)") +cpp_quote("#define OPC_E_DUPLICATE_PART MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0xb)") cpp_quote("#define OPC_E_INVALID_RELATIONSHIP_TARGET MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x12)") +cpp_quote("#define OPC_E_NO_SUCH_PART MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x18)") cpp_quote("#define OPC_E_NO_SUCH_RELATIONSHIP MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x48)") cpp_quote("#define OPC_E_ENUM_COLLECTION_CHANGED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x50)") cpp_quote("#define OPC_E_ENUM_INVALID_POSITION MAKE_HRESULT(SEVERITY_ERROR, FACILITY_OPC, 0x53)")
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 11 +++++++++-- dlls/opcservices/tests/opcservices.c | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 6e1a024c19..ae610ac82d 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -1011,9 +1011,16 @@ static HRESULT WINAPI opc_part_set_DeletePart(IOpcPartSet *iface, IOpcPartUri *n
static HRESULT WINAPI opc_part_set_PartExists(IOpcPartSet *iface, IOpcPartUri *name, BOOL *exists) { - FIXME("iface %p, name %p, exists %p stub!\n", iface, name, exists); + struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
- return E_NOTIMPL; + TRACE("iface %p, name %p, exists %p.\n", iface, name, exists); + + if (!name || !exists) + return E_POINTER; + + *exists = opc_part_set_get_part(part_set, name) != NULL; + + return S_OK; }
static HRESULT WINAPI opc_part_set_GetEnumerator(IOpcPartSet *iface, IOpcPartEnumerator **enumerator) diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 2bcf46fb9b..8bcd9140df 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -187,12 +187,19 @@ static void test_package(void) IOpcRelationshipSet_Release(relset); IOpcRelationshipSet_Release(relset2);
+ ret = 123; + hr = IOpcPartSet_PartExists(partset, NULL, &ret); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + ok(ret == 123, "Unexpected return value.\n"); + + hr = IOpcPartSet_PartExists(partset, part_uri, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + ret = FALSE; hr = IOpcPartSet_PartExists(partset, part_uri, &ret); -todo_wine { ok(SUCCEEDED(hr), "Unexpected hr %#x.\n", hr); ok(ret, "Expected part to exist.\n"); -} + IOpcPartUri_Release(part_uri); IOpcPart_Release(part);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/factory.c | 3 + dlls/opcservices/package.c | 244 ++++++++++++++++++++++++++- dlls/opcservices/tests/opcservices.c | 79 +++++++++ 3 files changed, 317 insertions(+), 9 deletions(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c index 9c04964498..ee155b3e71 100644 --- a/dlls/opcservices/factory.c +++ b/dlls/opcservices/factory.c @@ -387,6 +387,9 @@ static HRESULT WINAPI opc_factory_WritePackageToStream(IOpcFactory *iface, IOpcP { TRACE("iface %p, package %p, flags %#x, stream %p.\n", iface, package, flags, stream);
+ if (!package || !stream) + return E_POINTER; + return opc_package_write(package, flags, stream); }
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index ae610ac82d..074f3c8f99 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -25,6 +25,7 @@ #include "xmllite.h"
#include "wine/debug.h" +#include "wine/list.h" #include "wine/unicode.h"
#include "opc_private.h" @@ -1511,23 +1512,243 @@ HRESULT opc_package_create(IOpcFactory *factory, IOpcPackage **out) return S_OK; }
-static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlWriter *writer) +struct content_types +{ + struct list types; +}; + +enum content_type_element +{ + CONTENT_TYPE_DEFAULT, + CONTENT_TYPE_OVERRIDE, +}; + +struct content_type +{ + struct list entry; + enum content_type_element element; + union + { + struct default_type + { + WCHAR *ext; + WCHAR *type; + } def; + struct override_type + { + IOpcPart *part; + } override; + } u; +}; + +static HRESULT opc_package_add_override_content_type(struct content_types *types, IOpcPart *part) +{ + struct content_type *type; + + if (!(type = heap_alloc(sizeof(*type)))) + return E_OUTOFMEMORY; + + type->element = CONTENT_TYPE_OVERRIDE; + type->u.override.part = part; + IOpcPart_AddRef(part); + + list_add_tail(&types->types, &type->entry); + + return S_OK; +} + +static HRESULT opc_package_add_default_content_type(struct content_types *types, + const WCHAR *ext, const WCHAR *content_type) +{ + struct content_type *type; + + if (!(type = heap_alloc(sizeof(*type)))) + return E_OUTOFMEMORY; + + type->element = CONTENT_TYPE_DEFAULT; + type->u.def.ext = opc_strdupW(ext); + type->u.def.type = opc_strdupW(content_type); + if (!type->u.def.ext || !type->u.def.type) + { + CoTaskMemFree(type->u.def.ext); + CoTaskMemFree(type->u.def.type); + heap_free(type); + return E_OUTOFMEMORY; + } + + list_add_tail(&types->types, &type->entry); + + return S_OK; +} + +static HRESULT opc_package_add_content_type(struct content_types *types, IOpcPart *part) +{ + struct content_type *cur; + BSTR ext, content_type; + BOOL added = FALSE; + IOpcPartUri *name; + HRESULT hr; + + if (FAILED(hr = IOpcPart_GetName(part, &name))) + return hr; + + hr = IOpcPartUri_GetExtension(name, &ext); + IOpcPartUri_Release(name); + if (hr == S_FALSE) + { + hr = opc_package_add_override_content_type(types, part); + SysFreeString(ext); + return hr; + } + + if (FAILED(hr)) + return hr; + + if (FAILED(hr = IOpcPart_GetContentType(part, &content_type))) + return hr; + + LIST_FOR_EACH_ENTRY(cur, &types->types, struct content_type, entry) + { + if (cur->element == CONTENT_TYPE_OVERRIDE) + continue; + + if (!strcmpiW(cur->u.def.ext, ext)) + { + added = TRUE; + + if (!strcmpW(cur->u.def.type, content_type)) + break; + + hr = opc_package_add_override_content_type(types, part); + break; + } + } + + if (!added) + hr = opc_package_add_default_content_type(types, ext, content_type); + + SysFreeString(ext); + SysFreeString(content_type); + + return hr; +} + +static HRESULT opc_package_collect_content_types(IOpcPackage *package, struct content_types *types) +{ + IOpcPartEnumerator *enumerator; + IOpcPartSet *parts; + BOOL has_next; + HRESULT hr; + + if (FAILED(hr = IOpcPackage_GetPartSet(package, &parts))) + return hr; + + hr = IOpcPartSet_GetEnumerator(parts, &enumerator); + IOpcPartSet_Release(parts); + if (FAILED(hr)) + return hr; + + if (FAILED(hr = IOpcPartEnumerator_MoveNext(enumerator, &has_next)) || !has_next) + { + IOpcPartEnumerator_Release(enumerator); + return hr; + } + + while (has_next) + { + IOpcPart *part; + + if (FAILED(hr = IOpcPartEnumerator_GetCurrent(enumerator, &part))) + break; + + hr = opc_package_add_content_type(types, part); + IOpcPart_Release(part); + if (FAILED(hr)) + break; + + IOpcPartEnumerator_MoveNext(enumerator, &has_next); + } + + IOpcPartEnumerator_Release(enumerator); + + return hr; +} + +static HRESULT opc_package_write_contenttypes(IOpcPackage *package, struct zip_archive *archive, IXmlWriter *writer) { static const WCHAR uriW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','o','p','e','n','x','m','l','f','o','r','m','a','t','s','.','o','r','g','/', 'p','a','c','k','a','g','e','/','2','0','0','6','/','c','o','n','t','e','n','t','-','t','y','p','e','s',0}; static const WCHAR contenttypesW[] = {'[','C','o','n','t','e','n','t','_','T','y','p','e','s',']','.','x','m','l',0}; + static const WCHAR contenttypeW[] = {'C','o','n','t','e','n','t','T','y','p','e',0}; + static const WCHAR extensionW[] = {'E','x','t','e','n','s','i','o','n',0}; + static const WCHAR overrideW[] = {'O','v','e','r','r','i','d','e',0}; + static const WCHAR partnameW[] = {'P','a','r','t','N','a','m','e',0}; + static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0}; static const WCHAR typesW[] = {'T','y','p','e','s',0}; - IStream *content; + struct content_type *content_type, *content_type2; + struct content_types types; + IStream *content = NULL; HRESULT hr;
- if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content))) - return hr; + list_init(&types.types);
- hr = IXmlWriter_SetOutput(writer, (IUnknown *)content); + hr = CreateStreamOnHGlobal(NULL, TRUE, &content); + if (SUCCEEDED(hr)) + hr = opc_package_collect_content_types(package, &types); + if (SUCCEEDED(hr)) + hr = IXmlWriter_SetOutput(writer, (IUnknown *)content); if (SUCCEEDED(hr)) hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit); if (SUCCEEDED(hr)) hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW); + + LIST_FOR_EACH_ENTRY_SAFE(content_type, content_type2, &types.types, struct content_type, entry) + { + if (content_type->element == CONTENT_TYPE_DEFAULT) + { + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteStartElement(writer, NULL, defaultW, NULL); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteAttributeString(writer, NULL, extensionW, NULL, content_type->u.def.ext + 1); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, content_type->u.def.type); + + CoTaskMemFree(content_type->u.def.ext); + CoTaskMemFree(content_type->u.def.type); + } + else + { + IOpcPartUri *uri = NULL; + WCHAR *type = NULL; + BSTR name = NULL; + + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteStartElement(writer, NULL, overrideW, NULL); + if (SUCCEEDED(hr)) + hr = IOpcPart_GetName(content_type->u.override.part, &uri); + if (SUCCEEDED(hr)) + hr = IOpcPartUri_GetRawUri(uri, &name); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteAttributeString(writer, NULL, partnameW, NULL, name); + if (SUCCEEDED(hr)) + hr = IOpcPart_GetContentType(content_type->u.override.part, &type); + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, type); + + if (uri) + IOpcPartUri_Release(uri); + SysFreeString(name); + CoTaskMemFree(type); + + IOpcPart_Release(content_type->u.override.part); + } + if (SUCCEEDED(hr)) + hr = IXmlWriter_WriteEndElement(writer); + + list_remove(&content_type->entry); + heap_free(content_type); + } + if (SUCCEEDED(hr)) hr = IXmlWriter_WriteEndDocument(writer); if (SUCCEEDED(hr)) @@ -1535,7 +1756,9 @@ static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlW
if (SUCCEEDED(hr)) hr = compress_add_file(archive, contenttypesW, content, OPC_COMPRESSION_NORMAL); - IStream_Release(content); + + if (content) + IStream_Release(content);
return hr; } @@ -1736,7 +1959,7 @@ HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream * }
/* [Content_Types].xml */ - hr = opc_package_write_contenttypes(archive, writer); + hr = opc_package_write_contenttypes(package, archive, writer); /* Package relationships. */ if (SUCCEEDED(hr)) hr = IOpcPackage_GetRelationshipSet(package, &rels); @@ -1748,10 +1971,13 @@ HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream * if (SUCCEEDED(hr)) hr = opc_package_write_parts(archive, package, writer);
- IOpcRelationshipSet_Release(rels); + if (rels) + IOpcRelationshipSet_Release(rels); + if (uri) + IOpcUri_Release(uri); + compress_finalize_archive(archive); IXmlWriter_Release(writer); - IOpcUri_Release(uri);
return hr; } diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 8bcd9140df..764dca1cf3 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -1194,6 +1194,84 @@ static void test_create_part_uri(void) IOpcFactory_Release(factory); }
+static HRESULT WINAPI custom_package_QueryInterface(IOpcPackage *iface, REFIID iid, void **out) +{ + if (IsEqualIID(iid, &IID_IOpcPackage) || IsEqualIID(iid, &IID_IUnknown)) + { + *out = iface; + IOpcPackage_AddRef(iface); + return S_OK; + } + + *out = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI custom_package_AddRef(IOpcPackage *iface) +{ + return 2; +} + +static ULONG WINAPI custom_package_Release(IOpcPackage *iface) +{ + return 1; +} + +static HRESULT WINAPI custom_package_GetPartSet(IOpcPackage *iface, IOpcPartSet **part_set) +{ + return 0x80000001; +} + +static HRESULT WINAPI custom_package_GetRelationshipSet(IOpcPackage *iface, IOpcRelationshipSet **relationship_set) +{ + return 0x80000001; +} + +static const IOpcPackageVtbl custom_package_vtbl = +{ + custom_package_QueryInterface, + custom_package_AddRef, + custom_package_Release, + custom_package_GetPartSet, + custom_package_GetRelationshipSet, +}; + +static void test_write_package(void) +{ + IOpcPackage custom_package = { &custom_package_vtbl }; + IOpcFactory *factory; + IOpcPackage *package; + IStream *stream; + HRESULT hr; + + factory = create_factory(); + + hr = IOpcFactory_CreatePackage(factory, &package); + ok(SUCCEEDED(hr) || broken(hr == E_NOTIMPL) /* Vista */, "Failed to create a package, hr %#x.\n", hr); + if (FAILED(hr)) + { + IOpcFactory_Release(factory); + return; + } + + hr = IOpcFactory_WritePackageToStream(factory, NULL, OPC_WRITE_FORCE_ZIP32, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(SUCCEEDED(hr), "Failed to create a stream, hr %#x.\n", hr); + + hr = IOpcFactory_WritePackageToStream(factory, NULL, OPC_WRITE_FORCE_ZIP32, stream); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcFactory_WritePackageToStream(factory, &custom_package, OPC_WRITE_FORCE_ZIP32, stream); + ok(hr == 0x80000001, "Unexpected hr %#x.\n", hr); + + IStream_Release(stream); + + IOpcFactory_Release(factory); + IOpcPackage_Release(package); +} + START_TEST(opcservices) { IOpcFactory *factory; @@ -1217,6 +1295,7 @@ START_TEST(opcservices) test_relative_uri(); test_combine_uri(); test_create_part_uri(); + test_write_package();
IOpcFactory_Release(factory);