Commit 9b11e371 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

opcservices: Partially implement content stream for package parts.

parent 1517695f
......@@ -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;
}
......
......@@ -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);
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment