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 47 static inline MetadataHandler *impl_from_IWICMetadataWriter(IWICMetadataWriter *iface) 48 { 49 return CONTAINING_RECORD(iface, MetadataHandler, IWICMetadataWriter_iface); 50 } 51 52 static inline MetadataHandler *impl_from_IWICPersistStream(IWICPersistStream *iface) 53 { 54 return CONTAINING_RECORD(iface, MetadataHandler, IWICPersistStream_iface); 55 } 56 57 static inline MetadataHandler *impl_from_IWICStreamProvider(IWICStreamProvider *iface) 58 { 59 return CONTAINING_RECORD(iface, MetadataHandler, IWICStreamProvider_iface); 60 } 61 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 331 static HRESULT WINAPI MetadataHandler_IsDirty(IWICPersistStream *iface) 332 { 333 FIXME("(%p): stub\n", iface); 334 return E_NOTIMPL; 335 } 336 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 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 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 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 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 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 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 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 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 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 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 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 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 507 static inline MetadataHandlerEnum *impl_from_IWICEnumMetadataItem(IWICEnumMetadataItem *iface) 508 { 509 return CONTAINING_RECORD(iface, MetadataHandlerEnum, IWICEnumMetadataItem_iface); 510 } 511 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 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 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 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 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 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 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 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 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 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 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 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 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 1177 HRESULT IfdMetadataReader_CreateInstance(REFIID iid, void **ppv) 1178 { 1179 return MetadataReader_Create(&IfdMetadataReader_Vtbl, iid, ppv); 1180 } 1181 1182