Wine-Devel
By thread
wine-devel@list.winehq.org
By month
Messages by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2018
- 70 participants
- 1549 messages
Re: [PATCH 2/2] msi/tests: Add a test for repetitive MsiGetActiveDatabase calls.
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
Sept. 19, 2018
Re: [PATCH 1/2] msi/tests: Also test full range of properties for MsiSummaryInfoSetPropertyW. (v2)
by Hans Leidekker
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
Sept. 19, 2018
[PATCH 10/10] opcservices: Write full content type stream.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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);
--
2.18.0
Sept. 19, 2018
[PATCH 09/10] opcservices: Implement PartExists().
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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);
--
2.18.0
Sept. 19, 2018
[PATCH 08/10] opcservices: Implement GetPart().
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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)")
--
2.18.0
Sept. 19, 2018
[PATCH 07/10] opcservices: Improve error handling (Coverity).
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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);
--
2.18.0
Sept. 19, 2018
[PATCH 06/10] opcservices: Write relationship parts.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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;
}
--
2.18.0
Sept. 19, 2018
[PATCH 05/10] opcservices: Write package parts.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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);
--
2.18.0
Sept. 19, 2018
[PATCH 04/10] opcservices: Implement CombinePartUri().
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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,
--
2.18.0
Sept. 19, 2018
[PATCH 03/10] opcservices: Fix path used for part URIs.
by Nikolay Sivov
Signed-off-by: Nikolay Sivov <nsivov(a)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);
--
2.18.0
Sept. 19, 2018