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