[PATCH 6/6] opcservices: Implement IOpcRelationshipEnumerator.
Nikolay Sivov
nsivov at codeweavers.com
Thu Sep 13 01:21:20 CDT 2018
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/opcservices/package.c | 187 ++++++++++++++++++++++++++-
dlls/opcservices/tests/opcservices.c | 163 +++++++++++++++++++++++
2 files changed, 348 insertions(+), 2 deletions(-)
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c
index 5ae5d3cf21..eb9c1c9f5a 100644
--- a/dlls/opcservices/package.c
+++ b/dlls/opcservices/package.c
@@ -90,6 +90,16 @@ struct opc_part_set
GUID id;
};
+struct opc_rel_enum
+{
+ IOpcRelationshipEnumerator IOpcRelationshipEnumerator_iface;
+ LONG refcount;
+
+ struct opc_relationship_set *rel_set;
+ size_t pos;
+ GUID id;
+};
+
struct opc_relationship
{
IOpcRelationship IOpcRelationship_iface;
@@ -111,6 +121,7 @@ struct opc_relationship_set
size_t size;
size_t count;
IOpcUri *source_uri;
+ GUID id;
};
static inline struct opc_package *impl_from_IOpcPackage(IOpcPackage *iface)
@@ -148,6 +159,11 @@ static inline struct opc_part_enum *impl_from_IOpcPartEnumerator(IOpcPartEnumera
return CONTAINING_RECORD(iface, struct opc_part_enum, IOpcPartEnumerator_iface);
}
+static inline struct opc_rel_enum *impl_from_IOpcRelationshipEnumerator(IOpcRelationshipEnumerator *iface)
+{
+ return CONTAINING_RECORD(iface, struct opc_rel_enum, IOpcRelationshipEnumerator_iface);
+}
+
static void opc_content_release(struct opc_content *content)
{
ULONG refcount = InterlockedDecrement(&content->refcount);
@@ -320,6 +336,167 @@ static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnume
return S_OK;
}
+static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out);
+
+static HRESULT WINAPI opc_rel_enum_QueryInterface(IOpcRelationshipEnumerator *iface, REFIID iid, void **out)
+{
+ TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+ if (IsEqualIID(&IID_IOpcRelationshipEnumerator, iid) ||
+ IsEqualIID(&IID_IUnknown, iid))
+ {
+ *out = iface;
+ IOpcRelationshipEnumerator_AddRef(iface);
+ return S_OK;
+ }
+
+ *out = NULL;
+ WARN("Unsupported interface %s.\n", debugstr_guid(iid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI opc_rel_enum_AddRef(IOpcRelationshipEnumerator *iface)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+ ULONG refcount = InterlockedIncrement(&rel_enum->refcount);
+
+ TRACE("%p increasing refcount to %u.\n", iface, refcount);
+
+ return refcount;
+}
+
+static ULONG WINAPI opc_rel_enum_Release(IOpcRelationshipEnumerator *iface)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+ ULONG refcount = InterlockedDecrement(&rel_enum->refcount);
+
+ TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ IOpcRelationshipSet_Release(&rel_enum->rel_set->IOpcRelationshipSet_iface);
+ heap_free(rel_enum);
+ }
+
+ return refcount;
+}
+
+static BOOL has_rel_collection_changed(const struct opc_rel_enum *rel_enum)
+{
+ return !IsEqualGUID(&rel_enum->id, &rel_enum->rel_set->id);
+}
+
+static HRESULT WINAPI opc_rel_enum_MoveNext(IOpcRelationshipEnumerator *iface, BOOL *has_next)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+
+ TRACE("iface %p, has_next %p.\n", iface, has_next);
+
+ if (!has_next)
+ return E_POINTER;
+
+ if (has_rel_collection_changed(rel_enum))
+ return OPC_E_ENUM_COLLECTION_CHANGED;
+
+ if (rel_enum->rel_set->count && (rel_enum->pos == ~(size_t)0 || rel_enum->pos < rel_enum->rel_set->count))
+ rel_enum->pos++;
+
+ *has_next = rel_enum->pos < rel_enum->rel_set->count;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI opc_rel_enum_MovePrevious(IOpcRelationshipEnumerator *iface, BOOL *has_previous)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+
+ TRACE("iface %p, has_previous %p.\n", iface, has_previous);
+
+ if (!has_previous)
+ return E_POINTER;
+
+ if (has_rel_collection_changed(rel_enum))
+ return OPC_E_ENUM_COLLECTION_CHANGED;
+
+ if (rel_enum->pos != ~(size_t)0)
+ rel_enum->pos--;
+
+ *has_previous = rel_enum->pos != ~(size_t)0;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI opc_rel_enum_GetCurrent(IOpcRelationshipEnumerator *iface, IOpcRelationship **rel)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+
+ TRACE("iface %p, rel %p.\n", iface, rel);
+
+ if (!rel)
+ return E_POINTER;
+
+ *rel = NULL;
+
+ if (has_rel_collection_changed(rel_enum))
+ return OPC_E_ENUM_COLLECTION_CHANGED;
+
+ if (rel_enum->pos < rel_enum->rel_set->count)
+ {
+ *rel = &rel_enum->rel_set->relationships[rel_enum->pos]->IOpcRelationship_iface;
+ IOpcRelationship_AddRef(*rel);
+ }
+
+ return *rel ? S_OK : OPC_E_ENUM_INVALID_POSITION;
+}
+
+static HRESULT WINAPI opc_rel_enum_Clone(IOpcRelationshipEnumerator *iface, IOpcRelationshipEnumerator **out)
+{
+ struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
+
+ TRACE("iface %p, out %p.\n", iface, out);
+
+ if (!out)
+ return E_POINTER;
+
+ if (has_rel_collection_changed(rel_enum))
+ {
+ *out = NULL;
+ return OPC_E_ENUM_COLLECTION_CHANGED;
+ }
+
+ return opc_rel_enum_create(rel_enum->rel_set, out);
+}
+
+static const IOpcRelationshipEnumeratorVtbl opc_rel_enum_vtbl =
+{
+ opc_rel_enum_QueryInterface,
+ opc_rel_enum_AddRef,
+ opc_rel_enum_Release,
+ opc_rel_enum_MoveNext,
+ opc_rel_enum_MovePrevious,
+ opc_rel_enum_GetCurrent,
+ opc_rel_enum_Clone,
+};
+
+static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out)
+{
+ struct opc_rel_enum *rel_enum;
+
+ if (!(rel_enum = heap_alloc_zero(sizeof(*rel_enum))))
+ return E_OUTOFMEMORY;
+
+ rel_enum->IOpcRelationshipEnumerator_iface.lpVtbl = &opc_rel_enum_vtbl;
+ rel_enum->refcount = 1;
+ rel_enum->rel_set = rel_set;
+ IOpcRelationshipSet_AddRef(&rel_set->IOpcRelationshipSet_iface);
+ rel_enum->pos = ~(size_t)0;
+ rel_enum->id = rel_set->id;
+
+ *out = &rel_enum->IOpcRelationshipEnumerator_iface;
+ TRACE("Created relationship enumerator %p.\n", *out);
+ return S_OK;
+}
+
static HRESULT WINAPI opc_content_stream_QueryInterface(IStream *iface, REFIID iid, void **out)
{
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
@@ -978,6 +1155,7 @@ static HRESULT opc_relationship_create(struct opc_relationship_set *set, const W
set->relationships[set->count++] = relationship;
IOpcRelationship_AddRef(&relationship->IOpcRelationship_iface);
+ CoCreateGuid(&set->id);
*out = &relationship->IOpcRelationship_iface;
TRACE("Created relationship %p.\n", *out);
@@ -1108,9 +1286,14 @@ static HRESULT WINAPI opc_relationship_set_RelationshipExists(IOpcRelationshipSe
static HRESULT WINAPI opc_relationship_set_GetEnumerator(IOpcRelationshipSet *iface,
IOpcRelationshipEnumerator **enumerator)
{
- FIXME("iface %p, enumerator %p stub!\n", iface, enumerator);
+ struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
- return E_NOTIMPL;
+ TRACE("iface %p, enumerator %p.\n", iface, enumerator);
+
+ if (!enumerator)
+ return E_POINTER;
+
+ return opc_rel_enum_create(relationship_set, enumerator);
}
static HRESULT WINAPI opc_relationship_set_GetEnumeratorForType(IOpcRelationshipSet *iface, const WCHAR *type,
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c
index 67e5ffff54..936e2c751d 100644
--- a/dlls/opcservices/tests/opcservices.c
+++ b/dlls/opcservices/tests/opcservices.c
@@ -753,6 +753,168 @@ static void test_part_enumerator(void)
IOpcFactory_Release(factory);
}
+static void test_rels_enumerator(void)
+{
+ static const WCHAR typeW[] = {'t','y','p','e','/','s','u','b','t','y','p','e',0};
+ static const WCHAR targetW[] = {'t','a','r','g','e','t',0};
+ IOpcRelationshipEnumerator *relsenum, *relsenum2;
+ IOpcRelationship *rel, *rel2;
+ IOpcPackage *package;
+ IOpcFactory *factory;
+ IOpcRelationshipSet *rels;
+ IUri *target_uri;
+ HRESULT hr;
+ BOOL ret;
+
+ 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 = IOpcPackage_GetRelationshipSet(package, &rels);
+ ok(SUCCEEDED(hr), "Failed to get part set, hr %#x.\n", hr);
+
+ hr = IOpcRelationshipSet_GetEnumerator(rels, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum);
+ ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr);
+
+ hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum2);
+ ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr);
+ ok(relsenum != relsenum2, "Unexpected instance.\n");
+ IOpcRelationshipEnumerator_Release(relsenum2);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel);
+ ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr);
+
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ ret = TRUE;
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret);
+ ok(hr == S_OK, "Failed to move, hr %#x.\n", hr);
+ ok(!ret, "Unexpected result %d.\n", ret);
+
+ ret = TRUE;
+ hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret);
+ ok(hr == S_OK, "Failed to move, hr %#x.\n", hr);
+ ok(!ret, "Unexpected result %d.\n", ret);
+
+ hr = CreateUri(targetW, Uri_CREATE_ALLOW_RELATIVE, 0, &target_uri);
+ ok(SUCCEEDED(hr), "Failed to create target uri, hr %#x.\n", hr);
+
+ hr = IOpcRelationshipSet_CreateRelationship(rels, NULL, typeW, target_uri, OPC_URI_TARGET_MODE_INTERNAL, &rel);
+ ok(SUCCEEDED(hr), "Failed to create relationship, hr %#x.\n", hr);
+
+ IUri_Release(target_uri);
+
+ rel2 = (void *)0xdeadbeef;
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr);
+ ok(rel2 == NULL, "Unexpected instance.\n");
+
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ ret = 123;
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret);
+ ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr);
+ ok(ret == 123, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ ret = 123;
+ hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret);
+ ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr);
+ ok(ret == 123, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_Clone(relsenum, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ relsenum2 = (void *)0xdeadbeef;
+ hr = IOpcRelationshipEnumerator_Clone(relsenum, &relsenum2);
+ ok(hr == OPC_E_ENUM_COLLECTION_CHANGED, "Unexpected hr %#x.\n", hr);
+ ok(relsenum2 == NULL, "Unexpected instance.\n");
+
+ IOpcRelationshipEnumerator_Release(relsenum);
+
+ hr = IOpcRelationshipSet_GetEnumerator(rels, &relsenum);
+ ok(SUCCEEDED(hr), "Failed to get enumerator, hr %#x.\n", hr);
+
+ rel2 = (void *)0xdeadbeef;
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr);
+ ok(rel2 == NULL, "Unexpected instance.\n");
+
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(ret, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(rel2 == rel, "Unexpected instance.\n");
+ IOpcRelationship_Release(rel2);
+
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum, &ret);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(!ret, "Unexpected result %d.\n", ret);
+
+ rel2 = (void *)0xdeadbeef;
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr);
+ ok(rel2 == NULL, "Unexpected instance.\n");
+
+ hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(ret, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(rel2 == rel, "Unexpected instance.\n");
+ IOpcRelationship_Release(rel2);
+
+ hr = IOpcRelationshipEnumerator_MovePrevious(relsenum, &ret);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(!ret, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr);
+
+ hr = IOpcRelationshipEnumerator_Clone(relsenum, &relsenum2);
+ ok(SUCCEEDED(hr), "Clone failed, hr %#x.\n", hr);
+
+ hr = IOpcRelationshipEnumerator_MoveNext(relsenum2, &ret);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ ok(ret, "Unexpected result %d.\n", ret);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum2, &rel2);
+ ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ IOpcRelationship_Release(rel2);
+
+ hr = IOpcRelationshipEnumerator_GetCurrent(relsenum, &rel2);
+ ok(hr == OPC_E_ENUM_INVALID_POSITION, "Unexpected hr %#x.\n", hr);
+
+ IOpcRelationshipEnumerator_Release(relsenum2);
+
+ IOpcRelationshipEnumerator_Release(relsenum);
+
+ IOpcRelationship_Release(rel);
+
+ IOpcRelationshipSet_Release(rels);
+
+ IOpcPackage_Release(package);
+ IOpcFactory_Release(factory);
+}
START_TEST(opcservices)
{
IOpcFactory *factory;
@@ -772,6 +934,7 @@ START_TEST(opcservices)
test_relationship();
test_rel_part_uri();
test_part_enumerator();
+ test_rels_enumerator();
IOpcFactory_Release(factory);
--
2.18.0
More information about the wine-devel
mailing list