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,%s,%u,%u,%p)\n", iface, debug_wic_rect(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 STATSTG statstg; 515 unsigned int i; 516 517 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 518 519 EnterCriticalSection(&This->lock); 520 521 if (This->initialized) 522 { 523 hr = WINCODEC_ERR_WRONGSTATE; 524 goto end; 525 } 526 527 seek.QuadPart = 0; 528 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 529 if (FAILED(hr)) goto end; 530 531 hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread); 532 if (FAILED(hr)) goto end; 533 534 if (bytesread != sizeof(ICONHEADER)) 535 { 536 hr = WINCODEC_ERR_STREAMREAD; 537 goto end; 538 } 539 540 if (This->header.idReserved != 0 || 541 This->header.idType != 1) 542 { 543 hr = E_FAIL; 544 goto end; 545 } 546 547 hr = IStream_Stat(pIStream, &statstg, STATFLAG_NONAME); 548 if (FAILED(hr)) 549 { 550 WARN("Stat() failed, hr %#x.\n", hr); 551 goto end; 552 } 553 554 for (i = 0; i < This->header.idCount; i++) 555 { 556 ICONDIRENTRY direntry; 557 558 hr = IStream_Read(pIStream, &direntry, sizeof(direntry), &bytesread); 559 if (FAILED(hr)) goto end; 560 561 if (bytesread != sizeof(direntry) || (direntry.dwDIBSize + direntry.dwDIBOffset > statstg.cbSize.QuadPart)) 562 { 563 hr = WINCODEC_ERR_BADIMAGE; 564 goto end; 565 } 566 } 567 568 This->initialized = TRUE; 569 This->stream = pIStream; 570 IStream_AddRef(pIStream); 571 572 end: 573 574 LeaveCriticalSection(&This->lock); 575 576 return hr; 577 } 578 579 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 580 GUID *pguidContainerFormat) 581 { 582 memcpy(pguidContainerFormat, &GUID_ContainerFormatIco, sizeof(GUID)); 583 return S_OK; 584 } 585 586 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 587 IWICBitmapDecoderInfo **ppIDecoderInfo) 588 { 589 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 590 591 return get_decoder_info(&CLSID_WICIcoDecoder, ppIDecoderInfo); 592 } 593 594 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface, 595 IWICPalette *pIPalette) 596 { 597 TRACE("(%p,%p)\n", iface, pIPalette); 598 return WINCODEC_ERR_PALETTEUNAVAILABLE; 599 } 600 601 static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 602 IWICMetadataQueryReader **ppIMetadataQueryReader) 603 { 604 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 605 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 606 } 607 608 static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface, 609 IWICBitmapSource **ppIBitmapSource) 610 { 611 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 612 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 613 } 614 615 static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface, 616 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 617 { 618 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 619 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 620 } 621 622 static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface, 623 IWICBitmapSource **ppIThumbnail) 624 { 625 TRACE("(%p,%p)\n", iface, ppIThumbnail); 626 return WINCODEC_ERR_CODECNOTHUMBNAIL; 627 } 628 629 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface, 630 UINT *pCount) 631 { 632 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 633 634 if (!pCount) return E_INVALIDARG; 635 636 EnterCriticalSection(&This->lock); 637 *pCount = This->initialized ? This->header.idCount : 0; 638 LeaveCriticalSection(&This->lock); 639 640 TRACE("(%p) <-- %d\n", iface, *pCount); 641 642 return S_OK; 643 } 644 645 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, 646 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 647 { 648 IcoDecoder *This = impl_from_IWICBitmapDecoder(iface); 649 IcoFrameDecode *result=NULL; 650 LARGE_INTEGER seek; 651 ULARGE_INTEGER offset, length; 652 HRESULT hr; 653 ULONG bytesread; 654 ICONDIRENTRY entry; 655 IWICStream *substream=NULL; 656 DWORD magic; 657 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 658 659 EnterCriticalSection(&This->lock); 660 661 if (!This->initialized) 662 { 663 hr = WINCODEC_ERR_FRAMEMISSING; 664 goto fail; 665 } 666 667 if (This->header.idCount < index) 668 { 669 hr = E_INVALIDARG; 670 goto fail; 671 } 672 673 result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode)); 674 if (!result) 675 { 676 hr = E_OUTOFMEMORY; 677 goto fail; 678 } 679 680 result->IWICBitmapFrameDecode_iface.lpVtbl = &IcoFrameDecode_Vtbl; 681 result->ref = 1; 682 result->bits = NULL; 683 684 /* read the icon entry */ 685 seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index; 686 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0); 687 if (FAILED(hr)) goto fail; 688 689 hr = IStream_Read(This->stream, &entry, sizeof(ICONDIRENTRY), &bytesread); 690 if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail; 691 692 /* create a stream object for this icon */ 693 hr = StreamImpl_Create(&substream); 694 if (FAILED(hr)) goto fail; 695 696 offset.QuadPart = entry.dwDIBOffset; 697 length.QuadPart = entry.dwDIBSize; 698 hr = IWICStream_InitializeFromIStreamRegion(substream, This->stream, offset, length); 699 if (FAILED(hr)) goto fail; 700 701 /* read the bitmapinfo size or magic number */ 702 hr = IWICStream_Read(substream, &magic, sizeof(magic), &bytesread); 703 if (FAILED(hr) || bytesread != sizeof(magic)) goto fail; 704 705 /* forward to the appropriate decoding function based on the magic number */ 706 switch (magic) 707 { 708 case sizeof(BITMAPCOREHEADER): 709 case 64: /* sizeof(BITMAPCOREHEADER2) */ 710 case sizeof(BITMAPINFOHEADER): 711 case sizeof(BITMAPV4HEADER): 712 case sizeof(BITMAPV5HEADER): 713 hr = ReadIcoDib((IStream*)substream, result); 714 break; 715 case 0x474e5089: 716 hr = ReadIcoPng((IStream*)substream, result); 717 break; 718 default: 719 FIXME("Unrecognized ICO frame magic: %x\n", magic); 720 hr = E_FAIL; 721 break; 722 } 723 if (FAILED(hr)) goto fail; 724 725 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 726 727 LeaveCriticalSection(&This->lock); 728 729 IWICStream_Release(substream); 730 731 return S_OK; 732 733 fail: 734 LeaveCriticalSection(&This->lock); 735 HeapFree(GetProcessHeap(), 0, result); 736 if (substream) IWICStream_Release(substream); 737 if (SUCCEEDED(hr)) hr = E_FAIL; 738 TRACE("<-- %x\n", hr); 739 return hr; 740 } 741 742 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = { 743 IcoDecoder_QueryInterface, 744 IcoDecoder_AddRef, 745 IcoDecoder_Release, 746 IcoDecoder_QueryCapability, 747 IcoDecoder_Initialize, 748 IcoDecoder_GetContainerFormat, 749 IcoDecoder_GetDecoderInfo, 750 IcoDecoder_CopyPalette, 751 IcoDecoder_GetMetadataQueryReader, 752 IcoDecoder_GetPreview, 753 IcoDecoder_GetColorContexts, 754 IcoDecoder_GetThumbnail, 755 IcoDecoder_GetFrameCount, 756 IcoDecoder_GetFrame 757 }; 758 759 HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv) 760 { 761 IcoDecoder *This; 762 HRESULT ret; 763 764 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 765 766 *ppv = NULL; 767 768 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder)); 769 if (!This) return E_OUTOFMEMORY; 770 771 This->IWICBitmapDecoder_iface.lpVtbl = &IcoDecoder_Vtbl; 772 This->ref = 1; 773 This->stream = NULL; 774 This->initialized = FALSE; 775 InitializeCriticalSection(&This->lock); 776 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock"); 777 778 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 779 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 780 781 return ret; 782 } 783