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