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