d3drm: Implement IDirect3DRMMesh_GetClassName.
[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_GetMetadataFormat(IWICMetadataWriter *iface,
137     GUID *pguidMetadataFormat)
138 {
139     if (!pguidMetadataFormat) return E_INVALIDARG;
140
141     FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidMetadataFormat));
142     return E_NOTIMPL;
143 }
144
145 static HRESULT WINAPI MetadataHandler_GetMetadataHandlerInfo(IWICMetadataWriter *iface,
146     IWICMetadataHandlerInfo **ppIHandler)
147 {
148     FIXME("(%p,%p): stub\n", iface, ppIHandler);
149     return E_NOTIMPL;
150 }
151
152 static HRESULT WINAPI MetadataHandler_GetCount(IWICMetadataWriter *iface,
153     UINT *pcCount)
154 {
155     MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
156
157     TRACE("%p,%p\n", iface, pcCount);
158
159     if (!pcCount) return E_INVALIDARG;
160
161     *pcCount = This->item_count;
162     return S_OK;
163 }
164
165 static HRESULT WINAPI MetadataHandler_GetValueByIndex(IWICMetadataWriter *iface,
166     UINT nIndex, PROPVARIANT *pvarSchema, PROPVARIANT *pvarId, PROPVARIANT *pvarValue)
167 {
168     FIXME("(%p,%u,%p,%p,%p): stub\n", iface, nIndex, pvarSchema, pvarId, pvarValue);
169     return E_NOTIMPL;
170 }
171
172 static HRESULT WINAPI MetadataHandler_GetValue(IWICMetadataWriter *iface,
173     const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, PROPVARIANT *pvarValue)
174 {
175     FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue);
176     return E_NOTIMPL;
177 }
178
179 static HRESULT WINAPI MetadataHandler_GetEnumerator(IWICMetadataWriter *iface,
180     IWICEnumMetadataItem **ppIEnumMetadata)
181 {
182     MetadataHandler *This = impl_from_IWICMetadataWriter(iface);
183     TRACE("(%p,%p)\n", iface, ppIEnumMetadata);
184     return MetadataHandlerEnum_Create(This, 0, ppIEnumMetadata);
185 }
186
187 static HRESULT WINAPI MetadataHandler_SetValue(IWICMetadataWriter *iface,
188     const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue)
189 {
190     FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue);
191     return E_NOTIMPL;
192 }
193
194 static HRESULT WINAPI MetadataHandler_SetValueByIndex(IWICMetadataWriter *iface,
195     UINT nIndex, const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue)
196 {
197     FIXME("(%p,%u,%p,%p,%p): stub\n", iface, nIndex, pvarSchema, pvarId, pvarValue);
198     return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI MetadataHandler_RemoveValue(IWICMetadataWriter *iface,
202     const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId)
203 {
204     FIXME("(%p,%p,%p): stub\n", iface, pvarSchema, pvarId);
205     return E_NOTIMPL;
206 }
207
208 static HRESULT WINAPI MetadataHandler_RemoveValueByIndex(IWICMetadataWriter *iface,
209     UINT nIndex)
210 {
211     FIXME("(%p,%u): stub\n", iface, nIndex);
212     return E_NOTIMPL;
213 }
214
215 static const IWICMetadataWriterVtbl MetadataHandler_Vtbl = {
216     MetadataHandler_QueryInterface,
217     MetadataHandler_AddRef,
218     MetadataHandler_Release,
219     MetadataHandler_GetMetadataFormat,
220     MetadataHandler_GetMetadataHandlerInfo,
221     MetadataHandler_GetCount,
222     MetadataHandler_GetValueByIndex,
223     MetadataHandler_GetValue,
224     MetadataHandler_GetEnumerator,
225     MetadataHandler_SetValue,
226     MetadataHandler_SetValueByIndex,
227     MetadataHandler_RemoveValue,
228     MetadataHandler_RemoveValueByIndex
229 };
230
231 static HRESULT WINAPI MetadataHandler_PersistStream_QueryInterface(IWICPersistStream *iface,
232     REFIID iid, void **ppv)
233 {
234     MetadataHandler *This = impl_from_IWICPersistStream(iface);
235     return IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv);
236 }
237
238 static ULONG WINAPI MetadataHandler_PersistStream_AddRef(IWICPersistStream *iface)
239 {
240     MetadataHandler *This = impl_from_IWICPersistStream(iface);
241     return IWICMetadataWriter_AddRef(&This->IWICMetadataWriter_iface);
242 }
243
244 static ULONG WINAPI MetadataHandler_PersistStream_Release(IWICPersistStream *iface)
245 {
246     MetadataHandler *This = impl_from_IWICPersistStream(iface);
247     return IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface);
248 }
249
250 static HRESULT WINAPI MetadataHandler_GetClassID(IWICPersistStream *iface,
251     CLSID *pClassID)
252 {
253     FIXME("(%p,%p): stub\n", iface, pClassID);
254     return E_NOTIMPL;
255 }
256
257 static HRESULT WINAPI MetadataHandler_IsDirty(IWICPersistStream *iface)
258 {
259     FIXME("(%p): stub\n", iface);
260     return E_NOTIMPL;
261 }
262
263 static HRESULT WINAPI MetadataHandler_Load(IWICPersistStream *iface,
264     IStream *pStm)
265 {
266     FIXME("(%p,%p): stub\n", iface, pStm);
267     return E_NOTIMPL;
268 }
269
270 static HRESULT WINAPI MetadataHandler_Save(IWICPersistStream *iface,
271     IStream *pStm, BOOL fClearDirty)
272 {
273     FIXME("(%p,%p,%i): stub\n", iface, pStm, fClearDirty);
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI MetadataHandler_GetSizeMax(IWICPersistStream *iface,
278     ULARGE_INTEGER *pcbSize)
279 {
280     FIXME("(%p,%p): stub\n", iface, pcbSize);
281     return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI MetadataHandler_LoadEx(IWICPersistStream *iface,
285     IStream *pIStream, const GUID *pguidPreferredVendor, DWORD dwPersistOptions)
286 {
287     MetadataHandler *This = impl_from_IWICPersistStream(iface);
288     HRESULT hr;
289     MetadataItem *new_items=NULL;
290     DWORD item_count=0;
291
292     TRACE("(%p,%p,%s,%x)\n", iface, pIStream, debugstr_guid(pguidPreferredVendor), dwPersistOptions);
293
294     EnterCriticalSection(&This->lock);
295
296     hr = This->vtable->fnLoad(pIStream, pguidPreferredVendor, dwPersistOptions,
297         &new_items, &item_count);
298
299     if (SUCCEEDED(hr))
300     {
301         MetadataHandler_FreeItems(This);
302         This->items = new_items;
303         This->item_count = item_count;
304     }
305
306     LeaveCriticalSection(&This->lock);
307
308     return hr;
309 }
310
311 static HRESULT WINAPI MetadataHandler_SaveEx(IWICPersistStream *iface,
312     IStream *pIStream, DWORD dwPersistOptions, BOOL fClearDirty)
313 {
314     FIXME("(%p,%p,%x,%i): stub\n", iface, pIStream, dwPersistOptions, fClearDirty);
315     return E_NOTIMPL;
316 }
317
318 static const IWICPersistStreamVtbl MetadataHandler_PersistStream_Vtbl = {
319     MetadataHandler_PersistStream_QueryInterface,
320     MetadataHandler_PersistStream_AddRef,
321     MetadataHandler_PersistStream_Release,
322     MetadataHandler_GetClassID,
323     MetadataHandler_IsDirty,
324     MetadataHandler_Load,
325     MetadataHandler_Save,
326     MetadataHandler_GetSizeMax,
327     MetadataHandler_LoadEx,
328     MetadataHandler_SaveEx
329 };
330
331 static HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv)
332 {
333     MetadataHandler *This;
334     HRESULT hr;
335
336     TRACE("%s\n", debugstr_guid(vtable->clsid));
337
338     *ppv = NULL;
339
340     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
341
342     This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandler));
343     if (!This) return E_OUTOFMEMORY;
344
345     This->IWICMetadataWriter_iface.lpVtbl = &MetadataHandler_Vtbl;
346     This->IWICPersistStream_iface.lpVtbl = &MetadataHandler_PersistStream_Vtbl;
347     This->ref = 1;
348     This->vtable = vtable;
349     This->items = NULL;
350     This->item_count = 0;
351
352     InitializeCriticalSection(&This->lock);
353     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MetadataHandler.lock");
354
355     hr = IWICMetadataWriter_QueryInterface(&This->IWICMetadataWriter_iface, iid, ppv);
356
357     IWICMetadataWriter_Release(&This->IWICMetadataWriter_iface);
358
359     return hr;
360 }
361
362 typedef struct MetadataHandlerEnum {
363     IWICEnumMetadataItem IWICEnumMetadataItem_iface;
364     LONG ref;
365     MetadataHandler *parent;
366     DWORD index;
367 } MetadataHandlerEnum;
368
369 static inline MetadataHandlerEnum *impl_from_IWICEnumMetadataItem(IWICEnumMetadataItem *iface)
370 {
371     return CONTAINING_RECORD(iface, MetadataHandlerEnum, IWICEnumMetadataItem_iface);
372 }
373
374 static HRESULT WINAPI MetadataHandlerEnum_QueryInterface(IWICEnumMetadataItem *iface, REFIID iid,
375     void **ppv)
376 {
377     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
378     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
379
380     if (!ppv) return E_INVALIDARG;
381
382     if (IsEqualIID(&IID_IUnknown, iid) ||
383         IsEqualIID(&IID_IWICEnumMetadataItem, iid))
384     {
385         *ppv = &This->IWICEnumMetadataItem_iface;
386     }
387     else
388     {
389         *ppv = NULL;
390         return E_NOINTERFACE;
391     }
392
393     IUnknown_AddRef((IUnknown*)*ppv);
394     return S_OK;
395 }
396
397 static ULONG WINAPI MetadataHandlerEnum_AddRef(IWICEnumMetadataItem *iface)
398 {
399     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
400     ULONG ref = InterlockedIncrement(&This->ref);
401
402     TRACE("(%p) refcount=%u\n", iface, ref);
403
404     return ref;
405 }
406
407 static ULONG WINAPI MetadataHandlerEnum_Release(IWICEnumMetadataItem *iface)
408 {
409     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
410     ULONG ref = InterlockedDecrement(&This->ref);
411
412     TRACE("(%p) refcount=%u\n", iface, ref);
413
414     if (ref == 0)
415     {
416         IWICMetadataWriter_Release(&This->parent->IWICMetadataWriter_iface);
417         HeapFree(GetProcessHeap(), 0, This);
418     }
419
420     return ref;
421 }
422
423 static HRESULT WINAPI MetadataHandlerEnum_Next(IWICEnumMetadataItem *iface,
424     ULONG celt, PROPVARIANT *rgeltSchema, PROPVARIANT *rgeltId,
425     PROPVARIANT *rgeltValue, ULONG *pceltFetched)
426 {
427     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
428     ULONG new_index;
429     HRESULT hr=S_FALSE;
430     int i;
431
432     TRACE("(%p,%i)\n", iface, celt);
433
434     EnterCriticalSection(&This->parent->lock);
435
436     if (This->index >= This->parent->item_count)
437     {
438         *pceltFetched = 0;
439         LeaveCriticalSection(&This->parent->lock);
440         return S_FALSE;
441     }
442
443     new_index = min(This->parent->item_count, This->index + celt);
444     *pceltFetched = new_index - This->index;
445
446     if (rgeltSchema)
447     {
448         for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
449             hr = PropVariantCopy(&rgeltSchema[i], &This->parent->items[i+This->index].schema);
450     }
451
452     for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
453         hr = PropVariantCopy(&rgeltId[i], &This->parent->items[i+This->index].id);
454
455     if (rgeltValue)
456     {
457         for (i=0; SUCCEEDED(hr) && i < *pceltFetched; i++)
458             hr = PropVariantCopy(&rgeltValue[i], &This->parent->items[i+This->index].value);
459     }
460
461     if (SUCCEEDED(hr))
462     {
463         This->index = new_index;
464     }
465
466     LeaveCriticalSection(&This->parent->lock);
467
468     return hr;
469 }
470
471 static HRESULT WINAPI MetadataHandlerEnum_Skip(IWICEnumMetadataItem *iface,
472     ULONG celt)
473 {
474     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
475
476     EnterCriticalSection(&This->parent->lock);
477
478     This->index += celt;
479
480     LeaveCriticalSection(&This->parent->lock);
481
482     return S_OK;
483 }
484
485 static HRESULT WINAPI MetadataHandlerEnum_Reset(IWICEnumMetadataItem *iface)
486 {
487     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
488
489     EnterCriticalSection(&This->parent->lock);
490
491     This->index = 0;
492
493     LeaveCriticalSection(&This->parent->lock);
494
495     return S_OK;
496 }
497
498 static HRESULT WINAPI MetadataHandlerEnum_Clone(IWICEnumMetadataItem *iface,
499     IWICEnumMetadataItem **ppIEnumMetadataItem)
500 {
501     MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
502     HRESULT hr;
503
504     EnterCriticalSection(&This->parent->lock);
505
506     hr = MetadataHandlerEnum_Create(This->parent, This->index, ppIEnumMetadataItem);
507
508     LeaveCriticalSection(&This->parent->lock);
509
510     return hr;
511 }
512
513 static const IWICEnumMetadataItemVtbl MetadataHandlerEnum_Vtbl = {
514     MetadataHandlerEnum_QueryInterface,
515     MetadataHandlerEnum_AddRef,
516     MetadataHandlerEnum_Release,
517     MetadataHandlerEnum_Next,
518     MetadataHandlerEnum_Skip,
519     MetadataHandlerEnum_Reset,
520     MetadataHandlerEnum_Clone
521 };
522
523 static HRESULT MetadataHandlerEnum_Create(MetadataHandler *parent, DWORD index,
524     IWICEnumMetadataItem **ppIEnumMetadataItem)
525 {
526     MetadataHandlerEnum *This;
527
528     if (!ppIEnumMetadataItem) return E_INVALIDARG;
529
530     *ppIEnumMetadataItem = NULL;
531
532     This = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataHandlerEnum));
533     if (!This) return E_OUTOFMEMORY;
534
535     IWICMetadataWriter_AddRef(&parent->IWICMetadataWriter_iface);
536
537     This->IWICEnumMetadataItem_iface.lpVtbl = &MetadataHandlerEnum_Vtbl;
538     This->ref = 1;
539     This->parent = parent;
540     This->index = index;
541
542     *ppIEnumMetadataItem = &This->IWICEnumMetadataItem_iface;
543
544     return S_OK;
545 }
546
547 static HRESULT LoadUnknownMetadata(IStream *input, const GUID *preferred_vendor,
548     DWORD persist_options, MetadataItem **items, DWORD *item_count)
549 {
550     HRESULT hr;
551     MetadataItem *result;
552     STATSTG stat;
553     BYTE *data;
554     ULONG bytesread;
555
556     TRACE("\n");
557
558     hr = IStream_Stat(input, &stat, STATFLAG_NONAME);
559     if (FAILED(hr))
560         return hr;
561
562     data = HeapAlloc(GetProcessHeap(), 0, stat.cbSize.QuadPart);
563     if (!data) return E_OUTOFMEMORY;
564
565     hr = IStream_Read(input, data, stat.cbSize.QuadPart, &bytesread);
566     if (FAILED(hr))
567     {
568         HeapFree(GetProcessHeap(), 0, data);
569         return hr;
570     }
571
572     result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem));
573     if (!result)
574     {
575         HeapFree(GetProcessHeap(), 0, data);
576         return E_OUTOFMEMORY;
577     }
578
579     PropVariantInit(&result[0].schema);
580     PropVariantInit(&result[0].id);
581     PropVariantInit(&result[0].value);
582
583     result[0].value.vt = VT_BLOB;
584     result[0].value.u.blob.cbSize = bytesread;
585     result[0].value.u.blob.pBlobData = data;
586
587     *items = result;
588     *item_count = 1;
589
590     return S_OK;
591 }
592
593 static const MetadataHandlerVtbl UnknownMetadataReader_Vtbl = {
594     0,
595     &CLSID_WICUnknownMetadataReader,
596     LoadUnknownMetadata
597 };
598
599 HRESULT UnknownMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
600 {
601     return MetadataReader_Create(&UnknownMetadataReader_Vtbl, pUnkOuter, iid, ppv);
602 }
603
604 #define SWAP_USHORT(x) do { if (!native_byte_order) (x) = RtlUshortByteSwap(x); } while(0)
605 #define SWAP_ULONG(x) do { if (!native_byte_order) (x) = RtlUlongByteSwap(x); } while(0)
606 #define SWAP_ULONGLONG(x) do { if (!native_byte_order) (x) = RtlUlonglongByteSwap(x); } while(0)
607
608 #include "pshpack2.h"
609 struct IFD_entry
610 {
611     SHORT id;
612     SHORT type;
613     ULONG count;
614     LONG  value;
615 };
616
617 struct IFD_rational
618 {
619     LONG numerator;
620     LONG denominator;
621 };
622 #include "poppack.h"
623
624 #define IFD_BYTE 1
625 #define IFD_ASCII 2
626 #define IFD_SHORT 3
627 #define IFD_LONG 4
628 #define IFD_RATIONAL 5
629 #define IFD_SBYTE 6
630 #define IFD_UNDEFINED 7
631 #define IFD_SSHORT 8
632 #define IFD_SLONG 9
633 #define IFD_SRATIONAL 10
634 #define IFD_FLOAT 11
635 #define IFD_DOUBLE 12
636 #define IFD_IFD 13
637
638 static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry,
639                               MetadataItem *item, BOOL native_byte_order)
640 {
641     ULONG count, value;
642     SHORT type;
643
644     item->schema.vt = VT_EMPTY;
645     item->id.vt = VT_UI2;
646     item->id.u.uiVal = entry->id;
647     SWAP_USHORT(item->id.u.uiVal);
648
649     count = entry->count;
650     SWAP_ULONG(count);
651     type = entry->type;
652     SWAP_USHORT(type);
653     value = entry->value;
654     SWAP_ULONG(value);
655
656     switch (type)
657     {
658     case IFD_SHORT:
659         if (count == 1)
660         {
661             item->value.vt = VT_UI2;
662             item->value.u.uiVal = value;
663             break;
664         }
665         FIXME("loading multiple short fields is not implemented\n");
666         break;
667     case IFD_LONG:
668         if (count == 1)
669         {
670             item->value.vt = VT_UI4;
671             item->value.u.ulVal = value;
672             break;
673         }
674         FIXME("loading multiple long fields is not implemented\n");
675         break;
676     case IFD_RATIONAL:
677         if (count == 1)
678         {
679             HRESULT hr;
680             LARGE_INTEGER pos;
681             struct IFD_rational rational;
682
683             pos.QuadPart = value;
684             hr = IStream_Seek(input, pos, SEEK_SET, NULL);
685             if (FAILED(hr)) return hr;
686
687             item->value.vt = VT_UI8;
688             hr = IStream_Read(input, &rational, sizeof(rational), NULL);
689             if (FAILED(hr)) return hr;
690             item->value.u.uhVal.QuadPart = ((LONGLONG)rational.denominator << 32) | rational.numerator;
691             SWAP_ULONGLONG(item->value.u.uhVal.QuadPart);
692             break;
693         }
694         FIXME("loading multiple rational fields is not implemented\n");
695         break;
696     default:
697         FIXME("loading field of type %d is not implemented\n", entry->type);
698         break;
699     }
700     return S_OK;
701 }
702
703 static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor,
704     DWORD persist_options, MetadataItem **items, DWORD *item_count)
705 {
706     HRESULT hr;
707     MetadataItem *result;
708     USHORT count, i;
709     struct IFD_entry *entry;
710     BOOL native_byte_order = TRUE;
711
712     TRACE("\n");
713
714 #ifdef WORDS_BIGENDIAN
715     if (persist_options & WICPersistOptionsLittleEndian)
716 #else
717     if (persist_options & WICPersistOptionsBigEndian)
718 #endif
719         native_byte_order = FALSE;
720
721     hr = IStream_Read(input, &count, sizeof(count), NULL);
722     if (FAILED(hr)) return hr;
723
724     SWAP_USHORT(count);
725
726     entry = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*entry));
727     if (!entry) return E_OUTOFMEMORY;
728
729     hr = IStream_Read(input, entry, count * sizeof(*entry), NULL);
730     if (FAILED(hr))
731     {
732         HeapFree(GetProcessHeap(), 0, entry);
733         return hr;
734     }
735
736     /* limit number of IFDs to 4096 to avoid infinite loop */
737     for (i = 0; i < 4096; i++)
738     {
739         ULONG next_ifd_offset;
740         LARGE_INTEGER pos;
741         USHORT next_ifd_count;
742
743         hr = IStream_Read(input, &next_ifd_offset, sizeof(next_ifd_offset), NULL);
744         if (FAILED(hr)) break;
745
746         SWAP_ULONG(next_ifd_offset);
747         if (!next_ifd_offset) break;
748
749         pos.QuadPart = next_ifd_offset;
750         hr = IStream_Seek(input, pos, SEEK_SET, NULL);
751         if (FAILED(hr)) break;
752
753         hr = IStream_Read(input, &next_ifd_count, sizeof(next_ifd_count), NULL);
754         if (FAILED(hr)) break;
755
756         SWAP_USHORT(next_ifd_count);
757
758         pos.QuadPart = next_ifd_count * sizeof(*entry);
759         hr = IStream_Seek(input, pos, SEEK_CUR, NULL);
760         if (FAILED(hr)) break;
761     }
762
763     if (FAILED(hr) || i == 4096)
764     {
765         HeapFree(GetProcessHeap(), 0, entry);
766         return WINCODEC_ERR_BADMETADATAHEADER;
767     }
768
769     result = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*result));
770     if (!result)
771     {
772         HeapFree(GetProcessHeap(), 0, entry);
773         return E_OUTOFMEMORY;
774     }
775
776     for (i = 0; i < count; i++)
777     {
778         hr = load_IFD_entry(input, &entry[i], &result[i], native_byte_order);
779         if (FAILED(hr))
780         {
781             HeapFree(GetProcessHeap(), 0, entry);
782             HeapFree(GetProcessHeap(), 0, result);
783             return hr;
784         }
785     }
786
787     HeapFree(GetProcessHeap(), 0, entry);
788
789     *items = result;
790     *item_count = count;
791
792     return S_OK;
793 }
794
795 static const MetadataHandlerVtbl IfdMetadataReader_Vtbl = {
796     0,
797     &CLSID_WICIfdMetadataReader,
798     LoadIfdMetadata
799 };
800
801 HRESULT IfdMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
802 {
803     return MetadataReader_Create(&IfdMetadataReader_Vtbl, pUnkOuter, iid, ppv);
804 }