[PATCH] opcservices: Partially implement content stream for package parts.
Nikolay Sivov
nsivov at codeweavers.com
Wed Sep 12 08:26:14 CDT 2018
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
dlls/opcservices/factory.c | 2 +-
dlls/opcservices/package.c | 272 ++++++++++++++++++++++++++-
dlls/opcservices/tests/opcservices.c | 35 ++++
3 files changed, 306 insertions(+), 3 deletions(-)
diff --git a/dlls/opcservices/factory.c b/dlls/opcservices/factory.c
index 9036141495..1a98f3f49d 100644
--- a/dlls/opcservices/factory.c
+++ b/dlls/opcservices/factory.c
@@ -278,7 +278,7 @@ static HRESULT opc_filestream_create(const WCHAR *filename, OPC_STREAM_IO_MODE i
stream->refcount = 1;
*out = &stream->IStream_iface;
- TRACE("Created file steam %p.\n", *out);
+ TRACE("Created file stream %p.\n", *out);
return S_OK;
}
diff --git a/dlls/opcservices/package.c b/dlls/opcservices/package.c
index 66cc49a16e..c7ae2581cc 100644
--- a/dlls/opcservices/package.c
+++ b/dlls/opcservices/package.c
@@ -31,6 +31,22 @@
WINE_DEFAULT_DEBUG_CHANNEL(msopc);
+struct opc_content
+{
+ LONG refcount;
+ BYTE *data;
+ ULARGE_INTEGER size;
+};
+
+struct opc_content_stream
+{
+ IStream IStream_iface;
+ LONG refcount;
+
+ struct opc_content *content;
+ ULARGE_INTEGER pos;
+};
+
struct opc_package
{
IOpcPackage IOpcPackage_iface;
@@ -50,6 +66,7 @@ struct opc_part
WCHAR *content_type;
DWORD compression_options;
IOpcRelationshipSet *relationship_set;
+ struct opc_content *content;
};
struct opc_part_set
@@ -110,6 +127,243 @@ static inline struct opc_relationship *impl_from_IOpcRelationship(IOpcRelationsh
return CONTAINING_RECORD(iface, struct opc_relationship, IOpcRelationship_iface);
}
+static inline struct opc_content_stream *impl_from_IStream(IStream *iface)
+{
+ return CONTAINING_RECORD(iface, struct opc_content_stream, IStream_iface);
+}
+
+static void opc_content_release(struct opc_content *content)
+{
+ ULONG refcount = InterlockedDecrement(&content->refcount);
+
+ if (!refcount)
+ {
+ heap_free(content->data);
+ heap_free(content);
+ }
+}
+
+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);
+
+ 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_content_stream_AddRef(IStream *iface)
+{
+ struct opc_content_stream *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_content_stream_Release(IStream *iface)
+{
+ struct opc_content_stream *stream = impl_from_IStream(iface);
+ ULONG refcount = InterlockedDecrement(&stream->refcount);
+
+ TRACE("%p decreasing refcount to %u.\n", iface, refcount);
+
+ if (!refcount)
+ {
+ opc_content_release(stream->content);
+ heap_free(stream);
+ }
+
+ return refcount;
+}
+
+static HRESULT WINAPI opc_content_stream_Read(IStream *iface, void *buff, ULONG size, ULONG *num_read)
+{
+ struct opc_content_stream *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;
+
+ if (stream->content->size.QuadPart - stream->pos.QuadPart < size)
+ *num_read = stream->content->size.QuadPart - stream->pos.QuadPart;
+ else
+ *num_read = size;
+
+ if (*num_read)
+ memcpy(buff, stream->content->data + stream->pos.QuadPart, *num_read);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI opc_content_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *num_written)
+{
+ struct opc_content_stream *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 (size > stream->content->size.QuadPart - stream->pos.QuadPart)
+ {
+ void *ptr = heap_realloc(stream->content->data, stream->pos.QuadPart + size);
+ if (!ptr)
+ return E_OUTOFMEMORY;
+ stream->content->data = ptr;
+ }
+
+ memcpy(stream->content->data + stream->pos.QuadPart, data, size);
+ stream->pos.QuadPart += size;
+ stream->content->size.QuadPart += size;
+ *num_written = size;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI opc_content_stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos)
+{
+ struct opc_content_stream *stream = impl_from_IStream(iface);
+ ULARGE_INTEGER pos;
+
+ TRACE("iface %p, move %s, origin %d, newpos %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, newpos);
+
+ switch (origin)
+ {
+ case STREAM_SEEK_SET:
+ pos.QuadPart = move.QuadPart;
+ break;
+ case STREAM_SEEK_CUR:
+ pos.QuadPart = stream->pos.QuadPart + move.QuadPart;
+ break;
+ case STREAM_SEEK_END:
+ pos.QuadPart = stream->content->size.QuadPart + move.QuadPart;
+ default:
+ WARN("Unknown origin mode %d.\n", origin);
+ return E_INVALIDARG;
+ }
+
+ stream->pos = pos;
+
+ if (newpos)
+ *newpos = stream->pos;
+
+ return S_OK;
+}
+
+static HRESULT WINAPI opc_content_stream_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_content_stream_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_content_stream_Commit(IStream *iface, DWORD flags)
+{
+ FIXME("iface %p, flags %#x stub!\n", iface, flags);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI opc_content_stream_Revert(IStream *iface)
+{
+ FIXME("iface %p stub!\n", iface);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI opc_content_stream_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_content_stream_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_content_stream_Stat(IStream *iface, STATSTG *statstg, DWORD flag)
+{
+ FIXME("iface %p, statstg %p, flag %d stub!\n", iface, statstg, flag);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI opc_content_stream_Clone(IStream *iface, IStream **result)
+{
+ FIXME("iface %p, result %p stub!\n", iface, result);
+
+ return E_NOTIMPL;
+}
+
+static const IStreamVtbl opc_content_stream_vtbl =
+{
+ opc_content_stream_QueryInterface,
+ opc_content_stream_AddRef,
+ opc_content_stream_Release,
+ opc_content_stream_Read,
+ opc_content_stream_Write,
+ opc_content_stream_Seek,
+ opc_content_stream_SetSize,
+ opc_content_stream_CopyTo,
+ opc_content_stream_Commit,
+ opc_content_stream_Revert,
+ opc_content_stream_LockRegion,
+ opc_content_stream_UnlockRegion,
+ opc_content_stream_Stat,
+ opc_content_stream_Clone,
+};
+
+static HRESULT opc_content_stream_create(struct opc_content *content, IStream **out)
+{
+ struct opc_content_stream *stream;
+
+ if (!(stream = heap_alloc_zero(sizeof(*stream))))
+ return E_OUTOFMEMORY;
+
+ stream->IStream_iface.lpVtbl = &opc_content_stream_vtbl;
+ stream->refcount = 1;
+ stream->content = content;
+ InterlockedIncrement(&content->refcount);
+
+ *out = &stream->IStream_iface;
+
+ TRACE("Created content stream %p.\n", *out);
+ return S_OK;
+}
+
static HRESULT opc_relationship_set_create(IOpcUri *source_uri, IOpcRelationshipSet **relationship_set);
static WCHAR *opc_strdupW(const WCHAR *str)
@@ -168,6 +422,7 @@ static ULONG WINAPI opc_part_Release(IOpcPart *iface)
IOpcRelationshipSet_Release(part->relationship_set);
IOpcPartUri_Release(part->name);
CoTaskMemFree(part->content_type);
+ opc_content_release(part->content);
heap_free(part);
}
@@ -192,9 +447,14 @@ static HRESULT WINAPI opc_part_GetRelationshipSet(IOpcPart *iface, IOpcRelations
static HRESULT WINAPI opc_part_GetContentStream(IOpcPart *iface, IStream **stream)
{
- FIXME("iface %p, stream %p stub!\n", iface, stream);
+ struct opc_part *part = impl_from_IOpcPart(iface);
- return E_NOTIMPL;
+ TRACE("iface %p, stream %p.\n", iface, stream);
+
+ if (!stream)
+ return E_POINTER;
+
+ return opc_content_stream_create(part->content, stream);
}
static HRESULT WINAPI opc_part_GetName(IOpcPart *iface, IOpcPartUri **name)
@@ -266,6 +526,14 @@ static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, cons
return E_OUTOFMEMORY;
}
+ part->content = heap_alloc_zero(sizeof(*part->content));
+ if (!part->content)
+ {
+ IOpcPart_Release(&part->IOpcPart_iface);
+ return E_OUTOFMEMORY;
+ }
+ part->content->refcount = 1;
+
set->parts[set->count++] = part;
IOpcPart_AddRef(&part->IOpcPart_iface);
diff --git a/dlls/opcservices/tests/opcservices.c b/dlls/opcservices/tests/opcservices.c
index 84a8c12dc9..f6194609ed 100644
--- a/dlls/opcservices/tests/opcservices.c
+++ b/dlls/opcservices/tests/opcservices.c
@@ -44,12 +44,16 @@ static void test_package(void)
static const WCHAR rootW[] = {'/',0};
IOpcRelationshipSet *relset, *relset2;
IOpcPartSet *partset, *partset2;
+ IStream *stream, *stream2;
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;
BSTR str;
@@ -82,6 +86,37 @@ 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_GetContentStream(part, NULL);
+ ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
+
+ hr = IOpcPart_GetContentStream(part, &stream);
+ ok(SUCCEEDED(hr), "Failed to get content stream, hr %#x.\n", hr);
+
+ hr = IStream_Write(stream, "abc", 3, NULL);
+ ok(hr == S_OK, "Failed to write content, hr %#x.\n", hr);
+
+ move.QuadPart = 0;
+ hr = IStream_Seek(stream, move, STREAM_SEEK_CUR, &pos);
+ ok(SUCCEEDED(hr), "Seek failed, hr %#x.\n", hr);
+ ok(pos.QuadPart == 3, "Unexpected position.\n");
+
+ hr = IOpcPart_GetContentStream(part, &stream2);
+ ok(SUCCEEDED(hr), "Failed to get content stream, hr %#x.\n", hr);
+ ok(stream != stream2, "Unexpected instance.\n");
+
+ move.QuadPart = 0;
+ hr = IStream_Seek(stream2, move, STREAM_SEEK_CUR, &pos);
+ ok(SUCCEEDED(hr), "Seek failed, hr %#x.\n", hr);
+ ok(pos.QuadPart == 0, "Unexpected position.\n");
+
+ memset(buff, 0, sizeof(buff));
+ hr = IStream_Read(stream2, buff, sizeof(buff), NULL);
+ ok(hr == S_OK, "Failed to read content, hr %#x.\n", hr);
+ ok(!memcmp(buff, "abc", 3), "Unexpected content.\n");
+
+ IStream_Release(stream);
+ IStream_Release(stream2);
+
hr = IOpcPart_GetRelationshipSet(part, &relset);
ok(SUCCEEDED(hr), "Failed to get relationship set, hr %#x.\n", hr);
--
2.18.0
More information about the wine-devel
mailing list