1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "config.h" 20 21 #include <stdarg.h> 22 23 #define COBJMACROS 24 25 #include "windef.h" 26 #include "winbase.h" 27 #include "wingdi.h" 28 #include "objbase.h" 29 30 #include "wincodecs_private.h" 31 32 #include "wine/debug.h" 33 34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 35 36 #include "pshpack1.h" 37 38 typedef struct { 39 BYTE bWidth; 40 BYTE bHeight; 41 BYTE bColorCount; 42 BYTE bReserved; 43 WORD wPlanes; 44 WORD wBitCount; 45 DWORD dwDIBSize; 46 DWORD dwDIBOffset; 47 } ICONDIRENTRY; 48 49 typedef struct 50 { 51 WORD idReserved; 52 WORD idType; 53 WORD idCount; 54 } ICONHEADER; 55 56 #include "poppack.h" 57 58 typedef struct { 59 IWICBitmapDecoder IWICBitmapDecoder_iface; 60 LONG ref; 61 BOOL initialized; 62 IStream *stream; 63 ICONHEADER header; 64 CRITICAL_SECTION lock; /* must be held when accessing stream */ 65 } IcoDecoder; 66 67 typedef struct { 68 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 69 LONG ref; 70 UINT width, height; 71 double dpiX, dpiY; 72 BYTE *bits; 73 } IcoFrameDecode; 74 75 static inline IcoDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 76 { 77 return CONTAINING_RECORD(iface, IcoDecoder, IWICBitmapDecoder_iface); 78 } 79 80 static inline IcoFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 81 { 82 return CONTAINING_RECORD(iface, IcoFrameDecode, IWICBitmapFrameDecode_iface); 83 } 84 85 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 86 void **ppv) 87 { 88 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 89 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 90 91 if (!ppv) return E_INVALIDARG; 92 93 if (IsEqualIID(&IID_IUnknown, iid) || 94 IsEqualIID(&IID_IWICBitmapSource, iid) || 95 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 96 { 97 *ppv = &This->IWICBitmapFrameDecode_iface; 98 } 99 else 100 { 101 *ppv = NULL; 102 return E_NOINTERFACE; 103 } 104 105 IUnknown_AddRef((IUnknown*)*ppv); 106 return S_OK; 107 } 108 109 static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 110 { 111 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 112 ULONG ref = InterlockedIncrement(&This->ref); 113 114 TRACE("(%p) refcount=%u\n", iface, ref); 115 116 return ref; 117 } 118 119 static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface) 120 { 121 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 122 ULONG ref = InterlockedDecrement(&This->ref); 123 124 TRACE("(%p) refcount=%u\n", iface, ref); 125 126 if (ref == 0) 127 { 128 HeapFree(GetProcessHeap(), 0, This->bits); 129 HeapFree(GetProcessHeap(), 0, This); 130 } 131 132 return ref; 133 } 134 135 static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 136 UINT *puiWidth, UINT *puiHeight) 137 { 138 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 139 140 *puiWidth = This->width; 141 *puiHeight = This->height; 142 143 TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight); 144 145 return S_OK; 146 } 147 148 static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 149 WICPixelFormatGUID *pPixelFormat) 150 { 151 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)); 152 return S_OK; 153 } 154 155 static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 156 double *pDpiX, double *pDpiY) 157 { 158 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 159 160 *pDpiX = This->dpiX; 161 *pDpiY = This->dpiY; 162 163 TRACE("(%p) -> (%f,%f)\n", iface, *pDpiX, *pDpiY); 164 165 return S_OK; 166 } 167 168 static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 169 IWICPalette *pIPalette) 170 { 171 TRACE("(%p,%p)\n", iface, pIPalette); 172 return WINCODEC_ERR_PALETTEUNAVAILABLE; 173 } 174 175 static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 176 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 177 { 178 IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 179 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 180 181 return copy_pixels(32, This->bits, This->width, This->height, This->width * 4, 182 prc, cbStride, cbBufferSize, pbBuffer); 183 } 184 185 static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 186 IWICMetadataQueryReader **ppIMetadataQueryReader) 187 { 188 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 189 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 190 } 191 192 static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 193 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 194 { 195 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 196 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 197 } 198 199 static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 200 IWICBitmapSource **ppIThumbnail) 201 { 202 TRACE("(%p,%p)\n", iface, ppIThumbnail); 203 return IWICBitmapFrameDecode_QueryInterface(iface, &IID_IWICBitmapSource, (void **)ppIThumbnail); 204 } 205 206 static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = { 207 IcoFrameDecode_QueryInterface, 208 IcoFrameDecode_AddRef, 209 IcoFrameDecode_Release, 210 IcoFrameDecode_GetSize, 211 IcoFrameDecode_GetPixelFormat, 212 IcoFrameDecode_GetResolution, 213 IcoFrameDecode_CopyPalette, 214 IcoFrameDecode_CopyPixels, 215 IcoFrameDecode_GetMetadataQueryReader, 216 IcoFrameDecode_GetColorContexts, 217 IcoFrameDecode_GetThumbnail 218 }; 219 220 static inline void pixel_set_trans(DWORD* pixel, BOOL transparent) 221 { 222 if (transparent) *pixel = 0; 223 else *pixel |= 0xff000000; 224 } 225 226 static HRESULT ReadIcoDib(IStream *stream, IcoFrameDecode *result) 227 { 228 HRESULT hr; 229 BmpDecoder *bmp_decoder; 230 IWICBitmapDecoder *decoder; 231 IWICBitmapFrameDecode *framedecode; 232 WICPixelFormatGUID pixelformat; 233 IWICBitmapSource *source; 234 BOOL has_alpha=FALSE; /* if TRUE, alpha data might be in the image data */ 235 WICRect rc; 236 237 hr = IcoDibDecoder_CreateInstance(&bmp_decoder); 238 if (SUCCEEDED(hr)) 239 { 240 BmpDecoder_GetWICDecoder(bmp_decoder, &decoder); 241 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad); 242 243 if (SUCCEEDED(hr)) 244 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode); 245 246 if (SUCCEEDED(hr)) 247 { 248 hr = IWICBitmapFrameDecode_GetSize(framedecode, &result->width, &result->height); 249 250 if (SUCCEEDED(hr)) 251 { 252 result->bits = HeapAlloc(GetProcessHeap(), 0, result->width * result->height * 4); 253 if (!result->bits) hr = E_OUTOFMEMORY; 254 } 255 256 if (SUCCEEDED(hr)) 257 hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &pixelformat); 258 259 if (IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGR) || 260 IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGRA)) 261 { 262 source = (IWICBitmapSource*)framedecode; 263 IWICBitmapSource_AddRef(source); 264 has_alpha = TRUE; 265 } 266 else 267 { 268 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, 269 (IWICBitmapSource*)framedecode, &source); 270 has_alpha = FALSE; 271 } 272 273 if (SUCCEEDED(hr)) 274 { 275 rc.X = 0; 276 rc.Y = 0; 277 rc.Width = result->width; 278 rc.Height = result->height; 279 hr = IWICBitmapSource_CopyPixels(source, &rc, result->width * 4, 280 result->width * result->height * 4, result->bits); 281 282 IWICBitmapSource_Release(source); 283 } 284 285 if (SUCCEEDED(hr)) 286 hr = IWICBitmapFrameDecode_GetResolution(framedecode, &result->dpiX, &result->dpiY); 287 288 IWICBitmapFrameDecode_Release(framedecode); 289 } 290 291 if (SUCCEEDED(hr) && has_alpha) 292 { 293 /* If the alpha channel is fully transparent, we should ignore it. */ 294 int nonzero_alpha = 0; 295 UINT i; 296 297 for (i=0; i<(result->height*result->width); i++) 298 { 299 if (result->bits[i*4+3] != 0) 300 { 301 nonzero_alpha = 1; 302 break; 303 } 304 } 305 306 if (!nonzero_alpha) 307 { 308 for (i=0; i<(result->height*result->width); i++) 309 result->bits[i*4+3] = 0xff; 310 311 has_alpha = FALSE; 312 } 313 } 314 315 if (SUCCEEDED(hr) && !has_alpha) 316 { 317 /* set alpha data based on the AND mask */ 318 UINT andBytesPerRow = (result->width+31)/32*4; 319 UINT andBytes = andBytesPerRow * result->height; 320 INT andStride; 321 BYTE *tempdata=NULL; 322 BYTE *andRow; 323 BYTE *bitsRow; 324 UINT bitsStride = result->width * 4; 325 UINT x, y; 326 ULONG offset; 327 ULONG bytesread; 328 LARGE_INTEGER seek; 329 int topdown; 330 331 BmpDecoder_FindIconMask(bmp_decoder, &offset, &topdown); 332 333 if (offset) 334 { 335 seek.QuadPart = offset; 336 337 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, 0); 338 339 if (SUCCEEDED(hr)) 340 { 341 tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes); 342 if (!tempdata) hr = E_OUTOFMEMORY; 343 } 344 345 if (SUCCEEDED(hr)) 346 hr = IStream_Read(stream, tempdata, andBytes, &bytesread); 347 348 if (SUCCEEDED(hr) && bytesread == andBytes) 349 { 350 if (topdown) 351 { 352 andStride = andBytesPerRow; 353 andRow = tempdata; 354 } 355 else 356 { 357 andStride = -andBytesPerRow; 358 andRow = tempdata + (result->height-1)*andBytesPerRow; 359 } 360 361 bitsRow = result->bits; 362 for (y=0; y<result->height; y++) { 363 BYTE *andByte=andRow; 364 DWORD *bitsPixel=(DWORD*)bitsRow; 365 for (x=0; x<result->width; x+=8) { 366 BYTE andVal=*andByte++; 367 pixel_set_trans(bitsPixel++, andVal>>7&1); 368 if (x+1 < result->width) pixel_set_trans(bitsPixel++, andVal>>6&1); 369 if (x+2 < result->width) pixel_set_trans(bitsPixel++, andVal>>5&1); 370 if (x+3 < result->width) pixel_set_trans(bitsPixel++, andVal>>4&1); 371 if (x+4 < result->width) pixel_set_trans(bitsPixel++, andVal>>3&1); 372 if (x+5 < result->width) pixel_set_trans(bitsPixel++, andVal>>2&1); 373 if (x+6 < result->width) pixel_set_trans(bitsPixel++, andVal>>1&1); 374 if (x+7 < result->width) pixel_set_trans(bitsPixel++, andVal&1); 375 } 376 andRow += andStride; 377 bitsRow += bitsStride; 378 } 379 } 380 381 HeapFree(GetProcessHeap(), 0, tempdata); 382 } 383 } 384 385 IWICBitmapDecoder_Release(decoder); 386 } 387 388 return hr; 389 } 390 391 static HRESULT ReadIcoPng(IStream *stream, IcoFrameDecode *result) 392 { 393 IWICBitmapDecoder *decoder = NULL; 394 IWICBitmapFrameDecode *sourceFrame = NULL; 395 IWICBitmapSource *sourceBitmap = NULL; 396 WICRect rect; 397 HRESULT hr; 398 399 hr = PngDecoder_CreateInstance(&IID_IWICBitmapDecoder, (void**)&decoder); 400 if (FAILED(hr)) 401 goto end; 402 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad); 403 if (FAILED(hr)) 404 goto end; 405 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &sourceFrame); 406 if (FAILED(hr)) 407 goto end; 408 hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)sourceFrame, &sourceBitmap); 409 if (FAILED(hr)) 410 goto end; 411 hr = IWICBitmapFrameDecode_GetSize(sourceFrame, &result->width, &result->height); 412 if (FAILED(hr)) 413 goto end; 414 hr = IWICBitmapFrameDecode_GetResolution(sourceFrame, &result->dpiX, &result->dpiY); 415 if (FAILED(hr)) 416 goto end; 417 result->bits = HeapAlloc(GetProcessHeap(), 0, 4 * result->width * result->height); 418 if (result->bits == NULL) 419 { 420 hr = E_OUTOFMEMORY; 421 goto end; 422 } 423 rect.X = 0; 424 rect.Y = 0; 425 rect.Width = result->width; 426 rect.Height = result->height; 427 hr = IWICBitmapSource_CopyPixels(sourceBitmap, &rect, 4*result->width, 428 4*result->width*result->height, result->bits); 429 430 end: 431 if (decoder != NULL) 432 IWICBitmapDecoder_Release(decoder); 433 if (sourceFrame != NULL) 434 IWICBitmapFrameDecode_Release(sourceFrame); 435 if (sourceBitmap != NULL) 436 IWICBitmapSource_Release(sourceBitmap); 437 return hr; 438 } 439 440 static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 441 void **ppv) 442 { 443 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 444 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 445 446 if (!ppv) return E_INVALIDARG; 447 448 if (IsEqualIID(&IID_IUnknown, iid) || 449 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 450 { 451 *ppv = &This->IWICBitmapDecoder_iface; 452 } 453 else 454 { 455 *ppv = NULL; 456 return E_NOINTERFACE; 457 } 458 459 IUnknown_AddRef((IUnknown*)*ppv); 460 return S_OK; 461 } 462 463 static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface) 464 { 465 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 466 ULONG ref = InterlockedIncrement(&This->ref); 467 468 TRACE("(%p) refcount=%u\n", iface, ref); 469 470 return ref; 471 } 472 473 static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface) 474 { 475 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 476 ULONG ref = InterlockedDecrement(&This->ref); 477 478 TRACE("(%p) refcount=%u\n", iface, ref); 479 480 if (ref == 0) 481 { 482 This->lock.DebugInfo->Spare[0] = 0; 483 DeleteCriticalSection(&This->lock); 484 if (This->stream) IStream_Release(This->stream); 485 HeapFree(GetProcessHeap(), 0, This); 486 } 487 488 return ref; 489 } 490 491 static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 492 DWORD *capability) 493 { 494 HRESULT hr; 495 496 TRACE("(%p,%p,%p)\n", iface, stream, capability); 497 498 if (!stream || !capability) return E_INVALIDARG; 499 500 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 501 if (hr != S_OK) return hr; 502 503 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages; 504 return S_OK; 505 } 506 507 static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 508 WICDecodeOptions cacheOptions) 509 { 510 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 511 LARGE_INTEGER seek; 512 HRESULT hr; 513 ULONG bytesread; 514 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 515 516 EnterCriticalSection(&This->lock); 517 518 if (This->initialized) 519 { 520 hr = WINCODEC_ERR_WRONGSTATE; 521 goto end; 522 } 523 524 seek.QuadPart = 0; 525 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 526 if (FAILED(hr)) goto end; 527 528 hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread); 529 if (FAILED(hr)) goto end; 530 if (bytesread != sizeof(ICONHEADER) || 531 This->header.idReserved != 0 || 532 This->header.idType != 1) 533 { 534 hr = E_FAIL; 535 goto end; 536 } 537 538 This->initialized = TRUE; 539 This->stream = pIStream; 540 IStream_AddRef(pIStream); 541 542 end: 543 544 LeaveCriticalSection(&This->lock); 545 546 return hr; 547 } 548 549 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 550 GUID *pguidContainerFormat) 551 { 552 memcpy(pguidContainerFormat, &GUID_ContainerFormatIco, sizeof(GUID)); 553 return S_OK; 554 } 555 556 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 557 IWICBitmapDecoderInfo **ppIDecoderInfo) 558 { 559 HRESULT hr; 560 IWICComponentInfo *compinfo; 561 562 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 563 564 hr = CreateComponentInfo(&CLSID_WICIcoDecoder, &compinfo); 565 if (FAILED(hr)) return hr; 566 567 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 568 (void**)ppIDecoderInfo); 569 570 IWICComponentInfo_Release(compinfo); 571 572 return hr; 573 } 574 575 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface, 576 IWICPalette *pIPalette) 577 { 578 TRACE("(%p,%p)\n", iface, pIPalette); 579 return WINCODEC_ERR_PALETTEUNAVAILABLE; 580 } 581 582 static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 583 IWICMetadataQueryReader **ppIMetadataQueryReader) 584 { 585 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 586 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 587 } 588 589 static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface, 590 IWICBitmapSource **ppIBitmapSource) 591 { 592 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 593 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 594 } 595 596 static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface, 597 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 598 { 599 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 600 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 601 } 602 603 static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface, 604 IWICBitmapSource **ppIThumbnail) 605 { 606 TRACE("(%p,%p)\n", iface, ppIThumbnail); 607 return WINCODEC_ERR_CODECNOTHUMBNAIL; 608 } 609 610 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface, 611 UINT *pCount) 612 { 613 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 614 615 if (!pCount) return E_INVALIDARG; 616 617 EnterCriticalSection(&This->lock); 618 *pCount = This->initialized ? This->header.idCount : 0; 619 LeaveCriticalSection(&This->lock); 620 621 TRACE("(%p) <-- %d\n", iface, *pCount); 622 623 return S_OK; 624 } 625 626 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, 627 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 628 { 629 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 630 IcoFrameDecode *result=NULL; 631 LARGE_INTEGER seek; 632 ULARGE_INTEGER offset, length; 633 HRESULT hr; 634 ULONG bytesread; 635 ICONDIRENTRY entry; 636 IWICStream *substream=NULL; 637 DWORD magic; 638 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 639 640 EnterCriticalSection(&This->lock); 641 642 if (!This->initialized) 643 { 644 hr = WINCODEC_ERR_FRAMEMISSING; 645 goto fail; 646 } 647 648 if (This->header.idCount < index) 649 { 650 hr = E_INVALIDARG; 651 goto fail; 652 } 653 654 result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode)); 655 if (!result) 656 { 657 hr = E_OUTOFMEMORY; 658 goto fail; 659 } 660 661 result->IWICBitmapFrameDecode_iface.lpVtbl = &IcoFrameDecode_Vtbl; 662 result->ref = 1; 663 result->bits = NULL; 664 665 /* read the icon entry */ 666 seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index; 667 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0); 668 if (FAILED(hr)) goto fail; 669 670 hr = IStream_Read(This->stream, &entry, sizeof(ICONDIRENTRY), &bytesread); 671 if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail; 672 673 /* create a stream object for this icon */ 674 hr = StreamImpl_Create(&substream); 675 if (FAILED(hr)) goto fail; 676 677 offset.QuadPart = entry.dwDIBOffset; 678 length.QuadPart = entry.dwDIBSize; 679 hr = IWICStream_InitializeFromIStreamRegion(substream, This->stream, offset, length); 680 if (FAILED(hr)) goto fail; 681 682 /* read the bitmapinfo size or magic number */ 683 hr = IWICStream_Read(substream, &magic, sizeof(magic), &bytesread); 684 if (FAILED(hr) || bytesread != sizeof(magic)) goto fail; 685 686 /* forward to the appropriate decoding function based on the magic number */ 687 switch (magic) 688 { 689 case sizeof(BITMAPCOREHEADER): 690 case 64: /* sizeof(BITMAPCOREHEADER2) */ 691 case sizeof(BITMAPINFOHEADER): 692 case sizeof(BITMAPV4HEADER): 693 case sizeof(BITMAPV5HEADER): 694 hr = ReadIcoDib((IStream*)substream, result); 695 break; 696 case 0x474e5089: 697 hr = ReadIcoPng((IStream*)substream, result); 698 break; 699 default: 700 FIXME("Unrecognized ICO frame magic: %x\n", magic); 701 hr = E_FAIL; 702 break; 703 } 704 if (FAILED(hr)) goto fail; 705 706 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 707 708 LeaveCriticalSection(&This->lock); 709 710 IWICStream_Release(substream); 711 712 return S_OK; 713 714 fail: 715 LeaveCriticalSection(&This->lock); 716 HeapFree(GetProcessHeap(), 0, result); 717 if (substream) IWICStream_Release(substream); 718 if (SUCCEEDED(hr)) hr = E_FAIL; 719 TRACE("<-- %x\n", hr); 720 return hr; 721 } 722 723 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = { 724 IcoDecoder_QueryInterface, 725 IcoDecoder_AddRef, 726 IcoDecoder_Release, 727 IcoDecoder_QueryCapability, 728 IcoDecoder_Initialize, 729 IcoDecoder_GetContainerFormat, 730 IcoDecoder_GetDecoderInfo, 731 IcoDecoder_CopyPalette, 732 IcoDecoder_GetMetadataQueryReader, 733 IcoDecoder_GetPreview, 734 IcoDecoder_GetColorContexts, 735 IcoDecoder_GetThumbnail, 736 IcoDecoder_GetFrameCount, 737 IcoDecoder_GetFrame 738 }; 739 740 HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv) 741 { 742 IcoDecoder *This; 743 HRESULT ret; 744 745 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 746 747 *ppv = NULL; 748 749 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder)); 750 if (!This) return E_OUTOFMEMORY; 751 752 This->IWICBitmapDecoder_iface.lpVtbl = &IcoDecoder_Vtbl; 753 This->ref = 1; 754 This->stream = NULL; 755 This->initialized = FALSE; 756 InitializeCriticalSection(&This->lock); 757 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock"); 758 759 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 760 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 761 762 return ret; 763 } 764