opcservices: Add missing error check (Coverity).
[wine.git] / dlls / opcservices / package.c
blob5f4f9552532c7d248c606dbe17a0ccafb894434a
1 /*
2 * Copyright 2018 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <stdarg.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "ntsecapi.h"
25 #include "xmllite.h"
27 #include "wine/debug.h"
28 #include "wine/list.h"
29 #include "wine/unicode.h"
31 #include "opc_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msopc);
35 struct opc_content
37 LONG refcount;
38 BYTE *data;
39 ULARGE_INTEGER size;
42 struct opc_content_stream
44 IStream IStream_iface;
45 LONG refcount;
47 struct opc_content *content;
48 ULARGE_INTEGER pos;
51 struct opc_package
53 IOpcPackage IOpcPackage_iface;
54 LONG refcount;
56 IOpcPartSet *part_set;
57 IOpcRelationshipSet *relationship_set;
58 IOpcUri *source_uri;
61 struct opc_part_enum
63 IOpcPartEnumerator IOpcPartEnumerator_iface;
64 LONG refcount;
66 struct opc_part_set *part_set;
67 size_t pos;
68 GUID id;
71 struct opc_part
73 IOpcPart IOpcPart_iface;
74 LONG refcount;
76 IOpcPartUri *name;
77 WCHAR *content_type;
78 DWORD compression_options;
79 IOpcRelationshipSet *relationship_set;
80 struct opc_content *content;
83 struct opc_part_set
85 IOpcPartSet IOpcPartSet_iface;
86 LONG refcount;
88 struct opc_part **parts;
89 size_t size;
90 size_t count;
91 GUID id;
94 struct opc_rel_enum
96 IOpcRelationshipEnumerator IOpcRelationshipEnumerator_iface;
97 LONG refcount;
99 struct opc_relationship_set *rel_set;
100 size_t pos;
101 GUID id;
104 struct opc_relationship
106 IOpcRelationship IOpcRelationship_iface;
107 LONG refcount;
109 WCHAR *id;
110 WCHAR *type;
111 IUri *target;
112 OPC_URI_TARGET_MODE target_mode;
113 IOpcUri *source_uri;
116 struct opc_relationship_set
118 IOpcRelationshipSet IOpcRelationshipSet_iface;
119 LONG refcount;
121 struct opc_relationship **relationships;
122 size_t size;
123 size_t count;
124 IOpcUri *source_uri;
125 GUID id;
128 static inline struct opc_package *impl_from_IOpcPackage(IOpcPackage *iface)
130 return CONTAINING_RECORD(iface, struct opc_package, IOpcPackage_iface);
133 static inline struct opc_part_set *impl_from_IOpcPartSet(IOpcPartSet *iface)
135 return CONTAINING_RECORD(iface, struct opc_part_set, IOpcPartSet_iface);
138 static inline struct opc_part *impl_from_IOpcPart(IOpcPart *iface)
140 return CONTAINING_RECORD(iface, struct opc_part, IOpcPart_iface);
143 static inline struct opc_relationship_set *impl_from_IOpcRelationshipSet(IOpcRelationshipSet *iface)
145 return CONTAINING_RECORD(iface, struct opc_relationship_set, IOpcRelationshipSet_iface);
148 static inline struct opc_relationship *impl_from_IOpcRelationship(IOpcRelationship *iface)
150 return CONTAINING_RECORD(iface, struct opc_relationship, IOpcRelationship_iface);
153 static inline struct opc_content_stream *impl_from_IStream(IStream *iface)
155 return CONTAINING_RECORD(iface, struct opc_content_stream, IStream_iface);
158 static inline struct opc_part_enum *impl_from_IOpcPartEnumerator(IOpcPartEnumerator *iface)
160 return CONTAINING_RECORD(iface, struct opc_part_enum, IOpcPartEnumerator_iface);
163 static inline struct opc_rel_enum *impl_from_IOpcRelationshipEnumerator(IOpcRelationshipEnumerator *iface)
165 return CONTAINING_RECORD(iface, struct opc_rel_enum, IOpcRelationshipEnumerator_iface);
168 static void opc_content_release(struct opc_content *content)
170 ULONG refcount = InterlockedDecrement(&content->refcount);
172 if (!refcount)
174 heap_free(content->data);
175 heap_free(content);
179 static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnumerator **out);
181 static HRESULT WINAPI opc_part_enum_QueryInterface(IOpcPartEnumerator *iface, REFIID iid, void **out)
183 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
185 if (IsEqualIID(&IID_IOpcPartEnumerator, iid) ||
186 IsEqualIID(&IID_IUnknown, iid))
188 *out = iface;
189 IOpcPartEnumerator_AddRef(iface);
190 return S_OK;
193 *out = NULL;
194 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
195 return E_NOINTERFACE;
198 static ULONG WINAPI opc_part_enum_AddRef(IOpcPartEnumerator *iface)
200 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
201 ULONG refcount = InterlockedIncrement(&part_enum->refcount);
203 TRACE("%p increasing refcount to %u.\n", iface, refcount);
205 return refcount;
208 static ULONG WINAPI opc_part_enum_Release(IOpcPartEnumerator *iface)
210 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
211 ULONG refcount = InterlockedDecrement(&part_enum->refcount);
213 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
215 if (!refcount)
217 IOpcPartSet_Release(&part_enum->part_set->IOpcPartSet_iface);
218 heap_free(part_enum);
221 return refcount;
224 static BOOL has_part_collection_changed(const struct opc_part_enum *part_enum)
226 return !IsEqualGUID(&part_enum->id, &part_enum->part_set->id);
229 static HRESULT WINAPI opc_part_enum_MoveNext(IOpcPartEnumerator *iface, BOOL *has_next)
231 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
233 TRACE("iface %p, has_next %p.\n", iface, has_next);
235 if (!has_next)
236 return E_POINTER;
238 if (has_part_collection_changed(part_enum))
239 return OPC_E_ENUM_COLLECTION_CHANGED;
241 if (part_enum->part_set->count && (part_enum->pos == ~(size_t)0 || part_enum->pos < part_enum->part_set->count))
242 part_enum->pos++;
244 *has_next = part_enum->pos < part_enum->part_set->count;
246 return S_OK;
249 static HRESULT WINAPI opc_part_enum_MovePrevious(IOpcPartEnumerator *iface, BOOL *has_previous)
251 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
253 TRACE("iface %p, has_previous %p.\n", iface, has_previous);
255 if (!has_previous)
256 return E_POINTER;
258 if (has_part_collection_changed(part_enum))
259 return OPC_E_ENUM_COLLECTION_CHANGED;
261 if (part_enum->pos != ~(size_t)0)
262 part_enum->pos--;
264 *has_previous = part_enum->pos != ~(size_t)0;
266 return S_OK;
269 static HRESULT WINAPI opc_part_enum_GetCurrent(IOpcPartEnumerator *iface, IOpcPart **part)
271 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
273 TRACE("iface %p, part %p.\n", iface, part);
275 if (!part)
276 return E_POINTER;
278 *part = NULL;
280 if (has_part_collection_changed(part_enum))
281 return OPC_E_ENUM_COLLECTION_CHANGED;
283 if (part_enum->pos < part_enum->part_set->count)
285 *part = &part_enum->part_set->parts[part_enum->pos]->IOpcPart_iface;
286 IOpcPart_AddRef(*part);
289 return *part ? S_OK : OPC_E_ENUM_INVALID_POSITION;
292 static HRESULT WINAPI opc_part_enum_Clone(IOpcPartEnumerator *iface, IOpcPartEnumerator **out)
294 struct opc_part_enum *part_enum = impl_from_IOpcPartEnumerator(iface);
296 TRACE("iface %p, out %p.\n", iface, out);
298 if (!out)
299 return E_POINTER;
301 if (has_part_collection_changed(part_enum))
303 *out = NULL;
304 return OPC_E_ENUM_COLLECTION_CHANGED;
307 return opc_part_enum_create(part_enum->part_set, out);
310 static const IOpcPartEnumeratorVtbl opc_part_enum_vtbl =
312 opc_part_enum_QueryInterface,
313 opc_part_enum_AddRef,
314 opc_part_enum_Release,
315 opc_part_enum_MoveNext,
316 opc_part_enum_MovePrevious,
317 opc_part_enum_GetCurrent,
318 opc_part_enum_Clone,
321 static HRESULT opc_part_enum_create(struct opc_part_set *part_set, IOpcPartEnumerator **out)
323 struct opc_part_enum *part_enum;
325 if (!(part_enum = heap_alloc_zero(sizeof(*part_enum))))
326 return E_OUTOFMEMORY;
328 part_enum->IOpcPartEnumerator_iface.lpVtbl = &opc_part_enum_vtbl;
329 part_enum->refcount = 1;
330 part_enum->part_set = part_set;
331 IOpcPartSet_AddRef(&part_set->IOpcPartSet_iface);
332 part_enum->pos = ~(size_t)0;
333 part_enum->id = part_set->id;
335 *out = &part_enum->IOpcPartEnumerator_iface;
336 TRACE("Created part enumerator %p.\n", *out);
337 return S_OK;
340 static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out);
342 static HRESULT WINAPI opc_rel_enum_QueryInterface(IOpcRelationshipEnumerator *iface, REFIID iid, void **out)
344 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
346 if (IsEqualIID(&IID_IOpcRelationshipEnumerator, iid) ||
347 IsEqualIID(&IID_IUnknown, iid))
349 *out = iface;
350 IOpcRelationshipEnumerator_AddRef(iface);
351 return S_OK;
354 *out = NULL;
355 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
356 return E_NOINTERFACE;
359 static ULONG WINAPI opc_rel_enum_AddRef(IOpcRelationshipEnumerator *iface)
361 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
362 ULONG refcount = InterlockedIncrement(&rel_enum->refcount);
364 TRACE("%p increasing refcount to %u.\n", iface, refcount);
366 return refcount;
369 static ULONG WINAPI opc_rel_enum_Release(IOpcRelationshipEnumerator *iface)
371 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
372 ULONG refcount = InterlockedDecrement(&rel_enum->refcount);
374 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
376 if (!refcount)
378 IOpcRelationshipSet_Release(&rel_enum->rel_set->IOpcRelationshipSet_iface);
379 heap_free(rel_enum);
382 return refcount;
385 static BOOL has_rel_collection_changed(const struct opc_rel_enum *rel_enum)
387 return !IsEqualGUID(&rel_enum->id, &rel_enum->rel_set->id);
390 static HRESULT WINAPI opc_rel_enum_MoveNext(IOpcRelationshipEnumerator *iface, BOOL *has_next)
392 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
394 TRACE("iface %p, has_next %p.\n", iface, has_next);
396 if (!has_next)
397 return E_POINTER;
399 if (has_rel_collection_changed(rel_enum))
400 return OPC_E_ENUM_COLLECTION_CHANGED;
402 if (rel_enum->rel_set->count && (rel_enum->pos == ~(size_t)0 || rel_enum->pos < rel_enum->rel_set->count))
403 rel_enum->pos++;
405 *has_next = rel_enum->pos < rel_enum->rel_set->count;
407 return S_OK;
410 static HRESULT WINAPI opc_rel_enum_MovePrevious(IOpcRelationshipEnumerator *iface, BOOL *has_previous)
412 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
414 TRACE("iface %p, has_previous %p.\n", iface, has_previous);
416 if (!has_previous)
417 return E_POINTER;
419 if (has_rel_collection_changed(rel_enum))
420 return OPC_E_ENUM_COLLECTION_CHANGED;
422 if (rel_enum->pos != ~(size_t)0)
423 rel_enum->pos--;
425 *has_previous = rel_enum->pos != ~(size_t)0;
427 return S_OK;
430 static HRESULT WINAPI opc_rel_enum_GetCurrent(IOpcRelationshipEnumerator *iface, IOpcRelationship **rel)
432 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
434 TRACE("iface %p, rel %p.\n", iface, rel);
436 if (!rel)
437 return E_POINTER;
439 *rel = NULL;
441 if (has_rel_collection_changed(rel_enum))
442 return OPC_E_ENUM_COLLECTION_CHANGED;
444 if (rel_enum->pos < rel_enum->rel_set->count)
446 *rel = &rel_enum->rel_set->relationships[rel_enum->pos]->IOpcRelationship_iface;
447 IOpcRelationship_AddRef(*rel);
450 return *rel ? S_OK : OPC_E_ENUM_INVALID_POSITION;
453 static HRESULT WINAPI opc_rel_enum_Clone(IOpcRelationshipEnumerator *iface, IOpcRelationshipEnumerator **out)
455 struct opc_rel_enum *rel_enum = impl_from_IOpcRelationshipEnumerator(iface);
457 TRACE("iface %p, out %p.\n", iface, out);
459 if (!out)
460 return E_POINTER;
462 if (has_rel_collection_changed(rel_enum))
464 *out = NULL;
465 return OPC_E_ENUM_COLLECTION_CHANGED;
468 return opc_rel_enum_create(rel_enum->rel_set, out);
471 static const IOpcRelationshipEnumeratorVtbl opc_rel_enum_vtbl =
473 opc_rel_enum_QueryInterface,
474 opc_rel_enum_AddRef,
475 opc_rel_enum_Release,
476 opc_rel_enum_MoveNext,
477 opc_rel_enum_MovePrevious,
478 opc_rel_enum_GetCurrent,
479 opc_rel_enum_Clone,
482 static HRESULT opc_rel_enum_create(struct opc_relationship_set *rel_set, IOpcRelationshipEnumerator **out)
484 struct opc_rel_enum *rel_enum;
486 if (!(rel_enum = heap_alloc_zero(sizeof(*rel_enum))))
487 return E_OUTOFMEMORY;
489 rel_enum->IOpcRelationshipEnumerator_iface.lpVtbl = &opc_rel_enum_vtbl;
490 rel_enum->refcount = 1;
491 rel_enum->rel_set = rel_set;
492 IOpcRelationshipSet_AddRef(&rel_set->IOpcRelationshipSet_iface);
493 rel_enum->pos = ~(size_t)0;
494 rel_enum->id = rel_set->id;
496 *out = &rel_enum->IOpcRelationshipEnumerator_iface;
497 TRACE("Created relationship enumerator %p.\n", *out);
498 return S_OK;
501 static HRESULT WINAPI opc_content_stream_QueryInterface(IStream *iface, REFIID iid, void **out)
503 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
505 if (IsEqualIID(iid, &IID_IStream) ||
506 IsEqualIID(iid, &IID_ISequentialStream) ||
507 IsEqualIID(iid, &IID_IUnknown))
509 *out = iface;
510 IStream_AddRef(iface);
511 return S_OK;
514 *out = NULL;
515 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
516 return E_NOINTERFACE;
519 static ULONG WINAPI opc_content_stream_AddRef(IStream *iface)
521 struct opc_content_stream *stream = impl_from_IStream(iface);
522 ULONG refcount = InterlockedIncrement(&stream->refcount);
524 TRACE("%p increasing refcount to %u.\n", iface, refcount);
526 return refcount;
529 static ULONG WINAPI opc_content_stream_Release(IStream *iface)
531 struct opc_content_stream *stream = impl_from_IStream(iface);
532 ULONG refcount = InterlockedDecrement(&stream->refcount);
534 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
536 if (!refcount)
538 opc_content_release(stream->content);
539 heap_free(stream);
542 return refcount;
545 static HRESULT WINAPI opc_content_stream_Read(IStream *iface, void *buff, ULONG size, ULONG *num_read)
547 struct opc_content_stream *stream = impl_from_IStream(iface);
548 DWORD read = 0;
550 TRACE("iface %p, buff %p, size %u, num_read %p.\n", iface, buff, size, num_read);
552 if (!num_read)
553 num_read = &read;
555 if (stream->content->size.QuadPart - stream->pos.QuadPart < size)
556 *num_read = stream->content->size.QuadPart - stream->pos.QuadPart;
557 else
558 *num_read = size;
560 if (*num_read)
561 memcpy(buff, stream->content->data + stream->pos.QuadPart, *num_read);
563 stream->pos.QuadPart += *num_read;
565 return S_OK;
568 static HRESULT WINAPI opc_content_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *num_written)
570 struct opc_content_stream *stream = impl_from_IStream(iface);
571 DWORD written = 0;
573 TRACE("iface %p, data %p, size %u, num_written %p.\n", iface, data, size, num_written);
575 if (!num_written)
576 num_written = &written;
578 *num_written = 0;
580 if (size > stream->content->size.QuadPart - stream->pos.QuadPart)
582 void *ptr = heap_realloc(stream->content->data, stream->pos.QuadPart + size);
583 if (!ptr)
584 return E_OUTOFMEMORY;
585 stream->content->data = ptr;
588 memcpy(stream->content->data + stream->pos.QuadPart, data, size);
589 stream->pos.QuadPart += size;
590 stream->content->size.QuadPart += size;
591 *num_written = size;
593 return S_OK;
596 static HRESULT WINAPI opc_content_stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos)
598 struct opc_content_stream *stream = impl_from_IStream(iface);
599 ULARGE_INTEGER pos;
601 TRACE("iface %p, move %s, origin %d, newpos %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, newpos);
603 switch (origin)
605 case STREAM_SEEK_SET:
606 pos.QuadPart = move.QuadPart;
607 break;
608 case STREAM_SEEK_CUR:
609 pos.QuadPart = stream->pos.QuadPart + move.QuadPart;
610 break;
611 case STREAM_SEEK_END:
612 pos.QuadPart = stream->content->size.QuadPart + move.QuadPart;
613 break;
614 default:
615 WARN("Unknown origin mode %d.\n", origin);
616 return E_INVALIDARG;
619 stream->pos = pos;
621 if (newpos)
622 *newpos = stream->pos;
624 return S_OK;
627 static HRESULT WINAPI opc_content_stream_SetSize(IStream *iface, ULARGE_INTEGER size)
629 FIXME("iface %p, size %s stub!\n", iface, wine_dbgstr_longlong(size.QuadPart));
631 return E_NOTIMPL;
634 static HRESULT WINAPI opc_content_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
635 ULARGE_INTEGER *num_read, ULARGE_INTEGER *written)
637 FIXME("iface %p, dest %p, size %s, num_read %p, written %p stub!\n", iface, dest,
638 wine_dbgstr_longlong(size.QuadPart), num_read, written);
640 return E_NOTIMPL;
643 static HRESULT WINAPI opc_content_stream_Commit(IStream *iface, DWORD flags)
645 FIXME("iface %p, flags %#x stub!\n", iface, flags);
647 return E_NOTIMPL;
650 static HRESULT WINAPI opc_content_stream_Revert(IStream *iface)
652 FIXME("iface %p stub!\n", iface);
654 return E_NOTIMPL;
657 static HRESULT WINAPI opc_content_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
658 ULARGE_INTEGER size, DWORD lock_type)
660 FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart),
661 wine_dbgstr_longlong(size.QuadPart), lock_type);
663 return E_NOTIMPL;
666 static HRESULT WINAPI opc_content_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size,
667 DWORD lock_type)
669 FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart),
670 wine_dbgstr_longlong(size.QuadPart), lock_type);
672 return E_NOTIMPL;
675 static HRESULT WINAPI opc_content_stream_Stat(IStream *iface, STATSTG *statstg, DWORD flag)
677 FIXME("iface %p, statstg %p, flag %d stub!\n", iface, statstg, flag);
679 return E_NOTIMPL;
682 static HRESULT WINAPI opc_content_stream_Clone(IStream *iface, IStream **result)
684 FIXME("iface %p, result %p stub!\n", iface, result);
686 return E_NOTIMPL;
689 static const IStreamVtbl opc_content_stream_vtbl =
691 opc_content_stream_QueryInterface,
692 opc_content_stream_AddRef,
693 opc_content_stream_Release,
694 opc_content_stream_Read,
695 opc_content_stream_Write,
696 opc_content_stream_Seek,
697 opc_content_stream_SetSize,
698 opc_content_stream_CopyTo,
699 opc_content_stream_Commit,
700 opc_content_stream_Revert,
701 opc_content_stream_LockRegion,
702 opc_content_stream_UnlockRegion,
703 opc_content_stream_Stat,
704 opc_content_stream_Clone,
707 static HRESULT opc_content_stream_create(struct opc_content *content, IStream **out)
709 struct opc_content_stream *stream;
711 if (!(stream = heap_alloc_zero(sizeof(*stream))))
712 return E_OUTOFMEMORY;
714 stream->IStream_iface.lpVtbl = &opc_content_stream_vtbl;
715 stream->refcount = 1;
716 stream->content = content;
717 InterlockedIncrement(&content->refcount);
719 *out = &stream->IStream_iface;
721 TRACE("Created content stream %p.\n", *out);
722 return S_OK;
725 static HRESULT opc_relationship_set_create(IOpcUri *source_uri, IOpcRelationshipSet **relationship_set);
727 static WCHAR *opc_strdupW(const WCHAR *str)
729 WCHAR *ret = NULL;
731 if (str)
733 size_t size;
735 size = (strlenW(str) + 1) * sizeof(WCHAR);
736 ret = CoTaskMemAlloc(size);
737 if (ret)
738 memcpy(ret, str, size);
741 return ret;
744 static HRESULT WINAPI opc_part_QueryInterface(IOpcPart *iface, REFIID iid, void **out)
746 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
748 if (IsEqualIID(iid, &IID_IOpcPart) ||
749 IsEqualIID(iid, &IID_IUnknown))
751 *out = iface;
752 IOpcPart_AddRef(iface);
753 return S_OK;
756 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
757 return E_NOINTERFACE;
760 static ULONG WINAPI opc_part_AddRef(IOpcPart *iface)
762 struct opc_part *part = impl_from_IOpcPart(iface);
763 ULONG refcount = InterlockedIncrement(&part->refcount);
765 TRACE("%p increasing refcount to %u.\n", iface, refcount);
767 return refcount;
770 static ULONG WINAPI opc_part_Release(IOpcPart *iface)
772 struct opc_part *part = impl_from_IOpcPart(iface);
773 ULONG refcount = InterlockedDecrement(&part->refcount);
775 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
777 if (!refcount)
779 if (part->relationship_set)
780 IOpcRelationshipSet_Release(part->relationship_set);
781 IOpcPartUri_Release(part->name);
782 CoTaskMemFree(part->content_type);
783 opc_content_release(part->content);
784 heap_free(part);
787 return refcount;
790 static HRESULT WINAPI opc_part_GetRelationshipSet(IOpcPart *iface, IOpcRelationshipSet **relationship_set)
792 struct opc_part *part = impl_from_IOpcPart(iface);
793 HRESULT hr;
795 TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
797 if (!part->relationship_set && FAILED(hr = opc_relationship_set_create((IOpcUri *)part->name, &part->relationship_set)))
798 return hr;
800 *relationship_set = part->relationship_set;
801 IOpcRelationshipSet_AddRef(*relationship_set);
803 return S_OK;
806 static HRESULT WINAPI opc_part_GetContentStream(IOpcPart *iface, IStream **stream)
808 struct opc_part *part = impl_from_IOpcPart(iface);
810 TRACE("iface %p, stream %p.\n", iface, stream);
812 if (!stream)
813 return E_POINTER;
815 return opc_content_stream_create(part->content, stream);
818 static HRESULT WINAPI opc_part_GetName(IOpcPart *iface, IOpcPartUri **name)
820 struct opc_part *part = impl_from_IOpcPart(iface);
822 TRACE("iface %p, name %p.\n", iface, name);
824 *name = part->name;
825 IOpcPartUri_AddRef(*name);
827 return S_OK;
830 static HRESULT WINAPI opc_part_GetContentType(IOpcPart *iface, LPWSTR *type)
832 struct opc_part *part = impl_from_IOpcPart(iface);
834 TRACE("iface %p, type %p.\n", iface, type);
836 *type = opc_strdupW(part->content_type);
837 return *type ? S_OK : E_OUTOFMEMORY;
840 static HRESULT WINAPI opc_part_GetCompressionOptions(IOpcPart *iface, OPC_COMPRESSION_OPTIONS *options)
842 struct opc_part *part = impl_from_IOpcPart(iface);
844 TRACE("iface %p, options %p.\n", iface, options);
846 *options = part->compression_options;
847 return S_OK;
850 static const IOpcPartVtbl opc_part_vtbl =
852 opc_part_QueryInterface,
853 opc_part_AddRef,
854 opc_part_Release,
855 opc_part_GetRelationshipSet,
856 opc_part_GetContentStream,
857 opc_part_GetName,
858 opc_part_GetContentType,
859 opc_part_GetCompressionOptions,
862 static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, const WCHAR *content_type,
863 DWORD compression_options, IOpcPart **out)
865 struct opc_part *part;
867 if (!opc_array_reserve((void **)&set->parts, &set->size, set->count + 1, sizeof(*set->parts)))
868 return E_OUTOFMEMORY;
870 if (!(part = heap_alloc_zero(sizeof(*part))))
871 return E_OUTOFMEMORY;
873 part->IOpcPart_iface.lpVtbl = &opc_part_vtbl;
874 part->refcount = 1;
875 part->name = name;
876 IOpcPartUri_AddRef(name);
877 part->compression_options = compression_options;
878 if (!(part->content_type = opc_strdupW(content_type)))
880 IOpcPart_Release(&part->IOpcPart_iface);
881 return E_OUTOFMEMORY;
884 part->content = heap_alloc_zero(sizeof(*part->content));
885 if (!part->content)
887 IOpcPart_Release(&part->IOpcPart_iface);
888 return E_OUTOFMEMORY;
890 part->content->refcount = 1;
892 set->parts[set->count++] = part;
893 IOpcPart_AddRef(&part->IOpcPart_iface);
894 CoCreateGuid(&set->id);
896 *out = &part->IOpcPart_iface;
897 TRACE("Created part %p.\n", *out);
898 return S_OK;
901 static struct opc_part *opc_part_set_get_part(const struct opc_part_set *part_set, IOpcPartUri *name)
903 BOOL is_equal;
904 size_t i;
906 for (i = 0; i < part_set->count; ++i)
908 is_equal = FALSE;
909 if (IOpcPartUri_IsEqual(part_set->parts[i]->name, (IUri *)name, &is_equal) == S_OK && is_equal)
910 return part_set->parts[i];
913 return NULL;
916 static HRESULT WINAPI opc_part_set_QueryInterface(IOpcPartSet *iface, REFIID iid, void **out)
918 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
920 if (IsEqualIID(iid, &IID_IOpcPartSet) ||
921 IsEqualIID(iid, &IID_IUnknown))
923 *out = iface;
924 IOpcPartSet_AddRef(iface);
925 return S_OK;
928 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
929 return E_NOINTERFACE;
932 static ULONG WINAPI opc_part_set_AddRef(IOpcPartSet *iface)
934 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
935 ULONG refcount = InterlockedIncrement(&part_set->refcount);
937 TRACE("%p increasing refcount to %u.\n", iface, refcount);
939 return refcount;
942 static ULONG WINAPI opc_part_set_Release(IOpcPartSet *iface)
944 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
945 ULONG refcount = InterlockedDecrement(&part_set->refcount);
947 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
949 if (!refcount)
951 size_t i;
953 for (i = 0; i < part_set->count; ++i)
954 IOpcPart_Release(&part_set->parts[i]->IOpcPart_iface);
955 heap_free(part_set->parts);
956 heap_free(part_set);
959 return refcount;
962 static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name, IOpcPart **out)
964 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
965 struct opc_part *part;
967 TRACE("iface %p, name %p, out %p.\n", iface, name, out);
969 if (!out)
970 return E_POINTER;
972 *out = NULL;
974 if (!name)
975 return E_POINTER;
977 if ((part = opc_part_set_get_part(part_set, name)))
979 *out = &part->IOpcPart_iface;
980 IOpcPart_AddRef(*out);
983 return *out ? S_OK : OPC_E_NO_SUCH_PART;
986 static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *name, LPCWSTR content_type,
987 OPC_COMPRESSION_OPTIONS compression_options, IOpcPart **part)
989 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
991 TRACE("iface %p, name %p, content_type %s, compression_options %#x, part %p.\n", iface, name,
992 debugstr_w(content_type), compression_options, part);
994 if (!part)
995 return E_POINTER;
997 *part = NULL;
999 if (!name)
1000 return E_POINTER;
1002 if (opc_part_set_get_part(part_set, name))
1003 return OPC_E_DUPLICATE_PART;
1005 return opc_part_create(part_set, name, content_type, compression_options, part);
1008 static HRESULT WINAPI opc_part_set_DeletePart(IOpcPartSet *iface, IOpcPartUri *name)
1010 FIXME("iface %p, name %p stub!\n", iface, name);
1012 return E_NOTIMPL;
1015 static HRESULT WINAPI opc_part_set_PartExists(IOpcPartSet *iface, IOpcPartUri *name, BOOL *exists)
1017 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
1019 TRACE("iface %p, name %p, exists %p.\n", iface, name, exists);
1021 if (!name || !exists)
1022 return E_POINTER;
1024 *exists = opc_part_set_get_part(part_set, name) != NULL;
1026 return S_OK;
1029 static HRESULT WINAPI opc_part_set_GetEnumerator(IOpcPartSet *iface, IOpcPartEnumerator **enumerator)
1031 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
1033 TRACE("iface %p, enumerator %p.\n", iface, enumerator);
1035 if (!enumerator)
1036 return E_POINTER;
1038 return opc_part_enum_create(part_set, enumerator);
1041 static const IOpcPartSetVtbl opc_part_set_vtbl =
1043 opc_part_set_QueryInterface,
1044 opc_part_set_AddRef,
1045 opc_part_set_Release,
1046 opc_part_set_GetPart,
1047 opc_part_set_CreatePart,
1048 opc_part_set_DeletePart,
1049 opc_part_set_PartExists,
1050 opc_part_set_GetEnumerator,
1053 static HRESULT WINAPI opc_relationship_QueryInterface(IOpcRelationship *iface, REFIID iid, void **out)
1055 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1057 if (IsEqualIID(iid, &IID_IOpcRelationship) ||
1058 IsEqualIID(iid, &IID_IUnknown))
1060 *out = iface;
1061 IOpcRelationship_AddRef(iface);
1062 return S_OK;
1065 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1066 return E_NOINTERFACE;
1069 static ULONG WINAPI opc_relationship_AddRef(IOpcRelationship *iface)
1071 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1072 ULONG refcount = InterlockedIncrement(&relationship->refcount);
1074 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1076 return refcount;
1079 static ULONG WINAPI opc_relationship_Release(IOpcRelationship *iface)
1081 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1082 ULONG refcount = InterlockedDecrement(&relationship->refcount);
1084 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1086 if (!refcount)
1088 CoTaskMemFree(relationship->id);
1089 CoTaskMemFree(relationship->type);
1090 IOpcUri_Release(relationship->source_uri);
1091 IUri_Release(relationship->target);
1092 heap_free(relationship);
1095 return refcount;
1098 static HRESULT WINAPI opc_relationship_GetId(IOpcRelationship *iface, WCHAR **id)
1100 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1102 TRACE("iface %p, id %p.\n", iface, id);
1104 *id = opc_strdupW(relationship->id);
1105 return *id ? S_OK : E_OUTOFMEMORY;
1108 static HRESULT WINAPI opc_relationship_GetRelationshipType(IOpcRelationship *iface, WCHAR **type)
1110 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1112 TRACE("iface %p, type %p.\n", iface, type);
1114 *type = opc_strdupW(relationship->type);
1115 return *type ? S_OK : E_OUTOFMEMORY;
1118 static HRESULT WINAPI opc_relationship_GetSourceUri(IOpcRelationship *iface, IOpcUri **uri)
1120 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1122 TRACE("iface %p, uri %p.\n", iface, uri);
1124 *uri = relationship->source_uri;
1125 IOpcUri_AddRef(*uri);
1127 return S_OK;
1130 static HRESULT WINAPI opc_relationship_GetTargetUri(IOpcRelationship *iface, IUri **target)
1132 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1134 TRACE("iface %p, target %p.\n", iface, target);
1136 *target = relationship->target;
1137 IUri_AddRef(*target);
1139 return S_OK;
1142 static HRESULT WINAPI opc_relationship_GetTargetMode(IOpcRelationship *iface, OPC_URI_TARGET_MODE *target_mode)
1144 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1146 TRACE("iface %p, target_mode %p.\n", iface, target_mode);
1148 *target_mode = relationship->target_mode;
1150 return S_OK;
1153 static const IOpcRelationshipVtbl opc_relationship_vtbl =
1155 opc_relationship_QueryInterface,
1156 opc_relationship_AddRef,
1157 opc_relationship_Release,
1158 opc_relationship_GetId,
1159 opc_relationship_GetRelationshipType,
1160 opc_relationship_GetSourceUri,
1161 opc_relationship_GetTargetUri,
1162 opc_relationship_GetTargetMode,
1165 static struct opc_relationship *opc_relationshipset_get_rel(struct opc_relationship_set *relationship_set,
1166 const WCHAR *id)
1168 size_t i;
1170 for (i = 0; i < relationship_set->count; i++)
1172 if (!strcmpW(id, relationship_set->relationships[i]->id))
1173 return relationship_set->relationships[i];
1176 return NULL;
1179 static HRESULT opc_relationship_create(struct opc_relationship_set *set, const WCHAR *id, const WCHAR *type,
1180 IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **out)
1182 struct opc_relationship *relationship;
1184 if (!opc_array_reserve((void **)&set->relationships, &set->size, set->count + 1, sizeof(*set->relationships)))
1185 return E_OUTOFMEMORY;
1187 if (!(relationship = heap_alloc_zero(sizeof(*relationship))))
1188 return E_OUTOFMEMORY;
1190 relationship->IOpcRelationship_iface.lpVtbl = &opc_relationship_vtbl;
1191 relationship->refcount = 1;
1193 relationship->target = target_uri;
1194 IUri_AddRef(relationship->target);
1195 relationship->source_uri = set->source_uri;
1196 IOpcUri_AddRef(relationship->source_uri);
1198 if (id)
1199 relationship->id = opc_strdupW(id);
1200 else
1202 relationship->id = CoTaskMemAlloc(10 * sizeof(WCHAR));
1203 if (relationship->id)
1205 static const WCHAR fmtW[] = {'R','%','0','8','X',0};
1206 DWORD generated;
1208 /* FIXME: test that generated id is unique */
1209 RtlGenRandom(&generated, sizeof(generated));
1210 sprintfW(relationship->id, fmtW, generated);
1212 if (opc_relationshipset_get_rel(set, relationship->id))
1214 WARN("Newly generated id %s already exists.\n", debugstr_w(relationship->id));
1215 IOpcRelationship_Release(&relationship->IOpcRelationship_iface);
1216 return E_FAIL;
1221 relationship->type = opc_strdupW(type);
1222 if (!relationship->id || !relationship->type)
1224 IOpcRelationship_Release(&relationship->IOpcRelationship_iface);
1225 return E_OUTOFMEMORY;
1228 set->relationships[set->count++] = relationship;
1229 IOpcRelationship_AddRef(&relationship->IOpcRelationship_iface);
1230 CoCreateGuid(&set->id);
1232 *out = &relationship->IOpcRelationship_iface;
1233 TRACE("Created relationship %p.\n", *out);
1234 return S_OK;
1237 static HRESULT WINAPI opc_relationship_set_QueryInterface(IOpcRelationshipSet *iface, REFIID iid, void **out)
1239 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1241 if (IsEqualIID(iid, &IID_IOpcRelationshipSet) ||
1242 IsEqualIID(iid, &IID_IUnknown))
1244 *out = iface;
1245 IOpcRelationshipSet_AddRef(iface);
1246 return S_OK;
1249 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1250 return E_NOINTERFACE;
1253 static ULONG WINAPI opc_relationship_set_AddRef(IOpcRelationshipSet *iface)
1255 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1256 ULONG refcount = InterlockedIncrement(&relationship_set->refcount);
1258 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1260 return refcount;
1263 static ULONG WINAPI opc_relationship_set_Release(IOpcRelationshipSet *iface)
1265 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1266 ULONG refcount = InterlockedDecrement(&relationship_set->refcount);
1268 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1270 if (!refcount)
1272 size_t i;
1274 for (i = 0; i < relationship_set->count; ++i)
1275 IOpcRelationship_Release(&relationship_set->relationships[i]->IOpcRelationship_iface);
1276 IOpcUri_Release(relationship_set->source_uri);
1277 heap_free(relationship_set->relationships);
1278 heap_free(relationship_set);
1281 return refcount;
1284 static HRESULT WINAPI opc_relationship_set_GetRelationship(IOpcRelationshipSet *iface, const WCHAR *id,
1285 IOpcRelationship **relationship)
1287 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1288 struct opc_relationship *ret;
1290 TRACE("iface %p, id %s, relationship %p.\n", iface, debugstr_w(id), relationship);
1292 if (!relationship)
1293 return E_POINTER;
1295 *relationship = NULL;
1297 if (!id)
1298 return E_POINTER;
1300 if ((ret = opc_relationshipset_get_rel(relationship_set, id)))
1302 *relationship = &ret->IOpcRelationship_iface;
1303 IOpcRelationship_AddRef(*relationship);
1306 return *relationship ? S_OK : OPC_E_NO_SUCH_RELATIONSHIP;
1309 static HRESULT WINAPI opc_relationship_set_CreateRelationship(IOpcRelationshipSet *iface, const WCHAR *id,
1310 const WCHAR *type, IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **relationship)
1312 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1313 DWORD length;
1315 TRACE("iface %p, id %s, type %s, target_uri %p, target_mode %d, relationship %p.\n", iface, debugstr_w(id),
1316 debugstr_w(type), target_uri, target_mode, relationship);
1318 if (!relationship)
1319 return E_POINTER;
1321 *relationship = NULL;
1323 if (!type || !target_uri)
1324 return E_POINTER;
1326 if (id && opc_relationshipset_get_rel(relationship_set, id))
1327 return OPC_E_DUPLICATE_RELATIONSHIP;
1329 if (IUri_GetPropertyLength(target_uri, Uri_PROPERTY_SCHEME_NAME, &length, 0) == S_OK && length != 0
1330 && target_mode == OPC_URI_TARGET_MODE_INTERNAL)
1331 return OPC_E_INVALID_RELATIONSHIP_TARGET;
1333 return opc_relationship_create(relationship_set, id, type, target_uri, target_mode, relationship);
1336 static HRESULT WINAPI opc_relationship_set_DeleteRelationship(IOpcRelationshipSet *iface, const WCHAR *id)
1338 FIXME("iface %p, id %s stub!\n", iface, debugstr_w(id));
1340 return E_NOTIMPL;
1343 static HRESULT WINAPI opc_relationship_set_RelationshipExists(IOpcRelationshipSet *iface, const WCHAR *id, BOOL *exists)
1345 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1347 TRACE("iface %p, id %s, exists %p.\n", iface, debugstr_w(id), exists);
1349 if (!id || !exists)
1350 return E_POINTER;
1352 *exists = opc_relationshipset_get_rel(relationship_set, id) != NULL;
1354 return S_OK;
1357 static HRESULT WINAPI opc_relationship_set_GetEnumerator(IOpcRelationshipSet *iface,
1358 IOpcRelationshipEnumerator **enumerator)
1360 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1362 TRACE("iface %p, enumerator %p.\n", iface, enumerator);
1364 if (!enumerator)
1365 return E_POINTER;
1367 return opc_rel_enum_create(relationship_set, enumerator);
1370 static HRESULT WINAPI opc_relationship_set_GetEnumeratorForType(IOpcRelationshipSet *iface, const WCHAR *type,
1371 IOpcRelationshipEnumerator **enumerator)
1373 FIXME("iface %p, type %s, enumerator %p stub!\n", iface, debugstr_w(type), enumerator);
1375 return E_NOTIMPL;
1378 static HRESULT WINAPI opc_relationship_set_GetRelationshipsContentStream(IOpcRelationshipSet *iface, IStream **stream)
1380 FIXME("iface %p, stream %p stub!\n", iface, stream);
1382 return E_NOTIMPL;
1385 static const IOpcRelationshipSetVtbl opc_relationship_set_vtbl =
1387 opc_relationship_set_QueryInterface,
1388 opc_relationship_set_AddRef,
1389 opc_relationship_set_Release,
1390 opc_relationship_set_GetRelationship,
1391 opc_relationship_set_CreateRelationship,
1392 opc_relationship_set_DeleteRelationship,
1393 opc_relationship_set_RelationshipExists,
1394 opc_relationship_set_GetEnumerator,
1395 opc_relationship_set_GetEnumeratorForType,
1396 opc_relationship_set_GetRelationshipsContentStream,
1399 static HRESULT opc_relationship_set_create(IOpcUri *source_uri, IOpcRelationshipSet **out)
1401 struct opc_relationship_set *relationship_set;
1403 if (!(relationship_set = heap_alloc_zero(sizeof(*relationship_set))))
1404 return E_OUTOFMEMORY;
1406 relationship_set->IOpcRelationshipSet_iface.lpVtbl = &opc_relationship_set_vtbl;
1407 relationship_set->refcount = 1;
1408 relationship_set->source_uri = source_uri;
1409 IOpcUri_AddRef(relationship_set->source_uri);
1411 *out = &relationship_set->IOpcRelationshipSet_iface;
1412 TRACE("Created relationship set %p.\n", *out);
1413 return S_OK;
1416 static HRESULT WINAPI opc_package_QueryInterface(IOpcPackage *iface, REFIID iid, void **out)
1418 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1420 if (IsEqualIID(iid, &IID_IOpcPackage) ||
1421 IsEqualIID(iid, &IID_IUnknown))
1423 *out = iface;
1424 IOpcPackage_AddRef(iface);
1425 return S_OK;
1428 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1429 return E_NOINTERFACE;
1432 static ULONG WINAPI opc_package_AddRef(IOpcPackage *iface)
1434 struct opc_package *package = impl_from_IOpcPackage(iface);
1435 ULONG refcount = InterlockedIncrement(&package->refcount);
1437 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1439 return refcount;
1442 static ULONG WINAPI opc_package_Release(IOpcPackage *iface)
1444 struct opc_package *package = impl_from_IOpcPackage(iface);
1445 ULONG refcount = InterlockedDecrement(&package->refcount);
1447 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1449 if (!refcount)
1451 if (package->part_set)
1452 IOpcPartSet_Release(package->part_set);
1453 if (package->relationship_set)
1454 IOpcRelationshipSet_Release(package->relationship_set);
1455 if (package->source_uri)
1456 IOpcUri_Release(package->source_uri);
1457 heap_free(package);
1460 return refcount;
1463 static HRESULT WINAPI opc_package_GetPartSet(IOpcPackage *iface, IOpcPartSet **part_set)
1465 struct opc_package *package = impl_from_IOpcPackage(iface);
1467 TRACE("iface %p, part_set %p.\n", iface, part_set);
1469 if (!package->part_set)
1471 struct opc_part_set *part_set = heap_alloc_zero(sizeof(*part_set));
1472 if (!part_set)
1473 return E_OUTOFMEMORY;
1475 part_set->IOpcPartSet_iface.lpVtbl = &opc_part_set_vtbl;
1476 part_set->refcount = 1;
1478 package->part_set = &part_set->IOpcPartSet_iface;
1481 *part_set = package->part_set;
1482 IOpcPartSet_AddRef(*part_set);
1484 return S_OK;
1487 static HRESULT WINAPI opc_package_GetRelationshipSet(IOpcPackage *iface, IOpcRelationshipSet **relationship_set)
1489 struct opc_package *package = impl_from_IOpcPackage(iface);
1490 HRESULT hr;
1492 TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
1494 if (!package->relationship_set)
1496 if (FAILED(hr = opc_relationship_set_create(package->source_uri, &package->relationship_set)))
1497 return hr;
1500 *relationship_set = package->relationship_set;
1501 IOpcRelationshipSet_AddRef(*relationship_set);
1503 return S_OK;
1506 static const IOpcPackageVtbl opc_package_vtbl =
1508 opc_package_QueryInterface,
1509 opc_package_AddRef,
1510 opc_package_Release,
1511 opc_package_GetPartSet,
1512 opc_package_GetRelationshipSet,
1515 HRESULT opc_package_create(IOpcFactory *factory, IOpcPackage **out)
1517 struct opc_package *package;
1518 HRESULT hr;
1520 if (!(package = heap_alloc_zero(sizeof(*package))))
1521 return E_OUTOFMEMORY;
1523 package->IOpcPackage_iface.lpVtbl = &opc_package_vtbl;
1524 package->refcount = 1;
1526 if (FAILED(hr = IOpcFactory_CreatePackageRootUri(factory, &package->source_uri)))
1528 heap_free(package);
1529 return hr;
1532 *out = &package->IOpcPackage_iface;
1533 TRACE("Created package %p.\n", *out);
1534 return S_OK;
1537 struct content_types
1539 struct list types;
1540 BOOL has_rels_part;
1543 enum content_type_element
1545 CONTENT_TYPE_DEFAULT,
1546 CONTENT_TYPE_OVERRIDE,
1549 struct content_type
1551 struct list entry;
1552 enum content_type_element element;
1553 union
1555 struct default_type
1557 WCHAR *ext;
1558 WCHAR *type;
1559 } def;
1560 struct override_type
1562 IOpcPart *part;
1563 } override;
1564 } u;
1567 static HRESULT opc_package_add_override_content_type(struct content_types *types, IOpcPart *part)
1569 struct content_type *type;
1571 if (!(type = heap_alloc(sizeof(*type))))
1572 return E_OUTOFMEMORY;
1574 type->element = CONTENT_TYPE_OVERRIDE;
1575 type->u.override.part = part;
1576 IOpcPart_AddRef(part);
1578 list_add_tail(&types->types, &type->entry);
1580 return S_OK;
1583 static HRESULT opc_package_add_default_content_type(struct content_types *types,
1584 const WCHAR *ext, const WCHAR *content_type)
1586 struct content_type *type;
1588 if (!(type = heap_alloc(sizeof(*type))))
1589 return E_OUTOFMEMORY;
1591 type->element = CONTENT_TYPE_DEFAULT;
1592 type->u.def.ext = opc_strdupW(ext);
1593 type->u.def.type = opc_strdupW(content_type);
1594 if (!type->u.def.ext || !type->u.def.type)
1596 CoTaskMemFree(type->u.def.ext);
1597 CoTaskMemFree(type->u.def.type);
1598 heap_free(type);
1599 return E_OUTOFMEMORY;
1602 list_add_tail(&types->types, &type->entry);
1604 return S_OK;
1607 static HRESULT opc_package_add_content_type(struct content_types *types, IOpcPart *part)
1609 struct content_type *cur;
1610 BSTR ext, content_type;
1611 BOOL added = FALSE;
1612 IOpcPartUri *name;
1613 HRESULT hr;
1615 if (FAILED(hr = IOpcPart_GetName(part, &name)))
1616 return hr;
1618 hr = IOpcPartUri_GetExtension(name, &ext);
1619 IOpcPartUri_Release(name);
1620 if (hr == S_FALSE)
1622 hr = opc_package_add_override_content_type(types, part);
1623 SysFreeString(ext);
1624 return hr;
1627 if (FAILED(hr))
1628 return hr;
1630 if (FAILED(hr = IOpcPart_GetContentType(part, &content_type)))
1631 return hr;
1633 LIST_FOR_EACH_ENTRY(cur, &types->types, struct content_type, entry)
1635 if (cur->element == CONTENT_TYPE_OVERRIDE)
1636 continue;
1638 if (!strcmpiW(cur->u.def.ext, ext))
1640 added = TRUE;
1642 if (!strcmpW(cur->u.def.type, content_type))
1643 break;
1645 hr = opc_package_add_override_content_type(types, part);
1646 break;
1650 if (!added)
1651 hr = opc_package_add_default_content_type(types, ext, content_type);
1653 SysFreeString(ext);
1654 SysFreeString(content_type);
1656 return hr;
1659 static BOOL opc_package_has_rels_part(IOpcRelationshipSet *rel_set)
1661 IOpcRelationshipEnumerator *enumerator;
1662 BOOL has_next;
1663 HRESULT hr;
1665 if (FAILED(hr = IOpcRelationshipSet_GetEnumerator(rel_set, &enumerator)))
1666 return FALSE;
1668 has_next = FALSE;
1669 IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1670 IOpcRelationshipEnumerator_Release(enumerator);
1672 return has_next;
1675 static HRESULT opc_package_collect_content_types(IOpcPackage *package, struct content_types *types)
1677 IOpcPartEnumerator *enumerator;
1678 IOpcRelationshipSet *rel_set;
1679 IOpcPartSet *parts;
1680 BOOL has_next;
1681 HRESULT hr;
1683 if (FAILED(hr = IOpcPackage_GetPartSet(package, &parts)))
1684 return hr;
1686 hr = IOpcPackage_GetRelationshipSet(package, &rel_set);
1687 if (SUCCEEDED(hr))
1689 types->has_rels_part |= opc_package_has_rels_part(rel_set);
1690 IOpcRelationshipSet_Release(rel_set);
1693 hr = IOpcPartSet_GetEnumerator(parts, &enumerator);
1694 IOpcPartSet_Release(parts);
1695 if (FAILED(hr))
1696 return hr;
1698 if (FAILED(hr = IOpcPartEnumerator_MoveNext(enumerator, &has_next)) || !has_next)
1700 IOpcPartEnumerator_Release(enumerator);
1701 return hr;
1704 while (has_next)
1706 IOpcPart *part;
1708 if (FAILED(hr = IOpcPartEnumerator_GetCurrent(enumerator, &part)))
1709 break;
1711 if (!types->has_rels_part)
1713 hr = IOpcPart_GetRelationshipSet(part, &rel_set);
1714 if (SUCCEEDED(hr))
1716 types->has_rels_part |= opc_package_has_rels_part(rel_set);
1717 IOpcRelationshipSet_Release(rel_set);
1721 hr = opc_package_add_content_type(types, part);
1722 IOpcPart_Release(part);
1723 if (FAILED(hr))
1724 break;
1726 if (FAILED(hr = IOpcPartEnumerator_MoveNext(enumerator, &has_next)))
1727 break;
1730 IOpcPartEnumerator_Release(enumerator);
1732 return hr;
1735 static HRESULT opc_package_write_default_type(const WCHAR *ext, const WCHAR *type, IXmlWriter *writer)
1737 static const WCHAR contenttypeW[] = {'C','o','n','t','e','n','t','T','y','p','e',0};
1738 static const WCHAR extensionW[] = {'E','x','t','e','n','s','i','o','n',0};
1739 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
1740 HRESULT hr;
1742 hr = IXmlWriter_WriteStartElement(writer, NULL, defaultW, NULL);
1743 if (SUCCEEDED(hr))
1744 hr = IXmlWriter_WriteAttributeString(writer, NULL, extensionW, NULL, ext);
1745 if (SUCCEEDED(hr))
1746 hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, type);
1747 return hr;
1750 static HRESULT opc_package_write_contenttypes(IOpcPackage *package, struct zip_archive *archive, IXmlWriter *writer)
1752 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','/',
1753 'p','a','c','k','a','g','e','/','2','0','0','6','/','c','o','n','t','e','n','t','-','t','y','p','e','s',0};
1754 static const WCHAR relstypeW[] = {'a','p','p','l','i','c','a','t','i','o','n','/','v','n','d','.','o','p','e','n','x','m','l','f','o','r','m','a','t','s','-',
1755 'p','a','c','k','a','g','e','.','r','e','l','a','t','i','o','n','s','h','i','p','s','+','x','m','l',0};
1756 static const WCHAR contenttypesW[] = {'[','C','o','n','t','e','n','t','_','T','y','p','e','s',']','.','x','m','l',0};
1757 static const WCHAR contenttypeW[] = {'C','o','n','t','e','n','t','T','y','p','e',0};
1758 static const WCHAR overrideW[] = {'O','v','e','r','r','i','d','e',0};
1759 static const WCHAR partnameW[] = {'P','a','r','t','N','a','m','e',0};
1760 static const WCHAR typesW[] = {'T','y','p','e','s',0};
1761 static const WCHAR relsW[] = {'r','e','l','s',0};
1762 struct content_type *content_type, *content_type2;
1763 struct content_types types;
1764 IStream *content = NULL;
1765 HRESULT hr;
1767 list_init(&types.types);
1768 types.has_rels_part = FALSE;
1770 hr = CreateStreamOnHGlobal(NULL, TRUE, &content);
1771 if (SUCCEEDED(hr))
1772 hr = opc_package_collect_content_types(package, &types);
1773 if (SUCCEEDED(hr))
1774 hr = IXmlWriter_SetOutput(writer, (IUnknown *)content);
1775 if (SUCCEEDED(hr))
1776 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1777 if (SUCCEEDED(hr))
1778 hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW);
1780 if (SUCCEEDED(hr) && types.has_rels_part)
1782 hr = opc_package_write_default_type(relsW, relstypeW, writer);
1783 if (SUCCEEDED(hr))
1784 hr = IXmlWriter_WriteEndElement(writer);
1787 LIST_FOR_EACH_ENTRY_SAFE(content_type, content_type2, &types.types, struct content_type, entry)
1789 if (content_type->element == CONTENT_TYPE_DEFAULT)
1791 hr = opc_package_write_default_type(content_type->u.def.ext + 1, content_type->u.def.type, writer);
1793 CoTaskMemFree(content_type->u.def.ext);
1794 CoTaskMemFree(content_type->u.def.type);
1796 else
1798 IOpcPartUri *uri = NULL;
1799 WCHAR *type = NULL;
1800 BSTR name = NULL;
1802 if (SUCCEEDED(hr))
1803 hr = IXmlWriter_WriteStartElement(writer, NULL, overrideW, NULL);
1804 if (SUCCEEDED(hr))
1805 hr = IOpcPart_GetName(content_type->u.override.part, &uri);
1806 if (SUCCEEDED(hr))
1807 hr = IOpcPartUri_GetRawUri(uri, &name);
1808 if (SUCCEEDED(hr))
1809 hr = IXmlWriter_WriteAttributeString(writer, NULL, partnameW, NULL, name);
1810 if (SUCCEEDED(hr))
1811 hr = IOpcPart_GetContentType(content_type->u.override.part, &type);
1812 if (SUCCEEDED(hr))
1813 hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, type);
1815 if (uri)
1816 IOpcPartUri_Release(uri);
1817 SysFreeString(name);
1818 CoTaskMemFree(type);
1820 IOpcPart_Release(content_type->u.override.part);
1822 if (SUCCEEDED(hr))
1823 hr = IXmlWriter_WriteEndElement(writer);
1825 list_remove(&content_type->entry);
1826 heap_free(content_type);
1829 if (SUCCEEDED(hr))
1830 hr = IXmlWriter_WriteEndDocument(writer);
1831 if (SUCCEEDED(hr))
1832 hr = IXmlWriter_Flush(writer);
1834 if (SUCCEEDED(hr))
1835 hr = compress_add_file(archive, contenttypesW, content, OPC_COMPRESSION_NORMAL);
1837 if (content)
1838 IStream_Release(content);
1840 return hr;
1843 static HRESULT opc_package_write_rel(IOpcRelationship *rel, IXmlWriter *writer)
1845 static const WCHAR relationshipW[] = {'R','e','l','a','t','i','o','n','s','h','i','p',0};
1846 static const WCHAR targetW[] = {'T','a','r','g','e','t',0};
1847 static const WCHAR typeW[] = {'T','y','p','e',0};
1848 static const WCHAR idW[] = {'I','d',0};
1849 BSTR target_uri;
1850 HRESULT hr;
1851 WCHAR *str;
1852 IUri *uri;
1854 if (FAILED(hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipW, NULL)))
1855 return hr;
1857 if (FAILED(hr = IOpcRelationship_GetTargetUri(rel, &uri)))
1858 return hr;
1860 IUri_GetRawUri(uri, &target_uri);
1861 IUri_Release(uri);
1863 hr = IXmlWriter_WriteAttributeString(writer, NULL, targetW, NULL, target_uri);
1864 SysFreeString(target_uri);
1865 if (FAILED(hr))
1866 return hr;
1868 if (FAILED(hr = IOpcRelationship_GetId(rel, &str)))
1869 return hr;
1871 hr = IXmlWriter_WriteAttributeString(writer, NULL, idW, NULL, str);
1872 CoTaskMemFree(str);
1873 if (FAILED(hr))
1874 return hr;
1876 if (FAILED(hr = IOpcRelationship_GetRelationshipType(rel, &str)))
1877 return hr;
1879 hr = IXmlWriter_WriteAttributeString(writer, NULL, typeW, NULL, str);
1880 CoTaskMemFree(str);
1881 if (FAILED(hr))
1882 return hr;
1884 return IXmlWriter_WriteEndElement(writer);
1887 static HRESULT opc_package_write_rels(struct zip_archive *archive, IOpcRelationshipSet *rels,
1888 IOpcUri *uri, IXmlWriter *writer)
1890 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','/',
1891 'p','a','c','k','a','g','e','/','2','0','0','6','/','r','e','l','a','t','i','o','n','s','h','i','p','s',0};
1892 static const WCHAR relationshipsW[] = {'R','e','l','a','t','i','o','n','s','h','i','p','s',0};
1893 IOpcRelationshipEnumerator *enumerator;
1894 IOpcPartUri *rels_uri;
1895 BSTR rels_part_uri;
1896 IStream *content;
1897 BOOL has_next;
1898 HRESULT hr;
1900 if (FAILED(hr = IOpcRelationshipSet_GetEnumerator(rels, &enumerator)))
1901 return hr;
1903 hr = IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1904 if (!has_next)
1906 IOpcRelationshipEnumerator_Release(enumerator);
1907 return hr;
1910 if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content)))
1912 IOpcRelationshipEnumerator_Release(enumerator);
1913 return hr;
1916 hr = IXmlWriter_SetOutput(writer, (IUnknown *)content);
1917 if (SUCCEEDED(hr))
1918 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
1919 if (SUCCEEDED(hr))
1920 hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipsW, uriW);
1922 while (has_next)
1924 IOpcRelationship *rel;
1926 if (FAILED(hr = IOpcRelationshipEnumerator_GetCurrent(enumerator, &rel)))
1927 break;
1929 hr = opc_package_write_rel(rel, writer);
1930 IOpcRelationship_Release(rel);
1931 if (FAILED(hr))
1932 break;
1934 IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1937 IOpcRelationshipEnumerator_Release(enumerator);
1939 if (SUCCEEDED(hr))
1940 hr = IXmlWriter_WriteEndDocument(writer);
1941 if (SUCCEEDED(hr))
1942 hr = IXmlWriter_Flush(writer);
1944 if (SUCCEEDED(hr))
1945 hr = IOpcUri_GetRelationshipsPartUri(uri, &rels_uri);
1946 if (SUCCEEDED(hr))
1947 hr = IOpcPartUri_GetRawUri(rels_uri, &rels_part_uri);
1948 if (SUCCEEDED(hr))
1950 /* Relationship part names always start with root '/', skip it. */
1951 hr = compress_add_file(archive, rels_part_uri + 1, content, OPC_COMPRESSION_NORMAL);
1954 SysFreeString(rels_part_uri);
1955 IStream_Release(content);
1957 return hr;
1960 static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *part, IXmlWriter *writer)
1962 OPC_COMPRESSION_OPTIONS options = OPC_COMPRESSION_NORMAL;
1963 IOpcRelationshipSet *rels = NULL;
1964 IStream *content = NULL;
1965 IOpcPartUri *name;
1966 BSTR uri = NULL;
1967 HRESULT hr;
1969 if (FAILED(hr = IOpcPart_GetName(part, &name)))
1970 return hr;
1972 hr = IOpcPartUri_GetRawUri(name, &uri);
1973 if (SUCCEEDED(hr))
1974 hr = IOpcPart_GetCompressionOptions(part, &options);
1975 if (SUCCEEDED(hr))
1976 hr = IOpcPart_GetContentStream(part, &content);
1977 if (SUCCEEDED(hr))
1979 /* Part names always start with root '/', skip it. */
1980 hr = compress_add_file(archive, uri + 1, content, options);
1982 if (SUCCEEDED(hr))
1983 hr = IOpcPart_GetRelationshipSet(part, &rels);
1984 if (SUCCEEDED(hr))
1985 hr = opc_package_write_rels(archive, rels, (IOpcUri *)name, writer);
1987 IOpcPartUri_Release(name);
1988 SysFreeString(uri);
1989 if (content)
1990 IStream_Release(content);
1991 if (rels)
1992 IOpcRelationshipSet_Release(rels);
1994 return hr;
1997 static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage *package, IXmlWriter *writer)
1999 IOpcPartEnumerator *parts;
2000 IOpcPartSet *part_set;
2001 BOOL got_next;
2002 HRESULT hr;
2004 if (FAILED(hr = IOpcPackage_GetPartSet(package, &part_set)))
2005 return hr;
2007 hr = IOpcPartSet_GetEnumerator(part_set, &parts);
2008 IOpcPartSet_Release(part_set);
2009 if (FAILED(hr))
2010 return hr;
2012 while (IOpcPartEnumerator_MoveNext(parts, &got_next) == S_OK && got_next)
2014 IOpcPart *part;
2016 if (FAILED(hr = IOpcPartEnumerator_GetCurrent(parts, &part)))
2017 break;
2019 hr = opc_package_write_part(archive, part, writer);
2020 IOpcPart_Release(part);
2021 if (FAILED(hr))
2022 break;
2025 IOpcPartEnumerator_Release(parts);
2027 return hr;
2030 HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *stream)
2032 IOpcRelationshipSet *rels = NULL;
2033 struct zip_archive *archive;
2034 IOpcUri *uri = NULL;
2035 IXmlWriter *writer;
2036 HRESULT hr;
2038 if (flags != OPC_WRITE_FORCE_ZIP32)
2039 FIXME("Unsupported write flags %#x.\n", flags);
2041 if (FAILED(hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL)))
2042 return hr;
2044 if (FAILED(hr = compress_create_archive(stream, &archive)))
2046 IXmlWriter_Release(writer);
2047 return hr;
2050 /* [Content_Types].xml */
2051 hr = opc_package_write_contenttypes(package, archive, writer);
2052 /* Package relationships. */
2053 if (SUCCEEDED(hr))
2054 hr = IOpcPackage_GetRelationshipSet(package, &rels);
2055 if (SUCCEEDED(hr))
2056 hr = opc_root_uri_create(&uri);
2057 if (SUCCEEDED(hr))
2058 hr = opc_package_write_rels(archive, rels, uri, writer);
2059 /* Parts. */
2060 if (SUCCEEDED(hr))
2061 hr = opc_package_write_parts(archive, package, writer);
2063 if (rels)
2064 IOpcRelationshipSet_Release(rels);
2065 if (uri)
2066 IOpcUri_Release(uri);
2068 compress_finalize_archive(archive);
2069 IXmlWriter_Release(writer);
2071 return hr;