Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/Makefile.in | 2 +- dlls/opcservices/package.c | 61 ++++++++++++++++++++++++---- dlls/opcservices/tests/opcservices.c | 24 +++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-)
diff --git a/dlls/opcservices/Makefile.in b/dlls/opcservices/Makefile.in index 651cb411d7..47fbbe4cca 100644 --- a/dlls/opcservices/Makefile.in +++ b/dlls/opcservices/Makefile.in @@ -1,5 +1,5 @@ MODULE = opcservices.dll -IMPORTS = uuid +IMPORTS = uuid ole32
C_SRCS = \ factory.c \ diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index a3a2fabce7..e673f0c892 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -23,6 +23,7 @@ #include "winbase.h"
#include "wine/debug.h" +#include "wine/unicode.h"
#include "opc_private.h"
@@ -40,6 +41,10 @@ struct opc_part { IOpcPart IOpcPart_iface; LONG refcount; + + IOpcPartUri *name; + WCHAR *content_type; + DWORD compression_options; };
struct opc_part_set @@ -63,6 +68,24 @@ static inline struct opc_part *impl_from_IOpcPart(IOpcPart *iface) return CONTAINING_RECORD(iface, struct opc_part, IOpcPart_iface); }
+static WCHAR *opc_strdupW(const WCHAR *str) +{ + WCHAR *ret = NULL; + + if (str) + { + size_t size; + + size = (strlenW(str) + 1) * sizeof(WCHAR); + ret = CoTaskMemAlloc(size); + if (ret) + memcpy(ret, str, size); + } + + return ret; +} + + static HRESULT WINAPI opc_part_QueryInterface(IOpcPart *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -97,7 +120,11 @@ static ULONG WINAPI opc_part_Release(IOpcPart *iface) TRACE("%p decreasing refcount to %u.\n", iface, refcount);
if (!refcount) + { + IOpcPartUri_Release(part->name); + CoTaskMemFree(part->content_type); heap_free(part); + }
return refcount; } @@ -118,16 +145,24 @@ static HRESULT WINAPI opc_part_GetContentStream(IOpcPart *iface, IStream **strea
static HRESULT WINAPI opc_part_GetName(IOpcPart *iface, IOpcPartUri **name) { - FIXME("iface %p, name %p stub!\n", iface, name); + struct opc_part *part = impl_from_IOpcPart(iface);
- return E_NOTIMPL; + TRACE("iface %p, name %p.\n", iface, name); + + *name = part->name; + IOpcPartUri_AddRef(*name); + + return S_OK; }
static HRESULT WINAPI opc_part_GetContentType(IOpcPart *iface, LPWSTR *type) { - FIXME("iface %p, type %p stub!\n", iface, type); + struct opc_part *part = impl_from_IOpcPart(iface);
- return E_NOTIMPL; + TRACE("iface %p, type %p.\n", iface, type); + + *type = opc_strdupW(part->content_type); + return *type ? S_OK : E_OUTOFMEMORY; }
static HRESULT WINAPI opc_part_GetCompressionOptions(IOpcPart *iface, OPC_COMPRESSION_OPTIONS *options) @@ -149,15 +184,27 @@ static const IOpcPartVtbl opc_part_vtbl = opc_part_GetCompressionOptions, };
-static HRESULT opc_part_create(IOpcPart **out) +static HRESULT opc_part_create(IOpcPartUri *name, const WCHAR *content_type, + DWORD compression_options, IOpcPart **out) { struct opc_part *part;
+ if (!name) + return E_POINTER; + if (!(part = heap_alloc_zero(sizeof(*part)))) return E_OUTOFMEMORY;
part->IOpcPart_iface.lpVtbl = &opc_part_vtbl; part->refcount = 1; + part->name = name; + IOpcPartUri_AddRef(name); + part->compression_options = compression_options; + if (!(part->content_type = opc_strdupW(content_type))) + { + IOpcPart_Release(&part->IOpcPart_iface); + return E_OUTOFMEMORY; + }
*out = &part->IOpcPart_iface; TRACE("Created part %p.\n", *out); @@ -213,10 +260,10 @@ static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *name, LPCWSTR content_type, OPC_COMPRESSION_OPTIONS compression_options, IOpcPart **part) { - FIXME("iface %p, name %p, content_type %s, compression_options %#x, part %p stub!\n", iface, name, + TRACE("iface %p, name %p, content_type %s, compression_options %#x, part %p.\n", iface, name, debugstr_w(content_type), compression_options, part);
- return opc_part_create(part); + return opc_part_create(name, content_type, compression_options, part); }
static HRESULT WINAPI opc_part_set_DeletePart(IOpcPartSet *iface, IOpcPartUri *name) diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index e257c6ea2c..9ef44e6cc3 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -36,10 +36,15 @@ static IOpcFactory *create_factory(void)
static void test_package(void) { + static const WCHAR typeW[] = {'t','y','p','e','/','s','u','b','t','y','p','e',0}; + static const WCHAR uriW[] = {'/','u','r','i',0}; IOpcPartSet *partset, *partset2; + IOpcPartUri *part_uri; IOpcFactory *factory; IOpcPackage *package; + IOpcPart *part; HRESULT hr; + BOOL ret;
factory = create_factory();
@@ -58,6 +63,25 @@ static void test_package(void) ok(SUCCEEDED(hr), "Failed to create a part set, hr %#x.\n", hr); ok(partset == partset2, "Expected same part set instance.\n");
+ /* CreatePart */ + hr = IOpcFactory_CreatePartUri(factory, uriW, &part_uri); + ok(SUCCEEDED(hr), "Failed to create part uri, hr %#x.\n", hr); + + hr = IOpcPartSet_CreatePart(partset, NULL, typeW, OPC_COMPRESSION_NONE, &part); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, OPC_COMPRESSION_NONE, &part); + ok(SUCCEEDED(hr), "Failed to create a part, 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); + IOpcPackage_Release(package);
IOpcFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 150 ++++++++++++++++++++++++++- dlls/opcservices/tests/opcservices.c | 11 ++ 2 files changed, 158 insertions(+), 3 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index e673f0c892..09014ffc82 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -35,6 +35,7 @@ struct opc_package LONG refcount;
IOpcPartSet *part_set; + IOpcRelationshipSet *relationship_set; };
struct opc_part @@ -53,6 +54,12 @@ struct opc_part_set LONG refcount; };
+struct opc_relationship_set +{ + IOpcRelationshipSet IOpcRelationshipSet_iface; + LONG refcount; +}; + static inline struct opc_package *impl_from_IOpcPackage(IOpcPackage *iface) { return CONTAINING_RECORD(iface, struct opc_package, IOpcPackage_iface); @@ -68,6 +75,11 @@ static inline struct opc_part *impl_from_IOpcPart(IOpcPart *iface) return CONTAINING_RECORD(iface, struct opc_part, IOpcPart_iface); }
+static inline struct opc_relationship_set *impl_from_IOpcRelationshipSet(IOpcRelationshipSet *iface) +{ + return CONTAINING_RECORD(iface, struct opc_relationship_set, IOpcRelationshipSet_iface); +} + static WCHAR *opc_strdupW(const WCHAR *str) { WCHAR *ret = NULL; @@ -85,7 +97,6 @@ static WCHAR *opc_strdupW(const WCHAR *str) return ret; }
- static HRESULT WINAPI opc_part_QueryInterface(IOpcPart *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -299,6 +310,128 @@ static const IOpcPartSetVtbl opc_part_set_vtbl = opc_part_set_GtEnumerator, };
+static HRESULT WINAPI opc_relationship_set_QueryInterface(IOpcRelationshipSet *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(iid, &IID_IOpcRelationshipSet) || + IsEqualIID(iid, &IID_IUnknown)) + { + *out = iface; + IOpcRelationshipSet_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI opc_relationship_set_AddRef(IOpcRelationshipSet *iface) +{ + struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface); + ULONG refcount = InterlockedIncrement(&relationship_set->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI opc_relationship_set_Release(IOpcRelationshipSet *iface) +{ + struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface); + ULONG refcount = InterlockedDecrement(&relationship_set->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + heap_free(relationship_set); + + return refcount; +} + +static HRESULT WINAPI opc_relationship_set_GetRelationship(IOpcRelationshipSet *iface, const WCHAR *id, + IOpcRelationship **relationship) +{ + FIXME("iface %p, id %s, relationship %p stub!\n", iface, debugstr_w(id), relationship); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_CreateRelationship(IOpcRelationshipSet *iface, const WCHAR *id, + const WCHAR *type, IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **relationship) +{ + FIXME("iface %p, id %s, type %s, target_uri %p, target_mode %d, relationship %p stub!\n", iface, debugstr_w(id), + debugstr_w(type), target_uri, target_mode, relationship); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_DeleteRelationship(IOpcRelationshipSet *iface, const WCHAR *id) +{ + FIXME("iface %p, id %s stub!\n", iface, debugstr_w(id)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_RelationshipExists(IOpcRelationshipSet *iface, const WCHAR *id, BOOL *exists) +{ + FIXME("iface %p, id %s, exists %p stub!\n", iface, debugstr_w(id), exists); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_GetEnumerator(IOpcRelationshipSet *iface, + IOpcRelationshipEnumerator **enumerator) +{ + FIXME("iface %p, enumerator %p stub!\n", iface, enumerator); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_GetEnumeratorForType(IOpcRelationshipSet *iface, const WCHAR *type, + IOpcRelationshipEnumerator **enumerator) +{ + FIXME("iface %p, type %s, enumerator %p stub!\n", iface, debugstr_w(type), enumerator); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_set_GetRelationshipsContentStream(IOpcRelationshipSet *iface, IStream **stream) +{ + FIXME("iface %p, stream %p stub!\n", iface, stream); + + return E_NOTIMPL; +} + +static const IOpcRelationshipSetVtbl opc_relationship_set_vtbl = +{ + opc_relationship_set_QueryInterface, + opc_relationship_set_AddRef, + opc_relationship_set_Release, + opc_relationship_set_GetRelationship, + opc_relationship_set_CreateRelationship, + opc_relationship_set_DeleteRelationship, + opc_relationship_set_RelationshipExists, + opc_relationship_set_GetEnumerator, + opc_relationship_set_GetEnumeratorForType, + opc_relationship_set_GetRelationshipsContentStream, +}; + +static HRESULT opc_relationship_set_create(IOpcRelationshipSet **out) +{ + struct opc_relationship_set *relationship_set; + + if (!(relationship_set = heap_alloc_zero(sizeof(*relationship_set)))) + return E_OUTOFMEMORY; + + relationship_set->IOpcRelationshipSet_iface.lpVtbl = &opc_relationship_set_vtbl; + relationship_set->refcount = 1; + + *out = &relationship_set->IOpcRelationshipSet_iface; + TRACE("Created relationship set %p.\n", *out); + return S_OK; +} + static HRESULT WINAPI opc_package_QueryInterface(IOpcPackage *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -336,6 +469,8 @@ static ULONG WINAPI opc_package_Release(IOpcPackage *iface) { if (package->part_set) IOpcPartSet_Release(package->part_set); + if (package->relationship_set) + IOpcRelationshipSet_Release(package->relationship_set); heap_free(package); }
@@ -368,9 +503,18 @@ static HRESULT WINAPI opc_package_GetPartSet(IOpcPackage *iface, IOpcPartSet **p
static HRESULT WINAPI opc_package_GetRelationshipSet(IOpcPackage *iface, IOpcRelationshipSet **relationship_set) { - FIXME("iface %p, relationship_set %p stub!\n", iface, relationship_set); + struct opc_package *package = impl_from_IOpcPackage(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, relationship_set %p.\n", iface, relationship_set); + + if (!package->relationship_set && FAILED(hr = opc_relationship_set_create(&package->relationship_set))) + return hr; + + *relationship_set = package->relationship_set; + IOpcRelationshipSet_AddRef(*relationship_set); + + return S_OK; }
static const IOpcPackageVtbl opc_package_vtbl = diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 9ef44e6cc3..118ef8f0a4 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -38,6 +38,7 @@ static void test_package(void) { static const WCHAR typeW[] = {'t','y','p','e','/','s','u','b','t','y','p','e',0}; static const WCHAR uriW[] = {'/','u','r','i',0}; + IOpcRelationshipSet *relset, *relset2; IOpcPartSet *partset, *partset2; IOpcPartUri *part_uri; IOpcFactory *factory; @@ -82,6 +83,16 @@ todo_wine { IOpcPartUri_Release(part_uri); IOpcPart_Release(part);
+ /* Relationships */ + hr = IOpcPackage_GetRelationshipSet(package, &relset); + ok(SUCCEEDED(hr), "Failed to get relationship set, hr %#x.\n", hr); + + hr = IOpcPackage_GetRelationshipSet(package, &relset2); + ok(SUCCEEDED(hr), "Failed to get relationship set, hr %#x.\n", hr); + ok(relset == relset2, "Expected same part set instance.\n"); + IOpcRelationshipSet_Release(relset); + IOpcRelationshipSet_Release(relset2); + IOpcPackage_Release(package);
IOpcFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 114 ++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index 09014ffc82..a9b4d14fc3 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -54,6 +54,12 @@ struct opc_part_set LONG refcount; };
+struct opc_relationship +{ + IOpcRelationship IOpcRelationship_iface; + LONG refcount; +}; + struct opc_relationship_set { IOpcRelationshipSet IOpcRelationshipSet_iface; @@ -80,6 +86,11 @@ static inline struct opc_relationship_set *impl_from_IOpcRelationshipSet(IOpcRel return CONTAINING_RECORD(iface, struct opc_relationship_set, IOpcRelationshipSet_iface); }
+static inline struct opc_relationship *impl_from_IOpcRelationship(IOpcRelationship *iface) +{ + return CONTAINING_RECORD(iface, struct opc_relationship, IOpcRelationship_iface); +} + static WCHAR *opc_strdupW(const WCHAR *str) { WCHAR *ret = NULL; @@ -310,6 +321,107 @@ static const IOpcPartSetVtbl opc_part_set_vtbl = opc_part_set_GtEnumerator, };
+static HRESULT WINAPI opc_relationship_QueryInterface(IOpcRelationship *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(iid, &IID_IOpcRelationship) || + IsEqualIID(iid, &IID_IUnknown)) + { + *out = iface; + IOpcRelationship_AddRef(iface); + return S_OK; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI opc_relationship_AddRef(IOpcRelationship *iface) +{ + struct opc_relationship *relationship = impl_from_IOpcRelationship(iface); + ULONG refcount = InterlockedIncrement(&relationship->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI opc_relationship_Release(IOpcRelationship *iface) +{ + struct opc_relationship *relationship = impl_from_IOpcRelationship(iface); + ULONG refcount = InterlockedDecrement(&relationship->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + heap_free(relationship); + + return refcount; +} + +static HRESULT WINAPI opc_relationship_GetId(IOpcRelationship *iface, WCHAR **id) +{ + FIXME("iface %p, id %p stub!\n", iface, id); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_GetRelationshipType(IOpcRelationship *iface, WCHAR **type) +{ + FIXME("iface %p, type %p stub!\n", iface, type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_GetSourceUri(IOpcRelationship *iface, IOpcUri **uri) +{ + FIXME("iface %p, uri %p stub!\n", iface, uri); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_GetTargetUri(IOpcRelationship *iface, IUri **target) +{ + FIXME("iface %p, target %p stub!\n", iface, target); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_relationship_GetTargetMode(IOpcRelationship *iface, OPC_URI_TARGET_MODE *target_mode) +{ + FIXME("iface %p, target_mode %p stub!\n", iface, target_mode); + + return E_NOTIMPL; +} + +static const IOpcRelationshipVtbl opc_relationship_vtbl = +{ + opc_relationship_QueryInterface, + opc_relationship_AddRef, + opc_relationship_Release, + opc_relationship_GetId, + opc_relationship_GetRelationshipType, + opc_relationship_GetSourceUri, + opc_relationship_GetTargetUri, + opc_relationship_GetTargetMode, +}; + +static HRESULT opc_relationship_create(IOpcRelationship **out) +{ + struct opc_relationship *relationship; + + if (!(relationship = heap_alloc_zero(sizeof(*relationship)))) + return E_OUTOFMEMORY; + + relationship->IOpcRelationship_iface.lpVtbl = &opc_relationship_vtbl; + relationship->refcount = 1; + + *out = &relationship->IOpcRelationship_iface; + TRACE("Created relationship %p.\n", *out); + return S_OK; +} + static HRESULT WINAPI opc_relationship_set_QueryInterface(IOpcRelationshipSet *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -363,7 +475,7 @@ static HRESULT WINAPI opc_relationship_set_CreateRelationship(IOpcRelationshipSe FIXME("iface %p, id %s, type %s, target_uri %p, target_mode %d, relationship %p stub!\n", iface, debugstr_w(id), debugstr_w(type), target_uri, target_mode, relationship);
- return E_NOTIMPL; + return opc_relationship_create(relationship); }
static HRESULT WINAPI opc_relationship_set_DeleteRelationship(IOpcRelationshipSet *iface, const WCHAR *id)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/package.c | 18 ++++++++++++++++-- dlls/opcservices/tests/opcservices.c | 9 +++++++++ 2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c index a9b4d14fc3..cd4741d220 100644 --- a/dlls/opcservices/package.c +++ b/dlls/opcservices/package.c @@ -46,6 +46,7 @@ struct opc_part IOpcPartUri *name; WCHAR *content_type; DWORD compression_options; + IOpcRelationshipSet *relationship_set; };
struct opc_part_set @@ -91,6 +92,8 @@ static inline struct opc_relationship *impl_from_IOpcRelationship(IOpcRelationsh return CONTAINING_RECORD(iface, struct opc_relationship, IOpcRelationship_iface); }
+static HRESULT opc_relationship_set_create(IOpcRelationshipSet **relationship_set); + static WCHAR *opc_strdupW(const WCHAR *str) { WCHAR *ret = NULL; @@ -143,6 +146,8 @@ static ULONG WINAPI opc_part_Release(IOpcPart *iface)
if (!refcount) { + if (part->relationship_set) + IOpcRelationshipSet_Release(part->relationship_set); IOpcPartUri_Release(part->name); CoTaskMemFree(part->content_type); heap_free(part); @@ -153,9 +158,18 @@ static ULONG WINAPI opc_part_Release(IOpcPart *iface)
static HRESULT WINAPI opc_part_GetRelationshipSet(IOpcPart *iface, IOpcRelationshipSet **relationship_set) { - FIXME("iface %p, relationship_set %p stub!\n", iface, relationship_set); + struct opc_part *part = impl_from_IOpcPart(iface); + HRESULT hr;
- return E_NOTIMPL; + TRACE("iface %p, relationship_set %p.\n", iface, relationship_set); + + if (!part->relationship_set && FAILED(hr = opc_relationship_set_create(&part->relationship_set))) + return hr; + + *relationship_set = part->relationship_set; + IOpcRelationshipSet_AddRef(*relationship_set); + + return S_OK; }
static HRESULT WINAPI opc_part_GetContentStream(IOpcPart *iface, IStream **stream) diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 118ef8f0a4..8ab7f39e08 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -74,6 +74,15 @@ static void test_package(void) hr = IOpcPartSet_CreatePart(partset, part_uri, typeW, OPC_COMPRESSION_NONE, &part); ok(SUCCEEDED(hr), "Failed to create a part, hr %#x.\n", hr);
+ hr = IOpcPart_GetRelationshipSet(part, &relset); + ok(SUCCEEDED(hr), "Failed to get relationship set, hr %#x.\n", hr); + + hr = IOpcPart_GetRelationshipSet(part, &relset2); + ok(SUCCEEDED(hr), "Failed to get relationship set, hr %#x.\n", hr); + ok(relset == relset2, "Expected same part set instance.\n"); + IOpcRelationshipSet_Release(relset); + IOpcRelationshipSet_Release(relset2); + ret = FALSE; hr = IOpcPartSet_PartExists(partset, part_uri, &ret); todo_wine {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/factory.c | 252 ++++++++++++++++++++++++++- dlls/opcservices/tests/opcservices.c | 98 +++++++++++ 2 files changed, 348 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c index 7cbe233e9d..ca46d0a202 100644 --- a/dlls/opcservices/factory.c +++ b/dlls/opcservices/factory.c @@ -33,6 +33,254 @@
WINE_DEFAULT_DEBUG_CHANNEL(msopc);
+struct opc_filestream +{ + IStream IStream_iface; + LONG refcount; + + HANDLE hfile; +}; + +static inline struct opc_filestream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct opc_filestream, IStream_iface); +} + +static HRESULT WINAPI opc_filestream_QueryInterface(IStream *iface, REFIID iid, void **out) +{ + TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); + + if (IsEqualIID(iid, &IID_IStream) || + IsEqualIID(iid, &IID_ISequentialStream) || + IsEqualIID(iid, &IID_IUnknown)) + { + *out = iface; + IStream_AddRef(iface); + return S_OK; + } + + *out = NULL; + WARN("Unsupported interface %s.\n", debugstr_guid(iid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI opc_filestream_AddRef(IStream *iface) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedIncrement(&stream->refcount); + + TRACE("%p increasing refcount to %u.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI opc_filestream_Release(IStream *iface) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + ULONG refcount = InterlockedDecrement(&stream->refcount); + + TRACE("%p decreasing refcount to %u.\n", iface, refcount); + + if (!refcount) + { + CloseHandle(stream->hfile); + heap_free(stream); + } + + return refcount; +} + +static HRESULT WINAPI opc_filestream_Read(IStream *iface, void *buff, ULONG size, ULONG *num_read) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + DWORD read = 0; + + TRACE("iface %p, buff %p, size %u, num_read %p.\n", iface, buff, size, num_read); + + if (!num_read) + num_read = &read; + + *num_read = 0; + if (!ReadFile(stream->hfile, buff, size, num_read, NULL)) + { + WARN("Failed to read file, error %d.\n", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + + return *num_read == size ? S_OK : S_FALSE; +} + +static HRESULT WINAPI opc_filestream_Write(IStream *iface, const void *data, ULONG size, ULONG *num_written) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + DWORD written = 0; + + TRACE("iface %p, data %p, size %u, num_written %p.\n", iface, data, size, num_written); + + if (!num_written) + num_written = &written; + + *num_written = 0; + if (!WriteFile(stream->hfile, data, size, num_written, NULL)) + { + WARN("Failed to write to file, error %d.\n", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + + return S_OK; +} + +static HRESULT WINAPI opc_filestream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + + TRACE("iface %p, move %s, origin %d, newpos %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, newpos); + + if (!SetFilePointerEx(stream->hfile, move, (LARGE_INTEGER *)newpos, origin)) + return HRESULT_FROM_WIN32(GetLastError()); + + return S_OK; +} + +static HRESULT WINAPI opc_filestream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + FIXME("iface %p, size %s stub!\n", iface, wine_dbgstr_longlong(size.QuadPart)); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size, + ULARGE_INTEGER *num_read, ULARGE_INTEGER *written) +{ + FIXME("iface %p, dest %p, size %s, num_read %p, written %p stub!\n", iface, dest, + wine_dbgstr_longlong(size.QuadPart), num_read, written); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_Commit(IStream *iface, DWORD flags) +{ + FIXME("iface %p, flags %#x stub!\n", iface, flags); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_Revert(IStream *iface) +{ + FIXME("iface %p stub!\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_LockRegion(IStream *iface, ULARGE_INTEGER offset, + ULARGE_INTEGER size, DWORD lock_type) +{ + FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(size.QuadPart), lock_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size, + DWORD lock_type) +{ + FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart), + wine_dbgstr_longlong(size.QuadPart), lock_type); + + return E_NOTIMPL; +} + +static HRESULT WINAPI opc_filestream_Stat(IStream *iface, STATSTG *statstg, DWORD flag) +{ + struct opc_filestream *stream = impl_from_IStream(iface); + BY_HANDLE_FILE_INFORMATION fi; + + TRACE("iface %p, statstg %p, flag %d.\n", iface, statstg, flag); + + if (!statstg) + return E_POINTER; + + memset(&fi, 0, sizeof(fi)); + GetFileInformationByHandle(stream->hfile, &fi); + + memset(statstg, 0, sizeof(*statstg)); + statstg->type = STGTY_STREAM; + statstg->cbSize.u.LowPart = fi.nFileSizeLow; + statstg->cbSize.u.HighPart = fi.nFileSizeHigh; + statstg->mtime = fi.ftLastWriteTime; + statstg->ctime = fi.ftCreationTime; + statstg->atime = fi.ftLastAccessTime; + + return S_OK; +} + +static HRESULT WINAPI opc_filestream_Clone(IStream *iface, IStream **result) +{ + FIXME("iface %p, result %p stub!\n", iface, result); + + return E_NOTIMPL; +} + +static const IStreamVtbl opc_filestream_vtbl = +{ + opc_filestream_QueryInterface, + opc_filestream_AddRef, + opc_filestream_Release, + opc_filestream_Read, + opc_filestream_Write, + opc_filestream_Seek, + opc_filestream_SetSize, + opc_filestream_CopyTo, + opc_filestream_Commit, + opc_filestream_Revert, + opc_filestream_LockRegion, + opc_filestream_UnlockRegion, + opc_filestream_Stat, + opc_filestream_Clone, +}; + +static HRESULT opc_filestream_create(const WCHAR *filename, OPC_STREAM_IO_MODE io_mode, SECURITY_ATTRIBUTES *sa, + DWORD flags, IStream **out) +{ + struct opc_filestream *stream; + DWORD access, creation; + + if (!filename || !out) + return E_POINTER; + + switch (io_mode) + { + case OPC_STREAM_IO_READ: + access = GENERIC_READ; + creation = OPEN_EXISTING; + break; + case OPC_STREAM_IO_WRITE: + access = GENERIC_WRITE; + creation = CREATE_ALWAYS; + break; + default: + return E_INVALIDARG; + } + + if (!(stream = heap_alloc_zero(sizeof(*stream)))) + return E_OUTOFMEMORY; + + stream->hfile = CreateFileW(filename, access, 0, sa, creation, flags, NULL); + if (stream->hfile == INVALID_HANDLE_VALUE) + { + HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); + heap_free(stream); + return hr; + } + + stream->IStream_iface.lpVtbl = &opc_filestream_vtbl; + stream->refcount = 1; + + *out = &stream->IStream_iface; + TRACE("Created file steam %p.\n", *out); + return S_OK; +} + static HRESULT WINAPI opc_factory_QueryInterface(IOpcFactory *iface, REFIID iid, void **out) { TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out); @@ -76,10 +324,10 @@ static HRESULT WINAPI opc_factory_CreatePartUri(IOpcFactory *iface, LPCWSTR uri, static HRESULT WINAPI opc_factory_CreateStreamOnFile(IOpcFactory *iface, LPCWSTR filename, OPC_STREAM_IO_MODE io_mode, SECURITY_ATTRIBUTES *sa, DWORD flags, IStream **stream) { - FIXME("iface %p, filename %s, io_mode %d, sa %p, flags %#x, stream %p stub!\n", iface, debugstr_w(filename), + TRACE("iface %p, filename %s, io_mode %d, sa %p, flags %#x, stream %p.\n", iface, debugstr_w(filename), io_mode, sa, flags, stream);
- return E_NOTIMPL; + return opc_filestream_create(filename, io_mode, sa, flags, stream); }
static HRESULT WINAPI opc_factory_CreatePackage(IOpcFactory *iface, IOpcPackage **package) diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c index 8ab7f39e08..5dc0d8c772 100644 --- a/dlls/opcservices/tests/opcservices.c +++ b/dlls/opcservices/tests/opcservices.c @@ -107,6 +107,103 @@ todo_wine { IOpcFactory_Release(factory); }
+#define test_stream_stat(stream, size) test_stream_stat_(__LINE__, stream, size) +static void test_stream_stat_(unsigned int line, IStream *stream, ULONG size) +{ + STATSTG statstg; + HRESULT hr; + + hr = IStream_Stat(stream, NULL, 0); + ok_(__FILE__, line)(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + memset(&statstg, 0xff, sizeof(statstg)); + hr = IStream_Stat(stream, &statstg, 0); + ok_(__FILE__, line)(SUCCEEDED(hr), "Failed to get stat info, hr %#x.\n", hr); + + ok_(__FILE__, line)(statstg.pwcsName == NULL, "Unexpected name %s.\n", wine_dbgstr_w(statstg.pwcsName)); + ok_(__FILE__, line)(statstg.type == STGTY_STREAM, "Unexpected type.\n"); + ok_(__FILE__, line)(statstg.cbSize.QuadPart == size, "Unexpected size %u, expected %u.\n", + statstg.cbSize.LowPart, size); + ok_(__FILE__, line)(statstg.grfMode == STGM_READ, "Unexpected mode.\n"); + ok_(__FILE__, line)(statstg.grfLocksSupported == 0, "Unexpected lock mode.\n"); + ok_(__FILE__, line)(statstg.grfStateBits == 0, "Unexpected state bits.\n"); +} + +static void test_file_stream(void) +{ + static const WCHAR filereadW[] = {'o','p','c','f','i','l','e','r','e','a','d','.','e','x','t',0}; + WCHAR temppathW[MAX_PATH], pathW[MAX_PATH]; + IOpcFactory *factory; + LARGE_INTEGER move; + IStream *stream; + char buff[64]; + HRESULT hr; + ULONG size; + + factory = create_factory(); + + hr = IOpcFactory_CreateStreamOnFile(factory, NULL, OPC_STREAM_IO_READ, NULL, 0, &stream); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + GetTempPathW(ARRAY_SIZE(temppathW), temppathW); + lstrcpyW(pathW, temppathW); + lstrcatW(pathW, filereadW); + DeleteFileW(pathW); + + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, OPC_STREAM_IO_READ, NULL, 0, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + /* File does not exist */ + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, OPC_STREAM_IO_READ, NULL, 0, &stream); + ok(FAILED(hr), "Unexpected hr %#x.\n", hr); + + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, OPC_STREAM_IO_WRITE, NULL, 0, &stream); + ok(SUCCEEDED(hr), "Failed to create a write stream, hr %#x.\n", hr); + + test_stream_stat(stream, 0); + + size = lstrlenW(pathW) * sizeof(WCHAR); + hr = IStream_Write(stream, pathW, size, NULL); + ok(hr == S_OK, "Stream write failed, hr %#x.\n", hr); + + test_stream_stat(stream, size); + IStream_Release(stream); + + /* Invalid I/O mode */ + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, 10, NULL, 0, &stream); + ok(hr == E_INVALIDARG, "Failed to create a write stream, hr %#x.\n", hr); + + /* Write to read-only stream. */ + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, OPC_STREAM_IO_READ, NULL, 0, &stream); + ok(SUCCEEDED(hr), "Failed to create a read stream, hr %#x.\n", hr); + + test_stream_stat(stream, size); + hr = IStream_Write(stream, pathW, size, NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), "Stream write failed, hr %#x.\n", hr); + IStream_Release(stream); + + /* Read from write-only stream. */ + hr = IOpcFactory_CreateStreamOnFile(factory, pathW, OPC_STREAM_IO_WRITE, NULL, 0, &stream); + ok(SUCCEEDED(hr), "Failed to create a read stream, hr %#x.\n", hr); + + test_stream_stat(stream, 0); + hr = IStream_Write(stream, pathW, size, NULL); + ok(hr == S_OK, "Stream write failed, hr %#x.\n", hr); + test_stream_stat(stream, size); + + move.QuadPart = 0; + hr = IStream_Seek(stream, move, STREAM_SEEK_SET, NULL); + ok(SUCCEEDED(hr), "Seek failed, hr %#x.\n", hr); + + hr = IStream_Read(stream, buff, sizeof(buff), NULL); + ok(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED), "Stream read failed, hr %#x.\n", hr); + + IStream_Release(stream); + + IOpcFactory_Release(factory); + DeleteFileW(pathW); +} + START_TEST(opcservices) { IOpcFactory *factory; @@ -122,6 +219,7 @@ START_TEST(opcservices) }
test_package(); + test_file_stream();
IOpcFactory_Release(factory);
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/opcservices/factory.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c index ca46d0a202..7d72b39b7b 100644 --- a/dlls/opcservices/factory.c +++ b/dlls/opcservices/factory.c @@ -465,7 +465,6 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD reason, void *reserved)
HRESULT WINAPI DllRegisterServer(void) { - FIXME("\n"); return __wine_register_resources( OPC_hInstance ); }