[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