opcservices: Write relationship stream for parts.
[wine.git] / dlls / opcservices / package.c
blobfb07d4db7832b41f8f7c359f4f7bc37c1631adcf
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 return S_OK;
566 static HRESULT WINAPI opc_content_stream_Write(IStream *iface, const void *data, ULONG size, ULONG *num_written)
568 struct opc_content_stream *stream = impl_from_IStream(iface);
569 DWORD written = 0;
571 TRACE("iface %p, data %p, size %u, num_written %p.\n", iface, data, size, num_written);
573 if (!num_written)
574 num_written = &written;
576 *num_written = 0;
578 if (size > stream->content->size.QuadPart - stream->pos.QuadPart)
580 void *ptr = heap_realloc(stream->content->data, stream->pos.QuadPart + size);
581 if (!ptr)
582 return E_OUTOFMEMORY;
583 stream->content->data = ptr;
586 memcpy(stream->content->data + stream->pos.QuadPart, data, size);
587 stream->pos.QuadPart += size;
588 stream->content->size.QuadPart += size;
589 *num_written = size;
591 return S_OK;
594 static HRESULT WINAPI opc_content_stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER *newpos)
596 struct opc_content_stream *stream = impl_from_IStream(iface);
597 ULARGE_INTEGER pos;
599 TRACE("iface %p, move %s, origin %d, newpos %p.\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, newpos);
601 switch (origin)
603 case STREAM_SEEK_SET:
604 pos.QuadPart = move.QuadPart;
605 break;
606 case STREAM_SEEK_CUR:
607 pos.QuadPart = stream->pos.QuadPart + move.QuadPart;
608 break;
609 case STREAM_SEEK_END:
610 pos.QuadPart = stream->content->size.QuadPart + move.QuadPart;
611 break;
612 default:
613 WARN("Unknown origin mode %d.\n", origin);
614 return E_INVALIDARG;
617 stream->pos = pos;
619 if (newpos)
620 *newpos = stream->pos;
622 return S_OK;
625 static HRESULT WINAPI opc_content_stream_SetSize(IStream *iface, ULARGE_INTEGER size)
627 FIXME("iface %p, size %s stub!\n", iface, wine_dbgstr_longlong(size.QuadPart));
629 return E_NOTIMPL;
632 static HRESULT WINAPI opc_content_stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER size,
633 ULARGE_INTEGER *num_read, ULARGE_INTEGER *written)
635 FIXME("iface %p, dest %p, size %s, num_read %p, written %p stub!\n", iface, dest,
636 wine_dbgstr_longlong(size.QuadPart), num_read, written);
638 return E_NOTIMPL;
641 static HRESULT WINAPI opc_content_stream_Commit(IStream *iface, DWORD flags)
643 FIXME("iface %p, flags %#x stub!\n", iface, flags);
645 return E_NOTIMPL;
648 static HRESULT WINAPI opc_content_stream_Revert(IStream *iface)
650 FIXME("iface %p stub!\n", iface);
652 return E_NOTIMPL;
655 static HRESULT WINAPI opc_content_stream_LockRegion(IStream *iface, ULARGE_INTEGER offset,
656 ULARGE_INTEGER size, DWORD lock_type)
658 FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart),
659 wine_dbgstr_longlong(size.QuadPart), lock_type);
661 return E_NOTIMPL;
664 static HRESULT WINAPI opc_content_stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, ULARGE_INTEGER size,
665 DWORD lock_type)
667 FIXME("iface %p, offset %s, size %s, lock_type %d stub!\n", iface, wine_dbgstr_longlong(offset.QuadPart),
668 wine_dbgstr_longlong(size.QuadPart), lock_type);
670 return E_NOTIMPL;
673 static HRESULT WINAPI opc_content_stream_Stat(IStream *iface, STATSTG *statstg, DWORD flag)
675 FIXME("iface %p, statstg %p, flag %d stub!\n", iface, statstg, flag);
677 return E_NOTIMPL;
680 static HRESULT WINAPI opc_content_stream_Clone(IStream *iface, IStream **result)
682 FIXME("iface %p, result %p stub!\n", iface, result);
684 return E_NOTIMPL;
687 static const IStreamVtbl opc_content_stream_vtbl =
689 opc_content_stream_QueryInterface,
690 opc_content_stream_AddRef,
691 opc_content_stream_Release,
692 opc_content_stream_Read,
693 opc_content_stream_Write,
694 opc_content_stream_Seek,
695 opc_content_stream_SetSize,
696 opc_content_stream_CopyTo,
697 opc_content_stream_Commit,
698 opc_content_stream_Revert,
699 opc_content_stream_LockRegion,
700 opc_content_stream_UnlockRegion,
701 opc_content_stream_Stat,
702 opc_content_stream_Clone,
705 static HRESULT opc_content_stream_create(struct opc_content *content, IStream **out)
707 struct opc_content_stream *stream;
709 if (!(stream = heap_alloc_zero(sizeof(*stream))))
710 return E_OUTOFMEMORY;
712 stream->IStream_iface.lpVtbl = &opc_content_stream_vtbl;
713 stream->refcount = 1;
714 stream->content = content;
715 InterlockedIncrement(&content->refcount);
717 *out = &stream->IStream_iface;
719 TRACE("Created content stream %p.\n", *out);
720 return S_OK;
723 static HRESULT opc_relationship_set_create(IOpcUri *source_uri, IOpcRelationshipSet **relationship_set);
725 static WCHAR *opc_strdupW(const WCHAR *str)
727 WCHAR *ret = NULL;
729 if (str)
731 size_t size;
733 size = (strlenW(str) + 1) * sizeof(WCHAR);
734 ret = CoTaskMemAlloc(size);
735 if (ret)
736 memcpy(ret, str, size);
739 return ret;
742 static HRESULT WINAPI opc_part_QueryInterface(IOpcPart *iface, REFIID iid, void **out)
744 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
746 if (IsEqualIID(iid, &IID_IOpcPart) ||
747 IsEqualIID(iid, &IID_IUnknown))
749 *out = iface;
750 IOpcPart_AddRef(iface);
751 return S_OK;
754 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
755 return E_NOINTERFACE;
758 static ULONG WINAPI opc_part_AddRef(IOpcPart *iface)
760 struct opc_part *part = impl_from_IOpcPart(iface);
761 ULONG refcount = InterlockedIncrement(&part->refcount);
763 TRACE("%p increasing refcount to %u.\n", iface, refcount);
765 return refcount;
768 static ULONG WINAPI opc_part_Release(IOpcPart *iface)
770 struct opc_part *part = impl_from_IOpcPart(iface);
771 ULONG refcount = InterlockedDecrement(&part->refcount);
773 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
775 if (!refcount)
777 if (part->relationship_set)
778 IOpcRelationshipSet_Release(part->relationship_set);
779 IOpcPartUri_Release(part->name);
780 CoTaskMemFree(part->content_type);
781 opc_content_release(part->content);
782 heap_free(part);
785 return refcount;
788 static HRESULT WINAPI opc_part_GetRelationshipSet(IOpcPart *iface, IOpcRelationshipSet **relationship_set)
790 struct opc_part *part = impl_from_IOpcPart(iface);
791 HRESULT hr;
793 TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
795 if (!part->relationship_set && FAILED(hr = opc_relationship_set_create((IOpcUri *)part->name, &part->relationship_set)))
796 return hr;
798 *relationship_set = part->relationship_set;
799 IOpcRelationshipSet_AddRef(*relationship_set);
801 return S_OK;
804 static HRESULT WINAPI opc_part_GetContentStream(IOpcPart *iface, IStream **stream)
806 struct opc_part *part = impl_from_IOpcPart(iface);
808 TRACE("iface %p, stream %p.\n", iface, stream);
810 if (!stream)
811 return E_POINTER;
813 return opc_content_stream_create(part->content, stream);
816 static HRESULT WINAPI opc_part_GetName(IOpcPart *iface, IOpcPartUri **name)
818 struct opc_part *part = impl_from_IOpcPart(iface);
820 TRACE("iface %p, name %p.\n", iface, name);
822 *name = part->name;
823 IOpcPartUri_AddRef(*name);
825 return S_OK;
828 static HRESULT WINAPI opc_part_GetContentType(IOpcPart *iface, LPWSTR *type)
830 struct opc_part *part = impl_from_IOpcPart(iface);
832 TRACE("iface %p, type %p.\n", iface, type);
834 *type = opc_strdupW(part->content_type);
835 return *type ? S_OK : E_OUTOFMEMORY;
838 static HRESULT WINAPI opc_part_GetCompressionOptions(IOpcPart *iface, OPC_COMPRESSION_OPTIONS *options)
840 struct opc_part *part = impl_from_IOpcPart(iface);
842 TRACE("iface %p, options %p.\n", iface, options);
844 *options = part->compression_options;
845 return S_OK;
848 static const IOpcPartVtbl opc_part_vtbl =
850 opc_part_QueryInterface,
851 opc_part_AddRef,
852 opc_part_Release,
853 opc_part_GetRelationshipSet,
854 opc_part_GetContentStream,
855 opc_part_GetName,
856 opc_part_GetContentType,
857 opc_part_GetCompressionOptions,
860 static HRESULT opc_part_create(struct opc_part_set *set, IOpcPartUri *name, const WCHAR *content_type,
861 DWORD compression_options, IOpcPart **out)
863 struct opc_part *part;
865 if (!opc_array_reserve((void **)&set->parts, &set->size, set->count + 1, sizeof(*set->parts)))
866 return E_OUTOFMEMORY;
868 if (!(part = heap_alloc_zero(sizeof(*part))))
869 return E_OUTOFMEMORY;
871 part->IOpcPart_iface.lpVtbl = &opc_part_vtbl;
872 part->refcount = 1;
873 part->name = name;
874 IOpcPartUri_AddRef(name);
875 part->compression_options = compression_options;
876 if (!(part->content_type = opc_strdupW(content_type)))
878 IOpcPart_Release(&part->IOpcPart_iface);
879 return E_OUTOFMEMORY;
882 part->content = heap_alloc_zero(sizeof(*part->content));
883 if (!part->content)
885 IOpcPart_Release(&part->IOpcPart_iface);
886 return E_OUTOFMEMORY;
888 part->content->refcount = 1;
890 set->parts[set->count++] = part;
891 IOpcPart_AddRef(&part->IOpcPart_iface);
892 CoCreateGuid(&set->id);
894 *out = &part->IOpcPart_iface;
895 TRACE("Created part %p.\n", *out);
896 return S_OK;
899 static struct opc_part *opc_part_set_get_part(const struct opc_part_set *part_set, IOpcPartUri *name)
901 BOOL is_equal;
902 size_t i;
904 for (i = 0; i < part_set->count; ++i)
906 is_equal = FALSE;
907 if (IOpcPartUri_IsEqual(part_set->parts[i]->name, (IUri *)name, &is_equal) == S_OK && is_equal)
908 return part_set->parts[i];
911 return NULL;
914 static HRESULT WINAPI opc_part_set_QueryInterface(IOpcPartSet *iface, REFIID iid, void **out)
916 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
918 if (IsEqualIID(iid, &IID_IOpcPartSet) ||
919 IsEqualIID(iid, &IID_IUnknown))
921 *out = iface;
922 IOpcPartSet_AddRef(iface);
923 return S_OK;
926 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
927 return E_NOINTERFACE;
930 static ULONG WINAPI opc_part_set_AddRef(IOpcPartSet *iface)
932 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
933 ULONG refcount = InterlockedIncrement(&part_set->refcount);
935 TRACE("%p increasing refcount to %u.\n", iface, refcount);
937 return refcount;
940 static ULONG WINAPI opc_part_set_Release(IOpcPartSet *iface)
942 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
943 ULONG refcount = InterlockedDecrement(&part_set->refcount);
945 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
947 if (!refcount)
949 size_t i;
951 for (i = 0; i < part_set->count; ++i)
952 IOpcPart_Release(&part_set->parts[i]->IOpcPart_iface);
953 heap_free(part_set->parts);
954 heap_free(part_set);
957 return refcount;
960 static HRESULT WINAPI opc_part_set_GetPart(IOpcPartSet *iface, IOpcPartUri *name, IOpcPart **out)
962 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
963 struct opc_part *part;
965 TRACE("iface %p, name %p, out %p.\n", iface, name, out);
967 if (!out)
968 return E_POINTER;
970 *out = NULL;
972 if (!name)
973 return E_POINTER;
975 if ((part = opc_part_set_get_part(part_set, name)))
977 *out = &part->IOpcPart_iface;
978 IOpcPart_AddRef(*out);
981 return *out ? S_OK : OPC_E_NO_SUCH_PART;
984 static HRESULT WINAPI opc_part_set_CreatePart(IOpcPartSet *iface, IOpcPartUri *name, LPCWSTR content_type,
985 OPC_COMPRESSION_OPTIONS compression_options, IOpcPart **part)
987 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
989 TRACE("iface %p, name %p, content_type %s, compression_options %#x, part %p.\n", iface, name,
990 debugstr_w(content_type), compression_options, part);
992 if (!part)
993 return E_POINTER;
995 *part = NULL;
997 if (!name)
998 return E_POINTER;
1000 if (opc_part_set_get_part(part_set, name))
1001 return OPC_E_DUPLICATE_PART;
1003 return opc_part_create(part_set, name, content_type, compression_options, part);
1006 static HRESULT WINAPI opc_part_set_DeletePart(IOpcPartSet *iface, IOpcPartUri *name)
1008 FIXME("iface %p, name %p stub!\n", iface, name);
1010 return E_NOTIMPL;
1013 static HRESULT WINAPI opc_part_set_PartExists(IOpcPartSet *iface, IOpcPartUri *name, BOOL *exists)
1015 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
1017 TRACE("iface %p, name %p, exists %p.\n", iface, name, exists);
1019 if (!name || !exists)
1020 return E_POINTER;
1022 *exists = opc_part_set_get_part(part_set, name) != NULL;
1024 return S_OK;
1027 static HRESULT WINAPI opc_part_set_GetEnumerator(IOpcPartSet *iface, IOpcPartEnumerator **enumerator)
1029 struct opc_part_set *part_set = impl_from_IOpcPartSet(iface);
1031 TRACE("iface %p, enumerator %p.\n", iface, enumerator);
1033 if (!enumerator)
1034 return E_POINTER;
1036 return opc_part_enum_create(part_set, enumerator);
1039 static const IOpcPartSetVtbl opc_part_set_vtbl =
1041 opc_part_set_QueryInterface,
1042 opc_part_set_AddRef,
1043 opc_part_set_Release,
1044 opc_part_set_GetPart,
1045 opc_part_set_CreatePart,
1046 opc_part_set_DeletePart,
1047 opc_part_set_PartExists,
1048 opc_part_set_GetEnumerator,
1051 static HRESULT WINAPI opc_relationship_QueryInterface(IOpcRelationship *iface, REFIID iid, void **out)
1053 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1055 if (IsEqualIID(iid, &IID_IOpcRelationship) ||
1056 IsEqualIID(iid, &IID_IUnknown))
1058 *out = iface;
1059 IOpcRelationship_AddRef(iface);
1060 return S_OK;
1063 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1064 return E_NOINTERFACE;
1067 static ULONG WINAPI opc_relationship_AddRef(IOpcRelationship *iface)
1069 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1070 ULONG refcount = InterlockedIncrement(&relationship->refcount);
1072 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1074 return refcount;
1077 static ULONG WINAPI opc_relationship_Release(IOpcRelationship *iface)
1079 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1080 ULONG refcount = InterlockedDecrement(&relationship->refcount);
1082 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1084 if (!refcount)
1086 CoTaskMemFree(relationship->id);
1087 CoTaskMemFree(relationship->type);
1088 IOpcUri_Release(relationship->source_uri);
1089 IUri_Release(relationship->target);
1090 heap_free(relationship);
1093 return refcount;
1096 static HRESULT WINAPI opc_relationship_GetId(IOpcRelationship *iface, WCHAR **id)
1098 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1100 TRACE("iface %p, id %p.\n", iface, id);
1102 *id = opc_strdupW(relationship->id);
1103 return *id ? S_OK : E_OUTOFMEMORY;
1106 static HRESULT WINAPI opc_relationship_GetRelationshipType(IOpcRelationship *iface, WCHAR **type)
1108 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1110 TRACE("iface %p, type %p.\n", iface, type);
1112 *type = opc_strdupW(relationship->type);
1113 return *type ? S_OK : E_OUTOFMEMORY;
1116 static HRESULT WINAPI opc_relationship_GetSourceUri(IOpcRelationship *iface, IOpcUri **uri)
1118 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1120 TRACE("iface %p, uri %p.\n", iface, uri);
1122 *uri = relationship->source_uri;
1123 IOpcUri_AddRef(*uri);
1125 return S_OK;
1128 static HRESULT WINAPI opc_relationship_GetTargetUri(IOpcRelationship *iface, IUri **target)
1130 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1132 TRACE("iface %p, target %p.\n", iface, target);
1134 *target = relationship->target;
1135 IUri_AddRef(*target);
1137 return S_OK;
1140 static HRESULT WINAPI opc_relationship_GetTargetMode(IOpcRelationship *iface, OPC_URI_TARGET_MODE *target_mode)
1142 struct opc_relationship *relationship = impl_from_IOpcRelationship(iface);
1144 TRACE("iface %p, target_mode %p.\n", iface, target_mode);
1146 *target_mode = relationship->target_mode;
1148 return S_OK;
1151 static const IOpcRelationshipVtbl opc_relationship_vtbl =
1153 opc_relationship_QueryInterface,
1154 opc_relationship_AddRef,
1155 opc_relationship_Release,
1156 opc_relationship_GetId,
1157 opc_relationship_GetRelationshipType,
1158 opc_relationship_GetSourceUri,
1159 opc_relationship_GetTargetUri,
1160 opc_relationship_GetTargetMode,
1163 static struct opc_relationship *opc_relationshipset_get_rel(struct opc_relationship_set *relationship_set,
1164 const WCHAR *id)
1166 size_t i;
1168 for (i = 0; i < relationship_set->count; i++)
1170 if (!strcmpW(id, relationship_set->relationships[i]->id))
1171 return relationship_set->relationships[i];
1174 return NULL;
1177 static HRESULT opc_relationship_create(struct opc_relationship_set *set, const WCHAR *id, const WCHAR *type,
1178 IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **out)
1180 struct opc_relationship *relationship;
1182 if (!opc_array_reserve((void **)&set->relationships, &set->size, set->count + 1, sizeof(*set->relationships)))
1183 return E_OUTOFMEMORY;
1185 if (!(relationship = heap_alloc_zero(sizeof(*relationship))))
1186 return E_OUTOFMEMORY;
1188 relationship->IOpcRelationship_iface.lpVtbl = &opc_relationship_vtbl;
1189 relationship->refcount = 1;
1191 relationship->target = target_uri;
1192 IUri_AddRef(relationship->target);
1193 relationship->source_uri = set->source_uri;
1194 IOpcUri_AddRef(relationship->source_uri);
1196 if (id)
1197 relationship->id = opc_strdupW(id);
1198 else
1200 relationship->id = CoTaskMemAlloc(10 * sizeof(WCHAR));
1201 if (relationship->id)
1203 static const WCHAR fmtW[] = {'R','%','0','8','X',0};
1204 DWORD generated;
1206 /* FIXME: test that generated id is unique */
1207 RtlGenRandom(&generated, sizeof(generated));
1208 sprintfW(relationship->id, fmtW, generated);
1210 if (opc_relationshipset_get_rel(set, relationship->id))
1212 WARN("Newly generated id %s already exists.\n", debugstr_w(relationship->id));
1213 IOpcRelationship_Release(&relationship->IOpcRelationship_iface);
1214 return E_FAIL;
1219 relationship->type = opc_strdupW(type);
1220 if (!relationship->id || !relationship->type)
1222 IOpcRelationship_Release(&relationship->IOpcRelationship_iface);
1223 return E_OUTOFMEMORY;
1226 set->relationships[set->count++] = relationship;
1227 IOpcRelationship_AddRef(&relationship->IOpcRelationship_iface);
1228 CoCreateGuid(&set->id);
1230 *out = &relationship->IOpcRelationship_iface;
1231 TRACE("Created relationship %p.\n", *out);
1232 return S_OK;
1235 static HRESULT WINAPI opc_relationship_set_QueryInterface(IOpcRelationshipSet *iface, REFIID iid, void **out)
1237 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1239 if (IsEqualIID(iid, &IID_IOpcRelationshipSet) ||
1240 IsEqualIID(iid, &IID_IUnknown))
1242 *out = iface;
1243 IOpcRelationshipSet_AddRef(iface);
1244 return S_OK;
1247 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1248 return E_NOINTERFACE;
1251 static ULONG WINAPI opc_relationship_set_AddRef(IOpcRelationshipSet *iface)
1253 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1254 ULONG refcount = InterlockedIncrement(&relationship_set->refcount);
1256 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1258 return refcount;
1261 static ULONG WINAPI opc_relationship_set_Release(IOpcRelationshipSet *iface)
1263 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1264 ULONG refcount = InterlockedDecrement(&relationship_set->refcount);
1266 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1268 if (!refcount)
1270 size_t i;
1272 for (i = 0; i < relationship_set->count; ++i)
1273 IOpcRelationship_Release(&relationship_set->relationships[i]->IOpcRelationship_iface);
1274 IOpcUri_Release(relationship_set->source_uri);
1275 heap_free(relationship_set->relationships);
1276 heap_free(relationship_set);
1279 return refcount;
1282 static HRESULT WINAPI opc_relationship_set_GetRelationship(IOpcRelationshipSet *iface, const WCHAR *id,
1283 IOpcRelationship **relationship)
1285 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1286 struct opc_relationship *ret;
1288 TRACE("iface %p, id %s, relationship %p.\n", iface, debugstr_w(id), relationship);
1290 if (!relationship)
1291 return E_POINTER;
1293 *relationship = NULL;
1295 if (!id)
1296 return E_POINTER;
1298 if ((ret = opc_relationshipset_get_rel(relationship_set, id)))
1300 *relationship = &ret->IOpcRelationship_iface;
1301 IOpcRelationship_AddRef(*relationship);
1304 return *relationship ? S_OK : OPC_E_NO_SUCH_RELATIONSHIP;
1307 static HRESULT WINAPI opc_relationship_set_CreateRelationship(IOpcRelationshipSet *iface, const WCHAR *id,
1308 const WCHAR *type, IUri *target_uri, OPC_URI_TARGET_MODE target_mode, IOpcRelationship **relationship)
1310 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1311 DWORD length;
1313 TRACE("iface %p, id %s, type %s, target_uri %p, target_mode %d, relationship %p.\n", iface, debugstr_w(id),
1314 debugstr_w(type), target_uri, target_mode, relationship);
1316 if (!relationship)
1317 return E_POINTER;
1319 *relationship = NULL;
1321 if (!type || !target_uri)
1322 return E_POINTER;
1324 if (id && opc_relationshipset_get_rel(relationship_set, id))
1325 return OPC_E_DUPLICATE_RELATIONSHIP;
1327 if (IUri_GetPropertyLength(target_uri, Uri_PROPERTY_SCHEME_NAME, &length, 0) == S_OK && length != 0
1328 && target_mode == OPC_URI_TARGET_MODE_INTERNAL)
1329 return OPC_E_INVALID_RELATIONSHIP_TARGET;
1331 return opc_relationship_create(relationship_set, id, type, target_uri, target_mode, relationship);
1334 static HRESULT WINAPI opc_relationship_set_DeleteRelationship(IOpcRelationshipSet *iface, const WCHAR *id)
1336 FIXME("iface %p, id %s stub!\n", iface, debugstr_w(id));
1338 return E_NOTIMPL;
1341 static HRESULT WINAPI opc_relationship_set_RelationshipExists(IOpcRelationshipSet *iface, const WCHAR *id, BOOL *exists)
1343 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1345 TRACE("iface %p, id %s, exists %p.\n", iface, debugstr_w(id), exists);
1347 if (!id || !exists)
1348 return E_POINTER;
1350 *exists = opc_relationshipset_get_rel(relationship_set, id) != NULL;
1352 return S_OK;
1355 static HRESULT WINAPI opc_relationship_set_GetEnumerator(IOpcRelationshipSet *iface,
1356 IOpcRelationshipEnumerator **enumerator)
1358 struct opc_relationship_set *relationship_set = impl_from_IOpcRelationshipSet(iface);
1360 TRACE("iface %p, enumerator %p.\n", iface, enumerator);
1362 if (!enumerator)
1363 return E_POINTER;
1365 return opc_rel_enum_create(relationship_set, enumerator);
1368 static HRESULT WINAPI opc_relationship_set_GetEnumeratorForType(IOpcRelationshipSet *iface, const WCHAR *type,
1369 IOpcRelationshipEnumerator **enumerator)
1371 FIXME("iface %p, type %s, enumerator %p stub!\n", iface, debugstr_w(type), enumerator);
1373 return E_NOTIMPL;
1376 static HRESULT WINAPI opc_relationship_set_GetRelationshipsContentStream(IOpcRelationshipSet *iface, IStream **stream)
1378 FIXME("iface %p, stream %p stub!\n", iface, stream);
1380 return E_NOTIMPL;
1383 static const IOpcRelationshipSetVtbl opc_relationship_set_vtbl =
1385 opc_relationship_set_QueryInterface,
1386 opc_relationship_set_AddRef,
1387 opc_relationship_set_Release,
1388 opc_relationship_set_GetRelationship,
1389 opc_relationship_set_CreateRelationship,
1390 opc_relationship_set_DeleteRelationship,
1391 opc_relationship_set_RelationshipExists,
1392 opc_relationship_set_GetEnumerator,
1393 opc_relationship_set_GetEnumeratorForType,
1394 opc_relationship_set_GetRelationshipsContentStream,
1397 static HRESULT opc_relationship_set_create(IOpcUri *source_uri, IOpcRelationshipSet **out)
1399 struct opc_relationship_set *relationship_set;
1401 if (!(relationship_set = heap_alloc_zero(sizeof(*relationship_set))))
1402 return E_OUTOFMEMORY;
1404 relationship_set->IOpcRelationshipSet_iface.lpVtbl = &opc_relationship_set_vtbl;
1405 relationship_set->refcount = 1;
1406 relationship_set->source_uri = source_uri;
1407 IOpcUri_AddRef(relationship_set->source_uri);
1409 *out = &relationship_set->IOpcRelationshipSet_iface;
1410 TRACE("Created relationship set %p.\n", *out);
1411 return S_OK;
1414 static HRESULT WINAPI opc_package_QueryInterface(IOpcPackage *iface, REFIID iid, void **out)
1416 TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
1418 if (IsEqualIID(iid, &IID_IOpcPackage) ||
1419 IsEqualIID(iid, &IID_IUnknown))
1421 *out = iface;
1422 IOpcPackage_AddRef(iface);
1423 return S_OK;
1426 WARN("Unsupported interface %s.\n", debugstr_guid(iid));
1427 return E_NOINTERFACE;
1430 static ULONG WINAPI opc_package_AddRef(IOpcPackage *iface)
1432 struct opc_package *package = impl_from_IOpcPackage(iface);
1433 ULONG refcount = InterlockedIncrement(&package->refcount);
1435 TRACE("%p increasing refcount to %u.\n", iface, refcount);
1437 return refcount;
1440 static ULONG WINAPI opc_package_Release(IOpcPackage *iface)
1442 struct opc_package *package = impl_from_IOpcPackage(iface);
1443 ULONG refcount = InterlockedDecrement(&package->refcount);
1445 TRACE("%p decreasing refcount to %u.\n", iface, refcount);
1447 if (!refcount)
1449 if (package->part_set)
1450 IOpcPartSet_Release(package->part_set);
1451 if (package->relationship_set)
1452 IOpcRelationshipSet_Release(package->relationship_set);
1453 if (package->source_uri)
1454 IOpcUri_Release(package->source_uri);
1455 heap_free(package);
1458 return refcount;
1461 static HRESULT WINAPI opc_package_GetPartSet(IOpcPackage *iface, IOpcPartSet **part_set)
1463 struct opc_package *package = impl_from_IOpcPackage(iface);
1465 TRACE("iface %p, part_set %p.\n", iface, part_set);
1467 if (!package->part_set)
1469 struct opc_part_set *part_set = heap_alloc_zero(sizeof(*part_set));
1470 if (!part_set)
1471 return E_OUTOFMEMORY;
1473 part_set->IOpcPartSet_iface.lpVtbl = &opc_part_set_vtbl;
1474 part_set->refcount = 1;
1476 package->part_set = &part_set->IOpcPartSet_iface;
1479 *part_set = package->part_set;
1480 IOpcPartSet_AddRef(*part_set);
1482 return S_OK;
1485 static HRESULT WINAPI opc_package_GetRelationshipSet(IOpcPackage *iface, IOpcRelationshipSet **relationship_set)
1487 struct opc_package *package = impl_from_IOpcPackage(iface);
1488 HRESULT hr;
1490 TRACE("iface %p, relationship_set %p.\n", iface, relationship_set);
1492 if (!package->relationship_set)
1494 if (FAILED(hr = opc_relationship_set_create(package->source_uri, &package->relationship_set)))
1495 return hr;
1498 *relationship_set = package->relationship_set;
1499 IOpcRelationshipSet_AddRef(*relationship_set);
1501 return S_OK;
1504 static const IOpcPackageVtbl opc_package_vtbl =
1506 opc_package_QueryInterface,
1507 opc_package_AddRef,
1508 opc_package_Release,
1509 opc_package_GetPartSet,
1510 opc_package_GetRelationshipSet,
1513 HRESULT opc_package_create(IOpcFactory *factory, IOpcPackage **out)
1515 struct opc_package *package;
1516 HRESULT hr;
1518 if (!(package = heap_alloc_zero(sizeof(*package))))
1519 return E_OUTOFMEMORY;
1521 package->IOpcPackage_iface.lpVtbl = &opc_package_vtbl;
1522 package->refcount = 1;
1524 if (FAILED(hr = IOpcFactory_CreatePackageRootUri(factory, &package->source_uri)))
1526 heap_free(package);
1527 return hr;
1530 *out = &package->IOpcPackage_iface;
1531 TRACE("Created package %p.\n", *out);
1532 return S_OK;
1535 struct content_types
1537 struct list types;
1538 BOOL has_rels_part;
1541 enum content_type_element
1543 CONTENT_TYPE_DEFAULT,
1544 CONTENT_TYPE_OVERRIDE,
1547 struct content_type
1549 struct list entry;
1550 enum content_type_element element;
1551 union
1553 struct default_type
1555 WCHAR *ext;
1556 WCHAR *type;
1557 } def;
1558 struct override_type
1560 IOpcPart *part;
1561 } override;
1562 } u;
1565 static HRESULT opc_package_add_override_content_type(struct content_types *types, IOpcPart *part)
1567 struct content_type *type;
1569 if (!(type = heap_alloc(sizeof(*type))))
1570 return E_OUTOFMEMORY;
1572 type->element = CONTENT_TYPE_OVERRIDE;
1573 type->u.override.part = part;
1574 IOpcPart_AddRef(part);
1576 list_add_tail(&types->types, &type->entry);
1578 return S_OK;
1581 static HRESULT opc_package_add_default_content_type(struct content_types *types,
1582 const WCHAR *ext, const WCHAR *content_type)
1584 struct content_type *type;
1586 if (!(type = heap_alloc(sizeof(*type))))
1587 return E_OUTOFMEMORY;
1589 type->element = CONTENT_TYPE_DEFAULT;
1590 type->u.def.ext = opc_strdupW(ext);
1591 type->u.def.type = opc_strdupW(content_type);
1592 if (!type->u.def.ext || !type->u.def.type)
1594 CoTaskMemFree(type->u.def.ext);
1595 CoTaskMemFree(type->u.def.type);
1596 heap_free(type);
1597 return E_OUTOFMEMORY;
1600 list_add_tail(&types->types, &type->entry);
1602 return S_OK;
1605 static HRESULT opc_package_add_content_type(struct content_types *types, IOpcPart *part)
1607 struct content_type *cur;
1608 BSTR ext, content_type;
1609 BOOL added = FALSE;
1610 IOpcPartUri *name;
1611 HRESULT hr;
1613 if (FAILED(hr = IOpcPart_GetName(part, &name)))
1614 return hr;
1616 hr = IOpcPartUri_GetExtension(name, &ext);
1617 IOpcPartUri_Release(name);
1618 if (hr == S_FALSE)
1620 hr = opc_package_add_override_content_type(types, part);
1621 SysFreeString(ext);
1622 return hr;
1625 if (FAILED(hr))
1626 return hr;
1628 if (FAILED(hr = IOpcPart_GetContentType(part, &content_type)))
1629 return hr;
1631 LIST_FOR_EACH_ENTRY(cur, &types->types, struct content_type, entry)
1633 if (cur->element == CONTENT_TYPE_OVERRIDE)
1634 continue;
1636 if (!strcmpiW(cur->u.def.ext, ext))
1638 added = TRUE;
1640 if (!strcmpW(cur->u.def.type, content_type))
1641 break;
1643 hr = opc_package_add_override_content_type(types, part);
1644 break;
1648 if (!added)
1649 hr = opc_package_add_default_content_type(types, ext, content_type);
1651 SysFreeString(ext);
1652 SysFreeString(content_type);
1654 return hr;
1657 static BOOL opc_package_has_rels_part(IOpcRelationshipSet *rel_set)
1659 IOpcRelationshipEnumerator *enumerator;
1660 BOOL has_next;
1661 HRESULT hr;
1663 if (FAILED(hr = IOpcRelationshipSet_GetEnumerator(rel_set, &enumerator)))
1664 return FALSE;
1666 has_next = FALSE;
1667 IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1668 IOpcRelationshipEnumerator_Release(enumerator);
1670 return has_next;
1673 static HRESULT opc_package_collect_content_types(IOpcPackage *package, struct content_types *types)
1675 IOpcPartEnumerator *enumerator;
1676 IOpcRelationshipSet *rel_set;
1677 IOpcPartSet *parts;
1678 BOOL has_next;
1679 HRESULT hr;
1681 if (FAILED(hr = IOpcPackage_GetPartSet(package, &parts)))
1682 return hr;
1684 hr = IOpcPackage_GetRelationshipSet(package, &rel_set);
1685 if (SUCCEEDED(hr))
1687 types->has_rels_part |= opc_package_has_rels_part(rel_set);
1688 IOpcRelationshipSet_Release(rel_set);
1691 hr = IOpcPartSet_GetEnumerator(parts, &enumerator);
1692 IOpcPartSet_Release(parts);
1693 if (FAILED(hr))
1694 return hr;
1696 if (FAILED(hr = IOpcPartEnumerator_MoveNext(enumerator, &has_next)) || !has_next)
1698 IOpcPartEnumerator_Release(enumerator);
1699 return hr;
1702 while (has_next)
1704 IOpcPart *part;
1706 if (FAILED(hr = IOpcPartEnumerator_GetCurrent(enumerator, &part)))
1707 break;
1709 if (!types->has_rels_part)
1711 hr = IOpcPart_GetRelationshipSet(part, &rel_set);
1712 if (SUCCEEDED(hr))
1714 types->has_rels_part |= opc_package_has_rels_part(rel_set);
1715 IOpcRelationshipSet_Release(rel_set);
1719 hr = opc_package_add_content_type(types, part);
1720 IOpcPart_Release(part);
1721 if (FAILED(hr))
1722 break;
1724 IOpcPartEnumerator_MoveNext(enumerator, &has_next);
1727 IOpcPartEnumerator_Release(enumerator);
1729 return hr;
1732 static HRESULT opc_package_write_default_type(const WCHAR *ext, const WCHAR *type, IXmlWriter *writer)
1734 static const WCHAR contenttypeW[] = {'C','o','n','t','e','n','t','T','y','p','e',0};
1735 static const WCHAR extensionW[] = {'E','x','t','e','n','s','i','o','n',0};
1736 static const WCHAR defaultW[] = {'D','e','f','a','u','l','t',0};
1737 HRESULT hr;
1739 hr = IXmlWriter_WriteStartElement(writer, NULL, defaultW, NULL);
1740 if (SUCCEEDED(hr))
1741 hr = IXmlWriter_WriteAttributeString(writer, NULL, extensionW, NULL, ext);
1742 if (SUCCEEDED(hr))
1743 hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, type);
1744 return hr;
1747 static HRESULT opc_package_write_contenttypes(IOpcPackage *package, struct zip_archive *archive, IXmlWriter *writer)
1749 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','/',
1750 'p','a','c','k','a','g','e','/','2','0','0','6','/','c','o','n','t','e','n','t','-','t','y','p','e','s',0};
1751 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','-',
1752 'p','a','c','k','a','g','e','.','r','e','l','a','t','i','o','n','s','h','i','p','s','+','x','m','l',0};
1753 static const WCHAR contenttypesW[] = {'[','C','o','n','t','e','n','t','_','T','y','p','e','s',']','.','x','m','l',0};
1754 static const WCHAR contenttypeW[] = {'C','o','n','t','e','n','t','T','y','p','e',0};
1755 static const WCHAR overrideW[] = {'O','v','e','r','r','i','d','e',0};
1756 static const WCHAR partnameW[] = {'P','a','r','t','N','a','m','e',0};
1757 static const WCHAR typesW[] = {'T','y','p','e','s',0};
1758 static const WCHAR relsW[] = {'r','e','l','s',0};
1759 struct content_type *content_type, *content_type2;
1760 struct content_types types;
1761 IStream *content = NULL;
1762 HRESULT hr;
1764 list_init(&types.types);
1765 types.has_rels_part = FALSE;
1767 hr = CreateStreamOnHGlobal(NULL, TRUE, &content);
1768 if (SUCCEEDED(hr))
1769 hr = opc_package_collect_content_types(package, &types);
1770 if (SUCCEEDED(hr))
1771 hr = IXmlWriter_SetOutput(writer, (IUnknown *)content);
1772 if (SUCCEEDED(hr))
1773 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Omit);
1774 if (SUCCEEDED(hr))
1775 hr = IXmlWriter_WriteStartElement(writer, NULL, typesW, uriW);
1777 if (SUCCEEDED(hr) && types.has_rels_part)
1779 hr = opc_package_write_default_type(relsW, relstypeW, writer);
1780 if (SUCCEEDED(hr))
1781 hr = IXmlWriter_WriteEndElement(writer);
1784 LIST_FOR_EACH_ENTRY_SAFE(content_type, content_type2, &types.types, struct content_type, entry)
1786 if (content_type->element == CONTENT_TYPE_DEFAULT)
1788 hr = opc_package_write_default_type(content_type->u.def.ext + 1, content_type->u.def.type, writer);
1790 CoTaskMemFree(content_type->u.def.ext);
1791 CoTaskMemFree(content_type->u.def.type);
1793 else
1795 IOpcPartUri *uri = NULL;
1796 WCHAR *type = NULL;
1797 BSTR name = NULL;
1799 if (SUCCEEDED(hr))
1800 hr = IXmlWriter_WriteStartElement(writer, NULL, overrideW, NULL);
1801 if (SUCCEEDED(hr))
1802 hr = IOpcPart_GetName(content_type->u.override.part, &uri);
1803 if (SUCCEEDED(hr))
1804 hr = IOpcPartUri_GetRawUri(uri, &name);
1805 if (SUCCEEDED(hr))
1806 hr = IXmlWriter_WriteAttributeString(writer, NULL, partnameW, NULL, name);
1807 if (SUCCEEDED(hr))
1808 hr = IOpcPart_GetContentType(content_type->u.override.part, &type);
1809 if (SUCCEEDED(hr))
1810 hr = IXmlWriter_WriteAttributeString(writer, NULL, contenttypeW, NULL, type);
1812 if (uri)
1813 IOpcPartUri_Release(uri);
1814 SysFreeString(name);
1815 CoTaskMemFree(type);
1817 IOpcPart_Release(content_type->u.override.part);
1819 if (SUCCEEDED(hr))
1820 hr = IXmlWriter_WriteEndElement(writer);
1822 list_remove(&content_type->entry);
1823 heap_free(content_type);
1826 if (SUCCEEDED(hr))
1827 hr = IXmlWriter_WriteEndDocument(writer);
1828 if (SUCCEEDED(hr))
1829 hr = IXmlWriter_Flush(writer);
1831 if (SUCCEEDED(hr))
1832 hr = compress_add_file(archive, contenttypesW, content, OPC_COMPRESSION_NORMAL);
1834 if (content)
1835 IStream_Release(content);
1837 return hr;
1840 static HRESULT opc_package_write_rel(IOpcRelationship *rel, IXmlWriter *writer)
1842 static const WCHAR relationshipW[] = {'R','e','l','a','t','i','o','n','s','h','i','p',0};
1843 static const WCHAR targetW[] = {'T','a','r','g','e','t',0};
1844 static const WCHAR typeW[] = {'T','y','p','e',0};
1845 static const WCHAR idW[] = {'I','d',0};
1846 BSTR target_uri;
1847 HRESULT hr;
1848 WCHAR *str;
1849 IUri *uri;
1851 if (FAILED(hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipW, NULL)))
1852 return hr;
1854 if (FAILED(hr = IOpcRelationship_GetTargetUri(rel, &uri)))
1855 return hr;
1857 IUri_GetRawUri(uri, &target_uri);
1858 IUri_Release(uri);
1860 hr = IXmlWriter_WriteAttributeString(writer, NULL, targetW, NULL, target_uri);
1861 SysFreeString(target_uri);
1862 if (FAILED(hr))
1863 return hr;
1865 if (FAILED(hr = IOpcRelationship_GetId(rel, &str)))
1866 return hr;
1868 hr = IXmlWriter_WriteAttributeString(writer, NULL, idW, NULL, str);
1869 CoTaskMemFree(str);
1870 if (FAILED(hr))
1871 return hr;
1873 if (FAILED(hr = IOpcRelationship_GetRelationshipType(rel, &str)))
1874 return hr;
1876 hr = IXmlWriter_WriteAttributeString(writer, NULL, typeW, NULL, str);
1877 CoTaskMemFree(str);
1878 if (FAILED(hr))
1879 return hr;
1881 return IXmlWriter_WriteEndElement(writer);
1884 static HRESULT opc_package_write_rels(struct zip_archive *archive, IOpcRelationshipSet *rels,
1885 IOpcUri *uri, IXmlWriter *writer)
1887 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','/',
1888 '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};
1889 static const WCHAR relationshipsW[] = {'R','e','l','a','t','i','o','n','s','h','i','p','s',0};
1890 IOpcRelationshipEnumerator *enumerator;
1891 IOpcPartUri *rels_uri;
1892 BSTR rels_part_uri;
1893 IStream *content;
1894 BOOL has_next;
1895 HRESULT hr;
1897 if (FAILED(hr = IOpcRelationshipSet_GetEnumerator(rels, &enumerator)))
1898 return hr;
1900 hr = IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1901 if (!has_next)
1903 IOpcRelationshipEnumerator_Release(enumerator);
1904 return hr;
1907 if (FAILED(hr = CreateStreamOnHGlobal(NULL, TRUE, &content)))
1909 IOpcRelationshipEnumerator_Release(enumerator);
1910 return hr;
1913 hr = IXmlWriter_SetOutput(writer, (IUnknown *)content);
1914 if (SUCCEEDED(hr))
1915 hr = IXmlWriter_WriteStartDocument(writer, XmlStandalone_Yes);
1916 if (SUCCEEDED(hr))
1917 hr = IXmlWriter_WriteStartElement(writer, NULL, relationshipsW, uriW);
1919 while (has_next)
1921 IOpcRelationship *rel;
1923 if (FAILED(hr = IOpcRelationshipEnumerator_GetCurrent(enumerator, &rel)))
1924 break;
1926 hr = opc_package_write_rel(rel, writer);
1927 IOpcRelationship_Release(rel);
1928 if (FAILED(hr))
1929 break;
1931 IOpcRelationshipEnumerator_MoveNext(enumerator, &has_next);
1934 IOpcRelationshipEnumerator_Release(enumerator);
1936 if (SUCCEEDED(hr))
1937 hr = IXmlWriter_WriteEndDocument(writer);
1938 if (SUCCEEDED(hr))
1939 hr = IXmlWriter_Flush(writer);
1941 hr = IOpcUri_GetRelationshipsPartUri(uri, &rels_uri);
1942 if (SUCCEEDED(hr))
1943 hr = IOpcPartUri_GetRawUri(rels_uri, &rels_part_uri);
1944 if (SUCCEEDED(hr))
1946 /* Relationship part names always start with root '/', skip it. */
1947 hr = compress_add_file(archive, rels_part_uri + 1, content, OPC_COMPRESSION_NORMAL);
1950 SysFreeString(rels_part_uri);
1951 IStream_Release(content);
1953 return hr;
1956 static HRESULT opc_package_write_part(struct zip_archive *archive, IOpcPart *part, IXmlWriter *writer)
1958 OPC_COMPRESSION_OPTIONS options = OPC_COMPRESSION_NORMAL;
1959 IOpcRelationshipSet *rels = NULL;
1960 IStream *content = NULL;
1961 IOpcPartUri *name;
1962 BSTR uri = NULL;
1963 HRESULT hr;
1965 if (FAILED(hr = IOpcPart_GetName(part, &name)))
1966 return hr;
1968 hr = IOpcPartUri_GetRawUri(name, &uri);
1969 if (SUCCEEDED(hr))
1970 hr = IOpcPart_GetCompressionOptions(part, &options);
1971 if (SUCCEEDED(hr))
1972 hr = IOpcPart_GetContentStream(part, &content);
1973 if (SUCCEEDED(hr))
1975 /* Part names always start with root '/', skip it. */
1976 hr = compress_add_file(archive, uri + 1, content, options);
1978 if (SUCCEEDED(hr))
1979 hr = IOpcPart_GetRelationshipSet(part, &rels);
1980 if (SUCCEEDED(hr))
1981 hr = opc_package_write_rels(archive, rels, (IOpcUri *)name, writer);
1983 IOpcPartUri_Release(name);
1984 SysFreeString(uri);
1985 if (content)
1986 IStream_Release(content);
1987 if (rels)
1988 IOpcRelationshipSet_Release(rels);
1990 return hr;
1993 static HRESULT opc_package_write_parts(struct zip_archive *archive, IOpcPackage *package, IXmlWriter *writer)
1995 IOpcPartEnumerator *parts;
1996 IOpcPartSet *part_set;
1997 BOOL got_next;
1998 HRESULT hr;
2000 if (FAILED(hr = IOpcPackage_GetPartSet(package, &part_set)))
2001 return hr;
2003 hr = IOpcPartSet_GetEnumerator(part_set, &parts);
2004 IOpcPartSet_Release(part_set);
2005 if (FAILED(hr))
2006 return hr;
2008 while (IOpcPartEnumerator_MoveNext(parts, &got_next) == S_OK && got_next)
2010 IOpcPart *part;
2012 if (FAILED(hr = IOpcPartEnumerator_GetCurrent(parts, &part)))
2013 break;
2015 hr = opc_package_write_part(archive, part, writer);
2016 IOpcPart_Release(part);
2017 if (FAILED(hr))
2018 break;
2021 IOpcPartEnumerator_Release(parts);
2023 return hr;
2026 HRESULT opc_package_write(IOpcPackage *package, OPC_WRITE_FLAGS flags, IStream *stream)
2028 IOpcRelationshipSet *rels = NULL;
2029 struct zip_archive *archive;
2030 IOpcUri *uri = NULL;
2031 IXmlWriter *writer;
2032 HRESULT hr;
2034 if (flags != OPC_WRITE_FORCE_ZIP32)
2035 FIXME("Unsupported write flags %#x.\n", flags);
2037 if (FAILED(hr = CreateXmlWriter(&IID_IXmlWriter, (void **)&writer, NULL)))
2038 return hr;
2040 if (FAILED(hr = compress_create_archive(stream, &archive)))
2042 IXmlWriter_Release(writer);
2043 return hr;
2046 /* [Content_Types].xml */
2047 hr = opc_package_write_contenttypes(package, archive, writer);
2048 /* Package relationships. */
2049 if (SUCCEEDED(hr))
2050 hr = IOpcPackage_GetRelationshipSet(package, &rels);
2051 if (SUCCEEDED(hr))
2052 hr = opc_root_uri_create(&uri);
2053 if (SUCCEEDED(hr))
2054 hr = opc_package_write_rels(archive, rels, uri, writer);
2055 /* Parts. */
2056 if (SUCCEEDED(hr))
2057 hr = opc_package_write_parts(archive, package, writer);
2059 if (rels)
2060 IOpcRelationshipSet_Release(rels);
2061 if (uri)
2062 IOpcUri_Release(uri);
2064 compress_finalize_archive(archive);
2065 IXmlWriter_Release(writer);
2067 return hr;