e8d2ad9d33e71b688bc10e26b02414bc4e944d3d
[reactos.git] / reactos / dll / win32 / windowscodecs / metadatahandler.c
1 /*
2 * Copyright 2012 Vincent Povirk for CodeWeavers
3 * Copyright 2012 Dmitry Timoshkov
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #define WIN32_NO_STATUS
21 #define _INC_WINDOWS
22 #define COM_NO_WINDOWS_H
23
24 #include <config.h>
25
26 //#include <stdarg.h>
27 #include <stdio.h>
28
29 #define COBJMACROS
30 #define NONAMELESSUNION
31
32 #include <windef.h>
33 #include <winbase.h>
34 #include <winternl.h>
35 #include <objbase.h>
36 //#include "wincodec.h"
37 #include <wincodecsdk.h>
38
39 #include "wincodecs_private.h"
40
41 #include <wine/debug.h>
42
43 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
44
45 typedef struct MetadataHandler {
46 IWICMetadataWriter IWICMetadataWriter_iface;
47 LONG ref;
48 IWICPersistStream IWICPersistStream_iface;
49 const MetadataHandlerVtbl *vtable;
50 MetadataItem *items;
51 DWORD item_count;
52 CRITICAL_SECTION lock;
53 } MetadataHandler;
54
55 static inline MetadataHandler *impl_from_IWICMetadataWriter(IWICMetadataWriter *iface)
56 {
57 return CONTAINING_RECORD(iface, MetadataHandler, IWICMetadataWriter_iface);
58 }
59
60 static inline MetadataHandler *impl_from_IWICPersistStream(IWICPersistStream *iface)
61 {
62 return CONTAINING_RECORD(iface, MetadataHandler, IWICPersistStream_iface);
63 }
64
65 static void MetadataHandler_FreeItems(MetadataHandler *This)
66 {
67 DWORD i;
68
69 for (i=0; i<This->item_count; i++)
70 {
71 PropVariantClear(&This->items[i].schema);
72 PropVariantClear(&This->items[i].id);
73 PropVariantClear(&This->items[i].value);
74 }
75
76 HeapFree(GetProcessHeap(), 0, This->items);
77 }
78
79 static HRESULT MetadataHandlerEnum_Create(MetadataHandler *parent, DWORD index,
80 IWICEnumMetadataItem **ppIEnumMetadataItem);
81
82 static HRESULT WINAPI MetadataHandler_QueryInterface(IWICMetadataWriter *iface, REFIID iid,
83 void **ppv)
84 {
85 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
86 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
87
88 if (!ppv) return E_INVALIDARG;
89
90 if (IsEqualIID(&IID_IUnknown, iid) ||
91 IsEqualIID(&IID_IWICMetadataReader, iid) ||
92 (IsEqualIID(&IID_IWICMetadataWriter, iid) && This->vtable->is_writer))
93 {
94 *ppv = &This->IWICMetadataWriter_iface;
95 }
96 else if (IsEqualIID(&IID_IPersist, iid) ||
97 IsEqualIID(&IID_IPersistStream, iid) ||
98 IsEqualIID(&IID_IWICPersistStream, iid))
99 {
100 *ppv = &This->IWICPersistStream_iface;
101 }
102 else
103 {
104 *ppv = NULL;
105 return E_NOINTERFACE;
106 }
107
108 IUnknown_AddRef((IUnknown*)*ppv);
109 return S_OK;
110 }
111
112 static ULONG WINAPI MetadataHandler_AddRef(IWICMetadataWriter *iface)
113 {
114 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
115 ULONG ref = InterlockedIncrement(&This->ref);
116
117 TRACE("(%p) refcount=%u\n", iface, ref);
118
119 return ref;
120 }
121
122 static ULONG WINAPI MetadataHandler_Release(IWICMetadataWriter *iface)
123 {
124 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
125 ULONG ref = InterlockedDecrement(&This->ref);
126
127 TRACE("(%p) refcount=%u\n", iface, ref);
128
129 if (ref == 0)
130 {
131 MetadataHandler_FreeItems(This);
132 This->lock.DebugInfo->Spare[0] = 0;
133 DeleteCriticalSection(&This->lock);
134 HeapFree(GetProcessHeap(), 0, This);
135 }
136
137 return ref;
138 }
139
140 static HRESULT WINAPI MetadataHandler_GetMetadataHandlerInfo(IWICMetadataWriter *iface,
141 IWICMetadataHandlerInfo **ppIHandler)
142 {
143 HRESULT hr;
144 IWICComponentInfo *component_info;
145 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
146
147 TRACE("%p,%p\n", iface, ppIHandler);
148
149 hr = CreateComponentInfo(This->vtable->clsid, &component_info);
150 if (FAILED(hr)) return hr;
151
152 hr = IWICComponentInfo_QueryInterface(component_info, &IID_IWICMetadataHandlerInfo,
153 (void **)ppIHandler);
154
155 IWICComponentInfo_Release(component_info);
156 return hr;
157 }
158
159 static HRESULT WINAPI MetadataHandler_GetMetadataFormat(IWICMetadataWriter *iface,
160 GUID *pguidMetadataFormat)
161 {
162 HRESULT hr;
163 IWICMetadataHandlerInfo *metadata_info;
164
165 TRACE("%p,%p\n", iface, pguidMetadataFormat);
166
167 if (!pguidMetadataFormat) return E_INVALIDARG;
168
169 hr = MetadataHandler_GetMetadataHandlerInfo(iface, &metadata_info);
170 if (FAILED(hr)) return hr;
171
172 hr = IWICMetadataHandlerInfo_GetMetadataFormat(metadata_info, pguidMetadataFormat);
173 IWICMetadataHandlerInfo_Release(metadata_info);
174
175 return hr;
176 }
177
178 static HRESULT WINAPI MetadataHandler_GetCount(IWICMetadataWriter *iface,
179 UINT *pcCount)
180 {
181 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
182
183 TRACE("%p,%p\n", iface, pcCount);
184
185 if (!pcCount) return E_INVALIDARG;
186
187 *pcCount = This->item_count;
188 return S_OK;
189 }
190
191 static HRESULT WINAPI MetadataHandler_GetValueByIndex(IWICMetadataWriter *iface,
192 UINT index, PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value)
193 {
194 HRESULT hr = S_OK;
195 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
196
197 TRACE("%p,%u,%p,%p,%p\n", iface, index, schema, id, value);
198
199 EnterCriticalSection(&This->lock);
200
201 if (index >= This->item_count)
202 {
203 LeaveCriticalSection(&This->lock);
204 return E_INVALIDARG;
205 }
206
207 if (schema)
208 hr = PropVariantCopy(schema, &This->items[index].schema);
209
210 if (SUCCEEDED(hr) && id)
211 hr = PropVariantCopy(id, &This->items[index].id);
212
213 if (SUCCEEDED(hr) && value)
214 hr = PropVariantCopy(value, &This->items[index].value);
215
216 LeaveCriticalSection(&This->lock);
217 return hr;
218 }
219
220 static BOOL get_int_value(const PROPVARIANT *pv, LONGLONG *value)
221 {
222 switch (pv->vt)
223 {
224 case VT_NULL:
225 case VT_EMPTY:
226 *value = 0;
227 break;
228 case VT_I1:
229 *value = pv->u.cVal;
230 break;
231 case VT_UI1:
232 *value = pv->u.bVal;
233 break;
234 case VT_I2:
235 *value = pv->u.iVal;
236 break;
237 case VT_UI2:
238 *value = pv->u.uiVal;
239 break;
240 case VT_I4:
241 *value = pv->u.lVal;
242 break;
243 case VT_UI4:
244 *value = pv->u.ulVal;
245 break;
246 case VT_I8:
247 case VT_UI8:
248 *value = pv->u.hVal.QuadPart;
249 break;
250 default:
251 FIXME("not supported variant type %d\n", pv->vt);
252 return FALSE;
253 }
254 return TRUE;
255 }
256
257 /* FiXME: Use propsys.PropVariantCompareEx once it's implemented */
258 static int propvar_cmp(const PROPVARIANT *v1, const PROPVARIANT *v2)
259 {
260 LONGLONG value1, value2;
261
262 if (v1->vt == VT_LPSTR && v2->vt == VT_LPSTR)
263 {
264 return lstrcmpA(v1->u.pszVal, v2->u.pszVal);
265 }
266
267 if (v1->vt == VT_LPWSTR && v2->vt == VT_LPWSTR)
268 {
269 return lstrcmpiW(v1->u.pwszVal, v2->u.pwszVal);
270 }
271
272 if (!get_int_value(v1, &value1)) return -1;
273 if (!get_int_value(v2, &value2)) return -1;
274
275 value1 -= value2;
276 if (value1) return value1 < 0 ? -1 : 1;
277 return 0;
278 }
279
280 static HRESULT WINAPI MetadataHandler_GetValue(IWICMetadataWriter *iface,
281 const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value)
282 {
283 UINT i;
284 HRESULT hr = WINCODEC_ERR_PROPERTYNOTFOUND;
285 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
286
287 TRACE("(%p,%p,%p,%p)\n", iface, schema, id, value);
288
289 if (!id) return E_INVALIDARG;
290
291 EnterCriticalSection(&This->lock);
292
293 for (i = 0; i < This->item_count; i++)
294 {
295 if (schema && This->items[i].schema.vt != VT_EMPTY)
296 {
297 if (propvar_cmp(schema, &This->items[i].schema) != 0) continue;
298 }
299
300 if (propvar_cmp(id, &This->items[i].id) != 0) continue;
301
302 hr = value ? PropVariantCopy(value, &This->items[i].value) : S_OK;
303 break;
304 }
305
306 LeaveCriticalSection(&This->lock);
307 return hr;
308 }
309
310 static HRESULT WINAPI MetadataHandler_GetEnumerator(IWICMetadataWriter *iface,
311 IWICEnumMetadataItem **ppIEnumMetadata)
312 {
313 MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
314 TRACE("(%p,%p)\n", iface, ppIEnumMetadata);
315 return MetadataHandlerEnum_Create(This, 0, ppIEnumMetadata);
316 }
317
318 static HRESULT WINAPI MetadataHandler_SetValue(IWICMetadataWriter *iface,
319 const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue)
320 {
321 FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue);
322 return E_NOTIMPL;
323 }
324
325 static HRESULT WINAPI MetadataHandler_SetValueByIndex(IWICMetadataWriter *iface,
326 UINT nIndex, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue)
327 {
328 FIXME("(%p,%u,%p,%p,%p): stub\n", iface, nIndex, pvarSchema, pvarId, pvarValue);
329 return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI MetadataHandler_RemoveValue(IWICMetadataWriter *iface,
333 const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId)
334 {
335 FIXME("(%p,%p,%p): stub\n", iface, pvarSchema, pvarId);
336 return E_NOTIMPL;
337 }
338
339 static HRESULT WINAPI MetadataHandler_RemoveValueByIndex(IWICMetadataWriter *iface,
340 UINT nIndex)
341 {
342 FIXME("(%p,%u): stub\n", iface, nIndex);
343 return E_NOTIMPL;
344 }
345
346 static const IWICMetadataWriterVtbl MetadataHandler_Vtbl = {
347 MetadataHandler_QueryInterface,
348 MetadataHandler_AddRef,
349 MetadataHandler_Release,
350 MetadataHandler_GetMetadataFormat,
351 MetadataHandler_GetMetadataHandlerInfo,
352 MetadataHandler_GetCount,
353 MetadataHandler_GetValueByIndex,
354 MetadataHandler_GetValue,
355 MetadataHandler_GetEnumerator,
356 MetadataHandler_SetValue,
357 MetadataHandler_SetValueByIndex,
358 MetadataHandler_RemoveValue,
359 MetadataHandler_RemoveValueByIndex
360 };
361
362 static HRESULT WINAPI MetadataHandler_PersistStream_QueryInterface(IWICPersistStream *iface,
363 REFIID iid, void **ppv)
364 {
365 MetadataHandler *This = impl_from_IWICPersistStream(iface);
366 return IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv);
367 }
368
369 static ULONG WINAPI MetadataHandler_PersistStream_AddRef(IWICPersistStream *iface)
370 {
371 MetadataHandler *This = impl_from_IWICPersistStream(iface);
372 return IWICMetadataWriter_AddRef(&This->IWICMetadataWriter_iface);
373 }
374
375 static ULONG WINAPI MetadataHandler_PersistStream_Release(IWICPersistStream *iface)
376 {
377 MetadataHandler *This = impl_from_IWICPersistStream(iface);
378 return IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface);
379 }
380
381 static HRESULT WINAPI MetadataHandler_GetClassID(IWICPersistStream *iface,
382 CLSID *pClassID)
383 {
384 FIXME("(%p,%p): stub\n", iface, pClassID);
385 return E_NOTIMPL;
386 }
387
388 static HRESULT WINAPI MetadataHandler_IsDirty(IWICPersistStream *iface)
389 {
390 FIXME("(%p): stub\n", iface);
391 return E_NOTIMPL;
392 }
393
394 static HRESULT WINAPI MetadataHandler_Load(IWICPersistStream *iface,
395 IStream *pStm)
396 {
397 MetadataHandler *This = impl_from_IWICPersistStream(iface);
398 TRACE("(%p,%p)\n", iface, pStm);
399 return IWICPersistStream_LoadEx(&This->IWICPersistStream_iface, pStm, NULL, WICPersistOptionsDefault);
400 }
401
402 static HRESULT WINAPI MetadataHandler_Save(IWICPersistStream *iface,
403 IStream *pStm, BOOL fClearDirty)
404 {
405 FIXME("(%p,%p,%i): stub\n", iface, pStm, fClearDirty);
406 return E_NOTIMPL;
407 }
408
409 static HRESULT WINAPI MetadataHandler_GetSizeMax(IWICPersistStream *iface,
410 ULARGE_INTEGER *pcbSize)
411 {
412 FIXME("(%p,%p): stub\n", iface, pcbSize);
413 return E_NOTIMPL;
414 }
415
416 static HRESULT WINAPI MetadataHandler_LoadEx(IWICPersistStream *iface,
417 IStream *pIStream, const GUID *pguidPreferredVendor, DWORD dwPersistOptions)
418 {
419 MetadataHandler *This = impl_from_IWICPersistStream(iface);
420 HRESULT hr;
421 MetadataItem *new_items=NULL;
422 DWORD item_count=0;
423
424 TRACE("(%p,%p,%s,%x)\n", iface, pIStream, debugstr_guid(pguidPreferredVendor), dwPersistOptions);
425
426 EnterCriticalSection(&This->lock);
427
428 hr = This->vtable->fnLoad(pIStream, pguidPreferredVendor, dwPersistOptions,
429 &new_items, &item_count);
430
431 if (SUCCEEDED(hr))
432 {
433 MetadataHandler_FreeItems(This);
434 This->items = new_items;
435 This->item_count = item_count;
436 }
437
438 LeaveCriticalSection(&This->lock);
439
440 return hr;
441 }
442
443 static HRESULT WINAPI MetadataHandler_SaveEx(IWICPersistStream *iface,
444 IStream *pIStream, DWORD dwPersistOptions, BOOL fClearDirty)
445 {
446 FIXME("(%p,%p,%x,%i): stub\n", iface, pIStream, dwPersistOptions, fClearDirty);
447 return E_NOTIMPL;
448 }
449
450 static const IWICPersistStreamVtbl MetadataHandler_PersistStream_Vtbl = {
451 MetadataHandler_PersistStream_QueryInterface,
452 MetadataHandler_PersistStream_AddRef,
453 MetadataHandler_PersistStream_Release,
454 MetadataHandler_GetClassID,
455 MetadataHandler_IsDirty,
456 MetadataHandler_Load,
457 MetadataHandler_Save,
458 MetadataHandler_GetSizeMax,
459 MetadataHandler_LoadEx,
460 MetadataHandler_SaveEx
461 };
462
463 HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv)
464 {
465 MetadataHandler *This;
466 HRESULT hr;
467
468 TRACE("%s\n", debugstr_guid(vtable->clsid));
469
470 *ppv = NULL;
471
472 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
473
474 This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandler));
475 if (!This) return E_OUTOFMEMORY;
476
477 This->IWICMetadataWriter_iface.lpVtbl = &MetadataHandler_Vtbl;
478 This->IWICPersistStream_iface.lpVtbl = &MetadataHandler_PersistStream_Vtbl;
479 This->ref = 1;
480 This->vtable = vtable;
481 This->items = NULL;
482 This->item_count = 0;
483
484 InitializeCriticalSection(&This->lock);
485 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MetadataHandler.lock");
486
487 hr = IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv);
488
489 IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface);
490
491 return hr;
492 }
493
494 typedef struct MetadataHandlerEnum {
495 IWICEnumMetadataItem IWICEnumMetadataItem_iface;
496 LONG ref;
497 MetadataHandler *parent;
498 DWORD index;
499 } MetadataHandlerEnum;
500
501 static inline MetadataHandlerEnum *impl_from_IWICEnumMetadataItem(IWICEnumMetadataItem *iface)
502 {
503 return CONTAINING_RECORD(iface, MetadataHandlerEnum, IWICEnumMetadataItem_iface);
504 }
505
506 static HRESULT WINAPI MetadataHandlerEnum_QueryInterface(IWICEnumMetadataItem *iface, REFIID iid,
507 void **ppv)
508 {
509 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
510 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
511
512 if (!ppv) return E_INVALIDARG;
513
514 if (IsEqualIID(&IID_IUnknown, iid) ||
515 IsEqualIID(&IID_IWICEnumMetadataItem, iid))
516 {
517 *ppv = &This->IWICEnumMetadataItem_iface;
518 }
519 else
520 {
521 *ppv = NULL;
522 return E_NOINTERFACE;
523 }
524
525 IUnknown_AddRef((IUnknown*)*ppv);
526 return S_OK;
527 }
528
529 static ULONG WINAPI MetadataHandlerEnum_AddRef(IWICEnumMetadataItem *iface)
530 {
531 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
532 ULONG ref = InterlockedIncrement(&This->ref);
533
534 TRACE("(%p) refcount=%u\n", iface, ref);
535
536 return ref;
537 }
538
539 static ULONG WINAPI MetadataHandlerEnum_Release(IWICEnumMetadataItem *iface)
540 {
541 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
542 ULONG ref = InterlockedDecrement(&This->ref);
543
544 TRACE("(%p) refcount=%u\n", iface, ref);
545
546 if (ref == 0)
547 {
548 IWICMetadataWriter_Release(&This->parent->IWICMetadataWriter_iface);
549 HeapFree(GetProcessHeap(), 0, This);
550 }
551
552 return ref;
553 }
554
555 static HRESULT WINAPI MetadataHandlerEnum_Next(IWICEnumMetadataItem *iface,
556 ULONG celt, PROPVARIANT *rgeltSchema, PROPVARIANT *rgeltId,
557 PROPVARIANT *rgeltValue, ULONG *pceltFetched)
558 {
559 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
560 ULONG new_index;
561 HRESULT hr=S_FALSE;
562 ULONG i;
563
564 TRACE("(%p,%i)\n", iface, celt);
565
566 EnterCriticalSection(&This->parent->lock);
567
568 if (This->index >= This->parent->item_count)
569 {
570 *pceltFetched = 0;
571 LeaveCriticalSection(&This->parent->lock);
572 return S_FALSE;
573 }
574
575 new_index = min(This->parent->item_count, This->index + celt);
576 *pceltFetched = new_index - This->index;
577
578 if (rgeltSchema)
579 {
580 for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
581 hr = PropVariantCopy(&rgeltSchema[i], &This->parent->items[i+This->index].schema);
582 }
583
584 for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
585 hr = PropVariantCopy(&rgeltId[i], &This->parent->items[i+This->index].id);
586
587 if (rgeltValue)
588 {
589 for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
590 hr = PropVariantCopy(&rgeltValue[i], &This->parent->items[i+This->index].value);
591 }
592
593 if (SUCCEEDED(hr))
594 {
595 This->index = new_index;
596 }
597
598 LeaveCriticalSection(&This->parent->lock);
599
600 return hr;
601 }
602
603 static HRESULT WINAPI MetadataHandlerEnum_Skip(IWICEnumMetadataItem *iface,
604 ULONG celt)
605 {
606 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
607
608 EnterCriticalSection(&This->parent->lock);
609
610 This->index += celt;
611
612 LeaveCriticalSection(&This->parent->lock);
613
614 return S_OK;
615 }
616
617 static HRESULT WINAPI MetadataHandlerEnum_Reset(IWICEnumMetadataItem *iface)
618 {
619 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
620
621 EnterCriticalSection(&This->parent->lock);
622
623 This->index = 0;
624
625 LeaveCriticalSection(&This->parent->lock);
626
627 return S_OK;
628 }
629
630 static HRESULT WINAPI MetadataHandlerEnum_Clone(IWICEnumMetadataItem *iface,
631 IWICEnumMetadataItem **ppIEnumMetadataItem)
632 {
633 MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
634 HRESULT hr;
635
636 EnterCriticalSection(&This->parent->lock);
637
638 hr = MetadataHandlerEnum_Create(This->parent, This->index, ppIEnumMetadataItem);
639
640 LeaveCriticalSection(&This->parent->lock);
641
642 return hr;
643 }
644
645 static const IWICEnumMetadataItemVtbl MetadataHandlerEnum_Vtbl = {
646 MetadataHandlerEnum_QueryInterface,
647 MetadataHandlerEnum_AddRef,
648 MetadataHandlerEnum_Release,
649 MetadataHandlerEnum_Next,
650 MetadataHandlerEnum_Skip,
651 MetadataHandlerEnum_Reset,
652 MetadataHandlerEnum_Clone
653 };
654
655 static HRESULT MetadataHandlerEnum_Create(MetadataHandler *parent, DWORD index,
656 IWICEnumMetadataItem **ppIEnumMetadataItem)
657 {
658 MetadataHandlerEnum *This;
659
660 if (!ppIEnumMetadataItem) return E_INVALIDARG;
661
662 *ppIEnumMetadataItem = NULL;
663
664 This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandlerEnum));
665 if (!This) return E_OUTOFMEMORY;
666
667 IWICMetadataWriter_AddRef(&parent->IWICMetadataWriter_iface);
668
669 This->IWICEnumMetadataItem_iface.lpVtbl = &MetadataHandlerEnum_Vtbl;
670 This->ref = 1;
671 This->parent = parent;
672 This->index = index;
673
674 *ppIEnumMetadataItem = &This->IWICEnumMetadataItem_iface;
675
676 return S_OK;
677 }
678
679 static HRESULT LoadUnknownMetadata(IStream *input, const GUID *preferred_vendor,
680 DWORD persist_options, MetadataItem **items, DWORD *item_count)
681 {
682 HRESULT hr;
683 MetadataItem *result;
684 STATSTG stat;
685 BYTE *data;
686 ULONG bytesread;
687
688 TRACE("\n");
689
690 hr = IStream_Stat(input, &stat, STATFLAG_NONAME);
691 if (FAILED(hr))
692 return hr;
693
694 data = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart);
695 if (!data) return E_OUTOFMEMORY;
696
697 hr = IStream_Read(input, data, stat.cbSize.QuadPart, &bytesread);
698 if (bytesread != stat.cbSize.QuadPart) hr = E_FAIL;
699 if (hr != S_OK)
700 {
701 HeapFree(GetProcessHeap(), 0, data);
702 return hr;
703 }
704
705 result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem));
706 if (!result)
707 {
708 HeapFree(GetProcessHeap(), 0, data);
709 return E_OUTOFMEMORY;
710 }
711
712 PropVariantInit(&result[0].schema);
713 PropVariantInit(&result[0].id);
714 PropVariantInit(&result[0].value);
715
716 result[0].value.vt = VT_BLOB;
717 result[0].value.u.blob.cbSize = bytesread;
718 result[0].value.u.blob.pBlobData = data;
719
720 *items = result;
721 *item_count = 1;
722
723 return S_OK;
724 }
725
726 static const MetadataHandlerVtbl UnknownMetadataReader_Vtbl = {
727 0,
728 &CLSID_WICUnknownMetadataReader,
729 LoadUnknownMetadata
730 };
731
732 HRESULT UnknownMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
733 {
734 return MetadataReader_Create(&UnknownMetadataReader_Vtbl, pUnkOuter, iid, ppv);
735 }
736
737 #define SWAP_USHORT(x) do { if (!native_byte_order) (x) = RtlUshortByteSwap(x); } while(0)
738 #define SWAP_ULONG(x) do { if (!native_byte_order) (x) = RtlUlongByteSwap(x); } while(0)
739 #define SWAP_ULONGLONG(x) do { if (!native_byte_order) (x) = RtlUlonglongByteSwap(x); } while(0)
740
741 struct IFD_entry
742 {
743 SHORT id;
744 SHORT type;
745 ULONG count;
746 LONG value;
747 };
748
749 #define IFD_BYTE 1
750 #define IFD_ASCII 2
751 #define IFD_SHORT 3
752 #define IFD_LONG 4
753 #define IFD_RATIONAL 5
754 #define IFD_SBYTE 6
755 #define IFD_UNDEFINED 7
756 #define IFD_SSHORT 8
757 #define IFD_SLONG 9
758 #define IFD_SRATIONAL 10
759 #define IFD_FLOAT 11
760 #define IFD_DOUBLE 12
761 #define IFD_IFD 13
762
763 static int tag_to_vt(SHORT tag)
764 {
765 static const int tag2vt[] =
766 {
767 VT_EMPTY, /* 0 */
768 VT_UI1, /* IFD_BYTE 1 */
769 VT_LPSTR, /* IFD_ASCII 2 */
770 VT_UI2, /* IFD_SHORT 3 */
771 VT_UI4, /* IFD_LONG 4 */
772 VT_UI8, /* IFD_RATIONAL 5 */
773 VT_I1, /* IFD_SBYTE 6 */
774 VT_BLOB, /* IFD_UNDEFINED 7 */
775 VT_I2, /* IFD_SSHORT 8 */
776 VT_I4, /* IFD_SLONG 9 */
777 VT_I8, /* IFD_SRATIONAL 10 */
778 VT_R4, /* IFD_FLOAT 11 */
779 VT_R8, /* IFD_DOUBLE 12 */
780 VT_BLOB, /* IFD_IFD 13 */
781 };
782 return (tag > 0 && tag <= 13) ? tag2vt[tag] : VT_BLOB;
783 }
784
785 static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry,
786 MetadataItem *item, BOOL native_byte_order)
787 {
788 ULONG count, value, i, bytesread;
789 SHORT type;
790 LARGE_INTEGER pos;
791 HRESULT hr;
792
793 item->schema.vt = VT_EMPTY;
794 item->id.vt = VT_UI2;
795 item->id.u.uiVal = entry->id;
796 SWAP_USHORT(item->id.u.uiVal);
797
798 count = entry->count;
799 SWAP_ULONG(count);
800 type = entry->type;
801 SWAP_USHORT(type);
802 item->value.vt = tag_to_vt(type);
803 value = entry->value;
804 SWAP_ULONG(value);
805
806 switch (type)
807 {
808 case IFD_BYTE:
809 case IFD_SBYTE:
810 if (!count) count = 1;
811
812 if (count <= 4)
813 {
814 const BYTE *data = (const BYTE *)&entry->value;
815
816 if (count == 1)
817 item->value.u.bVal = data[0];
818 else
819 {
820 item->value.vt |= VT_VECTOR;
821 item->value.u.caub.cElems = count;
822 item->value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, count);
823 memcpy(item->value.u.caub.pElems, data, count);
824 }
825 break;
826 }
827
828 item->value.vt |= VT_VECTOR;
829 item->value.u.caub.cElems = count;
830 item->value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, count);
831 if (!item->value.u.caub.pElems) return E_OUTOFMEMORY;
832
833 pos.QuadPart = value;
834 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
835 if (FAILED(hr))
836 {
837 HeapFree(GetProcessHeap(), 0, item->value.u.caub.pElems);
838 return hr;
839 }
840 hr = IStream_Read(input, item->value.u.caub.pElems, count, &bytesread);
841 if (bytesread != count) hr = E_FAIL;
842 if (hr != S_OK)
843 {
844 HeapFree(GetProcessHeap(), 0, item->value.u.caub.pElems);
845 return hr;
846 }
847 break;
848 case IFD_SHORT:
849 case IFD_SSHORT:
850 if (!count) count = 1;
851
852 if (count <= 2)
853 {
854 const SHORT *data = (const SHORT *)&entry->value;
855
856 if (count == 1)
857 {
858 item->value.u.uiVal = data[0];
859 SWAP_USHORT(item->value.u.uiVal);
860 }
861 else
862 {
863 item->value.vt |= VT_VECTOR;
864 item->value.u.caui.cElems = count;
865 item->value.u.caui.pElems = HeapAlloc(GetProcessHeap(), 0, count * 2);
866 memcpy(item->value.u.caui.pElems, data, count * 2);
867 for (i = 0; i < count; i++)
868 SWAP_USHORT(item->value.u.caui.pElems[i]);
869 }
870 break;
871 }
872
873 item->value.vt |= VT_VECTOR;
874 item->value.u.caui.cElems = count;
875 item->value.u.caui.pElems = HeapAlloc(GetProcessHeap(), 0, count * 2);
876 if (!item->value.u.caui.pElems) return E_OUTOFMEMORY;
877
878 pos.QuadPart = value;
879 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
880 if (FAILED(hr))
881 {
882 HeapFree(GetProcessHeap(), 0, item->value.u.caui.pElems);
883 return hr;
884 }
885 hr = IStream_Read(input, item->value.u.caui.pElems, count * 2, &bytesread);
886 if (bytesread != count * 2) hr = E_FAIL;
887 if (hr != S_OK)
888 {
889 HeapFree(GetProcessHeap(), 0, item->value.u.caui.pElems);
890 return hr;
891 }
892 for (i = 0; i < count; i++)
893 SWAP_USHORT(item->value.u.caui.pElems[i]);
894 break;
895 case IFD_LONG:
896 case IFD_SLONG:
897 case IFD_FLOAT:
898 if (!count) count = 1;
899
900 if (count == 1)
901 {
902 item->value.u.ulVal = value;
903 break;
904 }
905
906 item->value.vt |= VT_VECTOR;
907 item->value.u.caul.cElems = count;
908 item->value.u.caul.pElems = HeapAlloc(GetProcessHeap(), 0, count * 4);
909 if (!item->value.u.caul.pElems) return E_OUTOFMEMORY;
910
911 pos.QuadPart = value;
912 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
913 if (FAILED(hr))
914 {
915 HeapFree(GetProcessHeap(), 0, item->value.u.caul.pElems);
916 return hr;
917 }
918 hr = IStream_Read(input, item->value.u.caul.pElems, count * 4, &bytesread);
919 if (bytesread != count * 4) hr = E_FAIL;
920 if (hr != S_OK)
921 {
922 HeapFree(GetProcessHeap(), 0, item->value.u.caul.pElems);
923 return hr;
924 }
925 for (i = 0; i < count; i++)
926 SWAP_ULONG(item->value.u.caul.pElems[i]);
927 break;
928 case IFD_RATIONAL:
929 case IFD_SRATIONAL:
930 case IFD_DOUBLE:
931 if (!count)
932 {
933 FIXME("IFD field type %d, count 0\n", type);
934 item->value.vt = VT_EMPTY;
935 break;
936 }
937
938 if (count == 1)
939 {
940 ULONGLONG ull;
941
942 pos.QuadPart = value;
943 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
944 if (FAILED(hr)) return hr;
945
946 hr = IStream_Read(input, &ull, sizeof(ull), &bytesread);
947 if (bytesread != sizeof(ull)) hr = E_FAIL;
948 if (hr != S_OK) return hr;
949
950 item->value.u.uhVal.QuadPart = ull;
951
952 if (type == IFD_DOUBLE)
953 SWAP_ULONGLONG(item->value.u.uhVal.QuadPart);
954 else
955 {
956 SWAP_ULONG(item->value.u.uhVal.u.LowPart);
957 SWAP_ULONG(item->value.u.uhVal.u.HighPart);
958 }
959 break;
960 }
961 else
962 {
963 item->value.vt |= VT_VECTOR;
964 item->value.u.cauh.cElems = count;
965 item->value.u.cauh.pElems = HeapAlloc(GetProcessHeap(), 0, count * 8);
966 if (!item->value.u.cauh.pElems) return E_OUTOFMEMORY;
967
968 pos.QuadPart = value;
969 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
970 if (FAILED(hr))
971 {
972 HeapFree(GetProcessHeap(), 0, item->value.u.cauh.pElems);
973 return hr;
974 }
975 hr = IStream_Read(input, item->value.u.cauh.pElems, count * 8, &bytesread);
976 if (bytesread != count * 8) hr = E_FAIL;
977 if (hr != S_OK)
978 {
979 HeapFree(GetProcessHeap(), 0, item->value.u.cauh.pElems);
980 return hr;
981 }
982 for (i = 0; i < count; i++)
983 {
984 if (type == IFD_DOUBLE)
985 SWAP_ULONGLONG(item->value.u.cauh.pElems[i].QuadPart);
986 else
987 {
988 SWAP_ULONG(item->value.u.cauh.pElems[i].u.LowPart);
989 SWAP_ULONG(item->value.u.cauh.pElems[i].u.HighPart);
990 }
991 }
992 }
993 break;
994 case IFD_ASCII:
995 item->value.u.pszVal = HeapAlloc(GetProcessHeap(), 0, count + 1);
996 if (!item->value.u.pszVal) return E_OUTOFMEMORY;
997
998 if (count <= 4)
999 {
1000 const char *data = (const char *)&entry->value;
1001 memcpy(item->value.u.pszVal, data, count);
1002 item->value.u.pszVal[count] = 0;
1003 break;
1004 }
1005
1006 pos.QuadPart = value;
1007 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
1008 if (FAILED(hr))
1009 {
1010 HeapFree(GetProcessHeap(), 0, item->value.u.pszVal);
1011 return hr;
1012 }
1013 hr = IStream_Read(input, item->value.u.pszVal, count, &bytesread);
1014 if (bytesread != count) hr = E_FAIL;
1015 if (hr != S_OK)
1016 {
1017 HeapFree(GetProcessHeap(), 0, item->value.u.pszVal);
1018 return hr;
1019 }
1020 item->value.u.pszVal[count] = 0;
1021 break;
1022 case IFD_UNDEFINED:
1023 if (!count)
1024 {
1025 FIXME("IFD field type %d, count 0\n", type);
1026 item->value.vt = VT_EMPTY;
1027 break;
1028 }
1029
1030 item->value.u.blob.pBlobData = HeapAlloc(GetProcessHeap(), 0, count);
1031 if (!item->value.u.blob.pBlobData) return E_OUTOFMEMORY;
1032
1033 item->value.u.blob.cbSize = count;
1034
1035 if (count <= 4)
1036 {
1037 const char *data = (const char *)&entry->value;
1038 memcpy(item->value.u.blob.pBlobData, data, count);
1039 break;
1040 }
1041
1042 pos.QuadPart = value;
1043 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
1044 if (FAILED(hr))
1045 {
1046 HeapFree(GetProcessHeap(), 0, item->value.u.blob.pBlobData);
1047 return hr;
1048 }
1049 hr = IStream_Read(input, item->value.u.blob.pBlobData, count, &bytesread);
1050 if (bytesread != count) hr = E_FAIL;
1051 if (hr != S_OK)
1052 {
1053 HeapFree(GetProcessHeap(), 0, item->value.u.blob.pBlobData);
1054 return hr;
1055 }
1056 break;
1057 default:
1058 FIXME("loading field of type %d, count %u is not implemented\n", type, count);
1059 break;
1060 }
1061 return S_OK;
1062 }
1063
1064 static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor,
1065 DWORD persist_options, MetadataItem **items, DWORD *item_count)
1066 {
1067 HRESULT hr;
1068 MetadataItem *result;
1069 USHORT count, i;
1070 struct IFD_entry *entry;
1071 BOOL native_byte_order = TRUE;
1072 ULONG bytesread;
1073
1074 TRACE("\n");
1075
1076 #ifdef WORDS_BIGENDIAN
1077 if (persist_options & WICPersistOptionsLittleEndian)
1078 #else
1079 if (persist_options & WICPersistOptionsBigEndian)
1080 #endif
1081 native_byte_order = FALSE;
1082
1083 hr = IStream_Read(input, &count, sizeof(count), &bytesread);
1084 if (bytesread != sizeof(count)) hr = E_FAIL;
1085 if (hr != S_OK) return hr;
1086
1087 SWAP_USHORT(count);
1088
1089 entry = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*entry));
1090 if (!entry) return E_OUTOFMEMORY;
1091
1092 hr = IStream_Read(input, entry, count * sizeof(*entry), &bytesread);
1093 if (bytesread != count * sizeof(*entry)) hr = E_FAIL;
1094 if (hr != S_OK)
1095 {
1096 HeapFree(GetProcessHeap(), 0, entry);
1097 return hr;
1098 }
1099
1100 /* limit number of IFDs to 4096 to avoid infinite loop */
1101 for (i = 0; i < 4096; i++)
1102 {
1103 ULONG next_ifd_offset;
1104 LARGE_INTEGER pos;
1105 USHORT next_ifd_count;
1106
1107 hr = IStream_Read(input, &next_ifd_offset, sizeof(next_ifd_offset), &bytesread);
1108 if (bytesread != sizeof(next_ifd_offset)) hr = E_FAIL;
1109 if (hr != S_OK) break;
1110
1111 SWAP_ULONG(next_ifd_offset);
1112 if (!next_ifd_offset) break;
1113
1114 pos.QuadPart = next_ifd_offset;
1115 hr = IStream_Seek(input, pos, SEEK_SET, NULL);
1116 if (FAILED(hr)) break;
1117
1118 hr = IStream_Read(input, &next_ifd_count, sizeof(next_ifd_count), &bytesread);
1119 if (bytesread != sizeof(next_ifd_count)) hr = E_FAIL;
1120 if (hr != S_OK) break;
1121
1122 SWAP_USHORT(next_ifd_count);
1123
1124 pos.QuadPart = next_ifd_count * sizeof(*entry);
1125 hr = IStream_Seek(input, pos, SEEK_CUR, NULL);
1126 if (FAILED(hr)) break;
1127 }
1128
1129 if (hr != S_OK || i == 4096)
1130 {
1131 HeapFree(GetProcessHeap(), 0, entry);
1132 return WINCODEC_ERR_BADMETADATAHEADER;
1133 }
1134
1135 result = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*result));
1136 if (!result)
1137 {
1138 HeapFree(GetProcessHeap(), 0, entry);
1139 return E_OUTOFMEMORY;
1140 }
1141
1142 for (i = 0; i < count; i++)
1143 {
1144 hr = load_IFD_entry(input, &entry[i], &result[i], native_byte_order);
1145 if (FAILED(hr))
1146 {
1147 HeapFree(GetProcessHeap(), 0, entry);
1148 HeapFree(GetProcessHeap(), 0, result);
1149 return hr;
1150 }
1151 }
1152
1153 HeapFree(GetProcessHeap(), 0, entry);
1154
1155 *items = result;
1156 *item_count = count;
1157
1158 return S_OK;
1159 }
1160
1161 static const MetadataHandlerVtbl IfdMetadataReader_Vtbl = {
1162 0,
1163 &CLSID_WICIfdMetadataReader,
1164 LoadIfdMetadata
1165 };
1166
1167 HRESULT IfdMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
1168 {
1169 return MetadataReader_Create(&IfdMetadataReader_Vtbl, pUnkOuter, iid, ppv);
1170 }