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