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