Sweden-Number/dlls/opcservices/package.c

1155 lines
32 KiB
C
Raw Normal View History

/*
* Copyright 2018 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "ntsecapi.h"
#include "xmllite.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "opc_private.h"
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;
LONG refcount;
IOpcPartSet *part_set;
IOpcRelationshipSet *relationship_set;
IOpcUri *source_uri;
};
struct opc_part
{
IOpcPart IOpcPart_iface;
LONG refcount;
IOpcPartUri *name;
WCHAR *content_type;
DWORD compression_options;
IOpcRelationshipSet *relationship_set;
struct opc_content *content;
};
struct opc_part_set
{
IOpcPartSet IOpcPartSet_iface;
LONG refcount;
struct opc_part **parts;
size_t size;
size_t count;
};
struct opc_relationship
{
IOpcRelationship IOpcRelationship_iface;
LONG refcount;
WCHAR *id;
WCHAR *type;
IUri *target;
OPC_URI_TARGET_MODE target_mode;
IOpcUri *source_uri;
};
struct opc_relationship_set
{
IOpcRelationshipSet IOpcRelationshipSet_iface;
LONG refcount;
struct opc_relationship **relationships;
size_t size;
size_t count;
IOpcUri *source_uri;
};
static inline struct opc_package *impl_from_IOpcPackage(IOpcPackage *iface)
{
return CONTAINING_RECORD(iface, struct opc_package, IOpcPackage_iface);
}
static inline struct opc_part_set *impl_from_IOpcPartSet(IOpcPartSet *iface)
{
return CONTAINING_RECORD(iface, struct opc_part_set, IOpcPartSet_iface);
}
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 inline struct opc_relationship *impl_from_IOpcRelationship(IOpcRelationship *iface)
{
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)
{
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);
if (IsEqualIID(iid, &IID_IOpcPart) ||
IsEqualIID(iid, &IID_IUnknown))
{
*out = iface;
IOpcPart_AddRef(iface);
return S_OK;
}
WARN("Unsupported interface %s.\n", debugstr_guid(iid));
return E_NOINTERFACE;
}
static ULONG WINAPI opc_part_AddRef(IOpcPart *iface)
{
struct opc_part *part = impl_from_IOpcPart(iface);
ULONG refcount = InterlockedIncrement(&part->refcount);
TRACE("%p increasing refcount to %u.\n", iface, refcount);
return refcount;
}
static ULONG WINAPI opc_part_Release(IOpcPart *iface)
{
struct opc_part *part = impl_from_IOpcPart(iface);
ULONG refcount = InterlockedDecrement(&part->refcount);
TRACE("%p decreasing refcount to %u.\n", iface, refcount);
if (!refcount)
{
if (part->relationship_set)
IOpcRelationshipSet_Release(part->relationship_set);
IOpcPartUri_Release(part->name);
CoTaskMemFree(part->content_type);
opc_content_release(part->content);
heap_free(part);
}
return refcount;
}
static HRESULT WINAPI opc_part_GetRelationshipSet(IOpcPart *iface, IOpcRelationshipSet **relationship_set)
{
struct opc_part *part = impl_from_IOpcPart(iface);
HRESULT hr;
TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
if (!part->relationship_set && FAILED(hr = opc_relationship_set_create((IOpcUri *)part->name, &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)
{
struct opc_part *part = impl_from_IOpcPart(iface);
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)
{
struct opc_part *part = impl_from_IOpcPart(iface);
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)
{
struct opc_part *part = impl_from_IOpcPart(iface);
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)
{
struct opc_part *part = impl_from_IOpcPart(iface);
TRACE("iface %p, options %p.\n", iface, options);
*options = part->compression_options;
return S_OK;
}
static const IOpcPartVtbl opc_part_vtbl =
{
opc_part_QueryInterface,
opc_part_AddRef,
opc_part_Release,
opc_part_GetRelationshipSet,
opc_part_GetContentStream,
opc_part_GetName,
opc_part_GetContentType,
opc_part_GetCompressionOptions,
};
static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, const WCHAR *content_type,
DWORD compression_options, IOpcPart **out)
{
struct opc_part *part;
if (!name)
return E_POINTER;
if (!opc_array_reserve((void **)&set->parts, &set->size, set->count + 1, sizeof(*set->parts)))
return E_OUTOFMEMORY;
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;
}
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);
*out = &part->IOpcPart_iface;
TRACE("Created part %p.\n", *out);
return S_OK;
}
static HRESULT WINAPI opc_part_set_QueryInterface(IOpcPartSet *iface, REFIID iid, void **out)
{
TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
if (IsEqualIID(iid, &IID_IOpcPartSet) ||
IsEqualIID(iid, &IID_IUnknown))
{
*out = iface;
IOpcPartSet_AddRef(iface);
return S_OK;
}
WARN("Unsupported interface %s.\n", debugstr_guid(iid));
return E_NOINTERFACE;
}
static ULONG WINAPI opc_part_set_AddRef(IOpcPartSet *iface)
{
struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
ULONG refcount = InterlockedIncrement(&part_set->refcount);
TRACE("%p increasing refcount to %u.\n", iface, refcount);
return refcount;
}
static ULONG WINAPI opc_part_set_Release(IOpcPartSet *iface)
{
struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
ULONG refcount = InterlockedDecrement(&part_set->refcount);
TRACE("%p decreasing refcount to %u.\n", iface, refcount);
if (!refcount)
{
size_t i;
for (i = 0; i < part_set->count; ++i)
IOpcPart_Release(&part_set->parts[i]->IOpcPart_iface);
heap_free(part_set->parts);
heap_free(part_set);
}
return refcount;
}
static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name, IOpcPart **part)
{
FIXME("iface %p, name %p, part %p stub!\n", iface, name, part);
return E_NOTIMPL;
}
static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *name, LPCWSTR content_type,
OPC_COMPRESSION_OPTIONS compression_options, IOpcPart **part)
{
struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
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_set, name, content_type, compression_options, part);
}
static HRESULT WINAPI opc_part_set_DeletePart(IOpcPartSet *iface, IOpcPartUri *name)
{
FIXME("iface %p, name %p stub!\n", iface, name);
return E_NOTIMPL;
}
static HRESULT WINAPI opc_part_set_PartExists(IOpcPartSet *iface, IOpcPartUri *name, BOOL *exists)
{
FIXME("iface %p, name %p, exists %p stub!\n", iface, name, exists);
return E_NOTIMPL;
}
static HRESULT WINAPI opc_part_set_GetEnumerator(IOpcPartSet *iface, IOpcPartEnumerator **enumerator)
{
FIXME("iface %p, enumerator %p stub!\n", iface, enumerator);
return E_NOTIMPL;
}
static const IOpcPartSetVtbl opc_part_set_vtbl =
{
opc_part_set_QueryInterface,
opc_part_set_AddRef,
opc_part_set_Release,
opc_part_set_GetPart,
opc_part_set_CreatePart,
opc_part_set_DeletePart,
opc_part_set_PartExists,
opc_part_set_GetEnumerator,
};
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)
{
CoTaskMemFree(relationship->id);
CoTaskMemFree(relationship->type);
IOpcUri_Release(relationship->source_uri);
IUri_Release(relationship->target);
heap_free(relationship);
}
return refcount;
}
static HRESULT WINAPI opc_relationship_GetId(IOpcRelationship *iface, WCHAR **id)
{
struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
TRACE("iface %p, id %p.\n", iface, id);
*id = opc_strdupW(relationship->id);
return *id ? S_OK : E_OUTOFMEMORY;
}
static HRESULT WINAPI opc_relationship_GetRelationshipType(IOpcRelationship *iface, WCHAR **type)
{
struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
TRACE("iface %p, type %p.\n", iface, type);
*type = opc_strdupW(relationship->type);
return *type ? S_OK : E_OUTOFMEMORY;
}
static HRESULT WINAPI opc_relationship_GetSourceUri(IOpcRelationship *iface, IOpcUri **uri)
{
struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
TRACE("iface %p, uri %p.\n", iface, uri);
*uri = relationship->source_uri;
IOpcUri_AddRef(*uri);
return S_OK;
}
static HRESULT WINAPI opc_relationship_GetTargetUri(IOpcRelationship *iface, IUri **target)
{
struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
TRACE("iface %p, target %p.\n", iface, target);
*target = relationship->target;
IUri_AddRef(*target);
return S_OK;
}
static HRESULT WINAPI opc_relationship_GetTargetMode(IOpcRelationship *iface, OPC_URI_TARGET_MODE *target_mode)
{
struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
TRACE("iface %p, target_mode %p.\n", iface, target_mode);
*target_mode = relationship->target_mode;
return S_OK;
}
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(struct opc_relationship_set *set, const WCHAR *id, const WCHAR *type,
IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **out)
{
struct opc_relationship *relationship;
if (!opc_array_reserve((void **)&set->relationships, &set->size, set->count + 1, sizeof(*set->relationships)))
return E_OUTOFMEMORY;
if (!(relationship = heap_alloc_zero(sizeof(*relationship))))
return E_OUTOFMEMORY;
relationship->IOpcRelationship_iface.lpVtbl = &opc_relationship_vtbl;
relationship->refcount = 1;
relationship->target = target_uri;
IUri_AddRef(relationship->target);
relationship->source_uri = set->source_uri;
IOpcUri_AddRef(relationship->source_uri);
/* FIXME: test that id is unique */
if (id)
relationship->id = opc_strdupW(id);
else
{
relationship->id = CoTaskMemAlloc(10 * sizeof(WCHAR));
if (relationship->id)
{
static const WCHAR fmtW[] = {'R','%','0','8','X',0};
DWORD generated;
RtlGenRandom(&generated, sizeof(generated));
sprintfW(relationship->id, fmtW, generated);
}
}
relationship->type = opc_strdupW(type);
if (!relationship->id || !relationship->type)
{
IOpcRelationship_Release(&relationship->IOpcRelationship_iface);
return E_OUTOFMEMORY;
}
set->relationships[set->count++] = relationship;
IOpcRelationship_AddRef(&relationship->IOpcRelationship_iface);
*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);
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)
{
size_t i;
for (i = 0; i < relationship_set->count; ++i)
IOpcRelationship_Release(&relationship_set->relationships[i]->IOpcRelationship_iface);
IOpcUri_Release(relationship_set->source_uri);
heap_free(relationship_set->relationships);
heap_free(relationship_set);
}
return refcount;
}
static struct opc_relationship *opc_relationshipset_get_item(struct opc_relationship_set *relationship_set,
const WCHAR *id)
{
size_t i;
for (i = 0; i < relationship_set->count; i++)
{
if (!strcmpW(id, relationship_set->relationships[i]->id))
return relationship_set->relationships[i];
}
return NULL;
}
static HRESULT WINAPI opc_relationship_set_GetRelationship(IOpcRelationshipSet *iface, const WCHAR *id,
IOpcRelationship **relationship)
{
struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
struct opc_relationship *ret;
TRACE("iface %p, id %s, relationship %p.\n", iface, debugstr_w(id), relationship);
if (!relationship)
return E_POINTER;
*relationship = NULL;
if (!id)
return E_POINTER;
if ((ret = opc_relationshipset_get_item(relationship_set, id)))
{
*relationship = &ret->IOpcRelationship_iface;
IOpcRelationship_AddRef(*relationship);
}
return *relationship ? S_OK : OPC_E_NO_SUCH_RELATIONSHIP;
}
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)
{
struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
TRACE("iface %p, id %s, type %s, target_uri %p, target_mode %d, relationship %p.\n", iface, debugstr_w(id),
debugstr_w(type), target_uri, target_mode, relationship);
if (!type || !target_uri)
return E_POINTER;
return opc_relationship_create(relationship_set, id, type, target_uri, target_mode, relationship);
}
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)
{
struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
TRACE("iface %p, id %s, exists %p.\n", iface, debugstr_w(id), exists);
if (!id || !exists)
return E_POINTER;
*exists = opc_relationshipset_get_item(relationship_set, id) != NULL;
return S_OK;
}
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(IOpcUri *source_uri, 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;
relationship_set->source_uri = source_uri;
IOpcUri_AddRef(relationship_set->source_uri);
*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);
if (IsEqualIID(iid, &IID_IOpcPackage) ||
IsEqualIID(iid, &IID_IUnknown))
{
*out = iface;
IOpcPackage_AddRef(iface);
return S_OK;
}
WARN("Unsupported interface %s.\n", debugstr_guid(iid));
return E_NOINTERFACE;
}
static ULONG WINAPI opc_package_AddRef(IOpcPackage *iface)
{
struct opc_package *package = impl_from_IOpcPackage(iface);
ULONG refcount = InterlockedIncrement(&package->refcount);
TRACE("%p increasing refcount to %u.\n", iface, refcount);
return refcount;
}
static ULONG WINAPI opc_package_Release(IOpcPackage *iface)
{
struct opc_package *package = impl_from_IOpcPackage(iface);
ULONG refcount = InterlockedDecrement(&package->refcount);
TRACE("%p decreasing refcount to %u.\n", iface, refcount);
if (!refcount)
{
if (package->part_set)
IOpcPartSet_Release(package->part_set);
if (package->relationship_set)
IOpcRelationshipSet_Release(package->relationship_set);
if (package->source_uri)
IOpcUri_Release(package->source_uri);
heap_free(package);
}
return refcount;
}
static HRESULT WINAPI opc_package_GetPartSet(IOpcPackage *iface, IOpcPartSet **part_set)
{
struct opc_package *package = impl_from_IOpcPackage(iface);
TRACE("iface %p, part_set %p.\n", iface, part_set);
if (!package->part_set)
{
struct opc_part_set *part_set = heap_alloc_zero(sizeof(*part_set));
if (!part_set)
return E_OUTOFMEMORY;
part_set->IOpcPartSet_iface.lpVtbl = &opc_part_set_vtbl;
part_set->refcount = 1;
package->part_set = &part_set->IOpcPartSet_iface;
}
*part_set = package->part_set;
IOpcPartSet_AddRef(*part_set);
return S_OK;
}
static HRESULT WINAPI opc_package_GetRelationshipSet(IOpcPackage *iface, IOpcRelationshipSet **relationship_set)
{
struct opc_package *package = impl_from_IOpcPackage(iface);
HRESULT hr;
TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
if (!package->relationship_set)
{
if (FAILED(hr = opc_relationship_set_create(package->source_uri, &package->relationship_set)))
return hr;
}
*relationship_set = package->relationship_set;
IOpcRelationshipSet_AddRef(*relationship_set);
return S_OK;
}
static const IOpcPackageVtbl opc_package_vtbl =
{
opc_package_QueryInterface,
opc_package_AddRef,
opc_package_Release,
opc_package_GetPartSet,
opc_package_GetRelationshipSet,
};
HRESULT opc_package_create(IOpcFactory *factory, IOpcPackage **out)
{
struct opc_package *package;
HRESULT hr;
if (!(package = heap_alloc_zero(sizeof(*package))))
return E_OUTOFMEMORY;
package->IOpcPackage_iface.lpVtbl = &opc_package_vtbl;
package->refcount = 1;
if (FAILED(hr = IOpcFactory_CreatePackageRootUri(factory, &package->source_uri)))
{
heap_free(package);
return hr;
}
*out = &package->IOpcPackage_iface;
TRACE("Created package %p.\n", *out);
return S_OK;
}
static HRESULT opc_package_write_contenttypes(struct zip_archive *archive, IXmlWriter *writer)
{
static const WCHAR uriW[] = {'h','t','t','p',':','/','/','s','c','h','e','m','a','s','.','o','p','e','n','x','m','l','f','o','r','m','a','t','s','.','o','r','g','/',
'p','a','c','k','a','g','e','/','2','0','0','6','/','c','o','n','t','e','n','t','-','t','y','p','e','s',0};
static const WCHAR contenttypesW[] = {'[','C','o','n','t','e','n','t','_','T','y','p','e','s',']','.','x','m','l',0};
static const WCHAR typesW[] = {'T','y','p','e','s',0};
IStream *content;
HRESULT hr;
if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content)))
return hr;
IXmlWriter_SetOutput(writer, (IUnknown *)content);
hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
if (SUCCEEDED(hr))
hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW);
if (SUCCEEDED(hr))
hr = IXmlWriter_WriteEndDocument(writer);
if (SUCCEEDED(hr))
hr = IXmlWriter_Flush(writer);
if (SUCCEEDED(hr))
hr = compress_add_file(archive, contenttypesW, content, OPC_COMPRESSION_NORMAL);
IStream_Release(content);
return hr;
}
HRESULT opc_package_write(IOpcPackage *input, OPC_WRITE_FLAGS flags, IStream *stream)
{
struct zip_archive *archive;
IXmlWriter *writer;
HRESULT hr;
if (flags != OPC_WRITE_FORCE_ZIP32)
FIXME("Unsupported write flags %#x.\n", flags);
if (FAILED(hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL)))
return hr;
if (FAILED(hr = compress_create_archive(stream, &archive)))
{
IXmlWriter_Release(writer);
return hr;
}
/* [Content_Types].xml */
hr = opc_package_write_contenttypes(archive, writer);
compress_finalize_archive(archive);
IXmlWriter_Release(writer);
return hr;
}