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 #include "wincodec.h" 30 31 #include "wincodecs_private.h" 32 33 #include "wine/debug.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 36 37 #include "pshpack1.h" 38 39 typedef struct { 40 BYTE bWidth; 41 BYTE bHeight; 42 BYTE bColorCount; 43 BYTE bReserved; 44 WORD wPlanes; 45 WORD wBitCount; 46 DWORD dwDIBSize; 47 DWORD dwDIBOffset; 48 } ICONDIRENTRY; 49 50 typedef struct 51 { 52 WORD idReserved; 53 WORD idType; 54 WORD idCount; 55 } ICONHEADER; 56 57 #include "poppack.h" 58 59 typedef struct { 60 const IWICBitmapDecoderVtbl *lpVtbl; 61 LONG ref; 62 BOOL initialized; 63 IStream *stream; 64 ICONHEADER header; 65 CRITICAL_SECTION lock; /* must be held when accessing stream */ 66 } IcoDecoder; 67 68 typedef struct { 69 const IWICBitmapFrameDecodeVtbl *lpVtbl; 70 LONG ref; 71 ICONDIRENTRY entry; 72 IcoDecoder *parent; 73 BYTE *bits; 74 } IcoFrameDecode; 75 76 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 77 void **ppv) 78 { 79 IcoFrameDecode *This = (IcoFrameDecode*)iface; 80 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 81 82 if (!ppv) return E_INVALIDARG; 83 84 if (IsEqualIID(&IID_IUnknown, iid) || 85 IsEqualIID(&IID_IWICBitmapSource, iid) || 86 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 87 { 88 *ppv = This; 89 } 90 else 91 { 92 *ppv = NULL; 93 return E_NOINTERFACE; 94 } 95 96 IUnknown_AddRef((IUnknown*)*ppv); 97 return S_OK; 98 } 99 100 static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 101 { 102 IcoFrameDecode *This = (IcoFrameDecode*)iface; 103 ULONG ref = InterlockedIncrement(&This->ref); 104 105 TRACE("(%p) refcount=%u\n", iface, ref); 106 107 return ref; 108 } 109 110 static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface) 111 { 112 IcoFrameDecode *This = (IcoFrameDecode*)iface; 113 ULONG ref = InterlockedDecrement(&This->ref); 114 115 TRACE("(%p) refcount=%u\n", iface, ref); 116 117 if (ref == 0) 118 { 119 IUnknown_Release((IUnknown*)This->parent); 120 HeapFree(GetProcessHeap(), 0, This->bits); 121 HeapFree(GetProcessHeap(), 0, This); 122 } 123 124 return ref; 125 } 126 127 static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 128 UINT *puiWidth, UINT *puiHeight) 129 { 130 IcoFrameDecode *This = (IcoFrameDecode*)iface; 131 132 *puiWidth = This->entry.bWidth ? This->entry.bWidth : 256; 133 *puiHeight = This->entry.bHeight ? This->entry.bHeight : 256; 134 135 TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight); 136 137 return S_OK; 138 } 139 140 static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 141 WICPixelFormatGUID *pPixelFormat) 142 { 143 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)); 144 return S_OK; 145 } 146 147 static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 148 double *pDpiX, double *pDpiY) 149 { 150 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY); 151 return E_NOTIMPL; 152 } 153 154 static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 155 IWICPalette *pIPalette) 156 { 157 TRACE("(%p,%p)\n", iface, pIPalette); 158 return WINCODEC_ERR_PALETTEUNAVAILABLE; 159 } 160 161 static inline void pixel_set_trans(DWORD* pixel, BOOL transparent) 162 { 163 if (transparent) *pixel = 0; 164 else *pixel |= 0xff000000; 165 } 166 167 static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This) 168 { 169 BITMAPINFOHEADER bih; 170 DWORD colors[256]; 171 UINT colorcount=0; 172 LARGE_INTEGER seek; 173 ULONG bytesread; 174 HRESULT hr; 175 BYTE *tempdata = NULL; 176 BYTE *bits = NULL; 177 UINT bitsStride; 178 UINT bitsSize; 179 UINT width, height; 180 181 width = This->entry.bWidth ? This->entry.bWidth : 256; 182 height = This->entry.bHeight ? This->entry.bHeight : 256; 183 184 /* read the BITMAPINFOHEADER */ 185 seek.QuadPart = This->entry.dwDIBOffset; 186 hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL); 187 if (FAILED(hr)) goto fail; 188 189 hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread); 190 if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail; 191 192 if (bih.biBitCount <= 8) 193 { 194 /* read the palette */ 195 colorcount = bih.biClrUsed ? bih.biClrUsed : 1 << bih.biBitCount; 196 197 hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread); 198 if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail; 199 } 200 201 bitsStride = width * 4; 202 bitsSize = bitsStride * height; 203 204 /* read the XOR data */ 205 switch (bih.biBitCount) 206 { 207 case 1: 208 { 209 UINT xorBytesPerRow = (width+31)/32*4; 210 UINT xorBytes = xorBytesPerRow * height; 211 INT xorStride; 212 BYTE *xorRow; 213 BYTE *bitsRow; 214 UINT x, y; 215 216 tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); 217 if (!tempdata) 218 { 219 hr = E_OUTOFMEMORY; 220 goto fail; 221 } 222 223 hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); 224 if (FAILED(hr) || bytesread != xorBytes) goto fail; 225 226 if (bih.biHeight > 0) /* bottom-up DIB */ 227 { 228 xorStride = -xorBytesPerRow; 229 xorRow = tempdata + (height-1)*xorBytesPerRow; 230 } 231 else /* top-down DIB */ 232 { 233 xorStride = xorBytesPerRow; 234 xorRow = tempdata; 235 } 236 237 bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); 238 239 /* palette-map the 1-bit data */ 240 bitsRow = bits; 241 for (y=0; y<height; y++) { 242 BYTE *xorByte=xorRow; 243 DWORD *bitsPixel=(DWORD*)bitsRow; 244 for (x=0; x<width; x+=8) { 245 BYTE xorVal; 246 xorVal=*xorByte++; 247 *bitsPixel++ = colors[xorVal>>7]; 248 if (x+1 < width) *bitsPixel++ = colors[xorVal>>6&1]; 249 if (x+2 < width) *bitsPixel++ = colors[xorVal>>5&1]; 250 if (x+3 < width) *bitsPixel++ = colors[xorVal>>4&1]; 251 if (x+4 < width) *bitsPixel++ = colors[xorVal>>3&1]; 252 if (x+5 < width) *bitsPixel++ = colors[xorVal>>2&1]; 253 if (x+6 < width) *bitsPixel++ = colors[xorVal>>1&1]; 254 if (x+7 < width) *bitsPixel++ = colors[xorVal&1]; 255 } 256 xorRow += xorStride; 257 bitsRow += bitsStride; 258 } 259 260 HeapFree(GetProcessHeap(), 0, tempdata); 261 break; 262 } 263 case 4: 264 { 265 UINT xorBytesPerRow = (width+7)/8*4; 266 UINT xorBytes = xorBytesPerRow * height; 267 INT xorStride; 268 BYTE *xorRow; 269 BYTE *bitsRow; 270 UINT x, y; 271 272 tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); 273 if (!tempdata) 274 { 275 hr = E_OUTOFMEMORY; 276 goto fail; 277 } 278 279 hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); 280 if (FAILED(hr) || bytesread != xorBytes) goto fail; 281 282 if (bih.biHeight > 0) /* bottom-up DIB */ 283 { 284 xorStride = -xorBytesPerRow; 285 xorRow = tempdata + (height-1)*xorBytesPerRow; 286 } 287 else /* top-down DIB */ 288 { 289 xorStride = xorBytesPerRow; 290 xorRow = tempdata; 291 } 292 293 bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); 294 295 /* palette-map the 4-bit data */ 296 bitsRow = bits; 297 for (y=0; y<height; y++) { 298 BYTE *xorByte=xorRow; 299 DWORD *bitsPixel=(DWORD*)bitsRow; 300 for (x=0; x<width; x+=2) { 301 BYTE xorVal; 302 xorVal=*xorByte++; 303 *bitsPixel++ = colors[xorVal>>4]; 304 if (x+1 < width) *bitsPixel++ = colors[xorVal&0xf]; 305 } 306 xorRow += xorStride; 307 bitsRow += bitsStride; 308 } 309 310 HeapFree(GetProcessHeap(), 0, tempdata); 311 break; 312 } 313 case 8: 314 { 315 UINT xorBytesPerRow = (width+3)/4*4; 316 UINT xorBytes = xorBytesPerRow * height; 317 INT xorStride; 318 BYTE *xorRow; 319 BYTE *bitsRow; 320 UINT x, y; 321 322 tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); 323 if (!tempdata) 324 { 325 hr = E_OUTOFMEMORY; 326 goto fail; 327 } 328 329 hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); 330 if (FAILED(hr) || bytesread != xorBytes) goto fail; 331 332 if (bih.biHeight > 0) /* bottom-up DIB */ 333 { 334 xorStride = -xorBytesPerRow; 335 xorRow = tempdata + (height-1)*xorBytesPerRow; 336 } 337 else /* top-down DIB */ 338 { 339 xorStride = xorBytesPerRow; 340 xorRow = tempdata; 341 } 342 343 bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); 344 345 /* palette-map the 8-bit data */ 346 bitsRow = bits; 347 for (y=0; y<height; y++) { 348 BYTE *xorByte=xorRow; 349 DWORD *bitsPixel=(DWORD*)bitsRow; 350 for (x=0; x<width; x++) 351 *bitsPixel++ = colors[*xorByte++]; 352 xorRow += xorStride; 353 bitsRow += bitsStride; 354 } 355 356 HeapFree(GetProcessHeap(), 0, tempdata); 357 break; 358 } 359 case 24: 360 { 361 UINT xorBytesPerRow = (width*3+3)/4*4; 362 UINT xorBytes = xorBytesPerRow * height; 363 INT xorStride; 364 BYTE *xorRow; 365 BYTE *bitsRow; 366 UINT x, y; 367 368 tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes); 369 if (!tempdata) 370 { 371 hr = E_OUTOFMEMORY; 372 goto fail; 373 } 374 375 hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread); 376 if (FAILED(hr) || bytesread != xorBytes) goto fail; 377 378 if (bih.biHeight > 0) /* bottom-up DIB */ 379 { 380 xorStride = -xorBytesPerRow; 381 xorRow = tempdata + (height-1)*xorBytesPerRow; 382 } 383 else /* top-down DIB */ 384 { 385 xorStride = xorBytesPerRow; 386 xorRow = tempdata; 387 } 388 389 bits = HeapAlloc(GetProcessHeap(), 0, bitsSize); 390 391 /* copy BGR->BGRA */ 392 bitsRow = bits; 393 for (y=0; y<height; y++) { 394 BYTE *xorByte=xorRow; 395 BYTE *bitsByte=bitsRow; 396 for (x=0; x<width; x++) 397 { 398 *bitsByte++ = *xorByte++; /* blue */ 399 *bitsByte++ = *xorByte++; /* green */ 400 *bitsByte++ = *xorByte++; /* red */ 401 bitsByte++; /* alpha */ 402 } 403 xorRow += xorStride; 404 bitsRow += bitsStride; 405 } 406 407 HeapFree(GetProcessHeap(), 0, tempdata); 408 break; 409 } 410 case 32: 411 { 412 UINT xorBytesPerRow = width*4; 413 UINT xorBytes = xorBytesPerRow * height; 414 415 bits = HeapAlloc(GetProcessHeap(), 0, xorBytes); 416 if (!bits) 417 { 418 hr = E_OUTOFMEMORY; 419 goto fail; 420 } 421 422 if (bih.biHeight > 0) /* bottom-up DIB */ 423 { 424 /* read the rows backwards so we get a top-down DIB */ 425 UINT i; 426 BYTE *xorRow = bits + xorBytesPerRow * (height-1); 427 428 for (i=0; i<height; i++) 429 { 430 hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread); 431 if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail; 432 xorRow -= xorBytesPerRow; 433 } 434 } 435 else /* top-down DIB */ 436 { 437 hr = IStream_Read(This->parent->stream, bits, xorBytes, &bytesread); 438 if (FAILED(hr) || bytesread != xorBytes) goto fail; 439 } 440 break; 441 } 442 default: 443 FIXME("unsupported bitcount: %u\n", bih.biBitCount); 444 goto fail; 445 } 446 447 if (bih.biBitCount < 32) 448 { 449 /* set alpha data based on the AND mask */ 450 UINT andBytesPerRow = (width+31)/32*4; 451 UINT andBytes = andBytesPerRow * height; 452 INT andStride; 453 BYTE *andRow; 454 BYTE *bitsRow; 455 UINT x, y; 456 457 tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes); 458 if (!tempdata) 459 { 460 hr = E_OUTOFMEMORY; 461 goto fail; 462 } 463 464 hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread); 465 if (FAILED(hr) || bytesread != andBytes) goto fail; 466 467 if (bih.biHeight > 0) /* bottom-up DIB */ 468 { 469 andStride = -andBytesPerRow; 470 andRow = tempdata + (height-1)*andBytesPerRow; 471 } 472 else /* top-down DIB */ 473 { 474 andStride = andBytesPerRow; 475 andRow = tempdata; 476 } 477 478 bitsRow = bits; 479 for (y=0; y<height; y++) { 480 BYTE *andByte=andRow; 481 DWORD *bitsPixel=(DWORD*)bitsRow; 482 for (x=0; x<width; x+=8) { 483 BYTE andVal=*andByte++; 484 pixel_set_trans(bitsPixel++, andVal>>7&1); 485 if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1); 486 if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1); 487 if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1); 488 if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1); 489 if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1); 490 if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1); 491 if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1); 492 } 493 andRow += andStride; 494 bitsRow += bitsStride; 495 } 496 497 HeapFree(GetProcessHeap(), 0, tempdata); 498 } 499 500 This->bits = bits; 501 502 return S_OK; 503 504 fail: 505 HeapFree(GetProcessHeap(), 0, tempdata); 506 HeapFree(GetProcessHeap(), 0, bits); 507 if (SUCCEEDED(hr)) hr = E_FAIL; 508 TRACE("<-- %x\n", hr); 509 return hr; 510 } 511 512 static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 513 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 514 { 515 IcoFrameDecode *This = (IcoFrameDecode*)iface; 516 HRESULT hr=S_OK; 517 UINT width, height, stride; 518 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 519 520 EnterCriticalSection(&This->parent->lock); 521 if (!This->bits) 522 { 523 hr = IcoFrameDecode_ReadPixels(This); 524 } 525 LeaveCriticalSection(&This->parent->lock); 526 if (FAILED(hr)) return hr; 527 528 width = This->entry.bWidth ? This->entry.bWidth : 256; 529 height = This->entry.bHeight ? This->entry.bHeight : 256; 530 stride = width * 4; 531 532 return copy_pixels(32, This->bits, width, height, stride, 533 prc, cbStride, cbBufferSize, pbBuffer); 534 } 535 536 static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 537 IWICMetadataQueryReader **ppIMetadataQueryReader) 538 { 539 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 540 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 541 } 542 543 static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 544 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 545 { 546 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 547 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 548 } 549 550 static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 551 IWICBitmapSource **ppIThumbnail) 552 { 553 TRACE("(%p,%p)\n", iface, ppIThumbnail); 554 return WINCODEC_ERR_CODECNOTHUMBNAIL; 555 } 556 557 static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = { 558 IcoFrameDecode_QueryInterface, 559 IcoFrameDecode_AddRef, 560 IcoFrameDecode_Release, 561 IcoFrameDecode_GetSize, 562 IcoFrameDecode_GetPixelFormat, 563 IcoFrameDecode_GetResolution, 564 IcoFrameDecode_CopyPalette, 565 IcoFrameDecode_CopyPixels, 566 IcoFrameDecode_GetMetadataQueryReader, 567 IcoFrameDecode_GetColorContexts, 568 IcoFrameDecode_GetThumbnail 569 }; 570 571 static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 572 void **ppv) 573 { 574 IcoDecoder *This = (IcoDecoder*)iface; 575 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 576 577 if (!ppv) return E_INVALIDARG; 578 579 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) 580 { 581 *ppv = This; 582 } 583 else 584 { 585 *ppv = NULL; 586 return E_NOINTERFACE; 587 } 588 589 IUnknown_AddRef((IUnknown*)*ppv); 590 return S_OK; 591 } 592 593 static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface) 594 { 595 IcoDecoder *This = (IcoDecoder*)iface; 596 ULONG ref = InterlockedIncrement(&This->ref); 597 598 TRACE("(%p) refcount=%u\n", iface, ref); 599 600 return ref; 601 } 602 603 static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface) 604 { 605 IcoDecoder *This = (IcoDecoder*)iface; 606 ULONG ref = InterlockedDecrement(&This->ref); 607 608 TRACE("(%p) refcount=%u\n", iface, ref); 609 610 if (ref == 0) 611 { 612 This->lock.DebugInfo->Spare[0] = 0; 613 DeleteCriticalSection(&This->lock); 614 if (This->stream) IStream_Release(This->stream); 615 HeapFree(GetProcessHeap(), 0, This); 616 } 617 618 return ref; 619 } 620 621 static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream, 622 DWORD *pdwCapability) 623 { 624 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability); 625 return E_NOTIMPL; 626 } 627 628 static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 629 WICDecodeOptions cacheOptions) 630 { 631 IcoDecoder *This = (IcoDecoder*)iface; 632 LARGE_INTEGER seek; 633 HRESULT hr; 634 ULONG bytesread; 635 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 636 637 EnterCriticalSection(&This->lock); 638 639 if (This->initialized) 640 { 641 hr = WINCODEC_ERR_WRONGSTATE; 642 goto end; 643 } 644 645 seek.QuadPart = 0; 646 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 647 if (FAILED(hr)) goto end; 648 649 hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread); 650 if (FAILED(hr)) goto end; 651 if (bytesread != sizeof(ICONHEADER) || 652 This->header.idReserved != 0 || 653 This->header.idType != 1) 654 { 655 hr = E_FAIL; 656 goto end; 657 } 658 659 This->initialized = TRUE; 660 This->stream = pIStream; 661 IStream_AddRef(pIStream); 662 663 end: 664 665 LeaveCriticalSection(&This->lock); 666 667 return hr; 668 } 669 670 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 671 GUID *pguidContainerFormat) 672 { 673 FIXME("(%p,%p): stub\n", iface, pguidContainerFormat); 674 return E_NOTIMPL; 675 } 676 677 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 678 IWICBitmapDecoderInfo **ppIDecoderInfo) 679 { 680 FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo); 681 return E_NOTIMPL; 682 } 683 684 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface, 685 IWICPalette *pIPalette) 686 { 687 TRACE("(%p,%p)\n", iface, pIPalette); 688 return WINCODEC_ERR_PALETTEUNAVAILABLE; 689 } 690 691 static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 692 IWICMetadataQueryReader **ppIMetadataQueryReader) 693 { 694 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 695 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 696 } 697 698 static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface, 699 IWICBitmapSource **ppIBitmapSource) 700 { 701 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 702 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 703 } 704 705 static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface, 706 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 707 { 708 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 709 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 710 } 711 712 static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface, 713 IWICBitmapSource **ppIThumbnail) 714 { 715 TRACE("(%p,%p)\n", iface, ppIThumbnail); 716 return WINCODEC_ERR_CODECNOTHUMBNAIL; 717 } 718 719 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface, 720 UINT *pCount) 721 { 722 IcoDecoder *This = (IcoDecoder*)iface; 723 TRACE("(%p,%p)\n", iface, pCount); 724 725 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED; 726 727 *pCount = This->header.idCount; 728 TRACE("<-- %u\n", *pCount); 729 730 return S_OK; 731 } 732 733 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface, 734 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 735 { 736 IcoDecoder *This = (IcoDecoder*)iface; 737 IcoFrameDecode *result=NULL; 738 LARGE_INTEGER seek; 739 HRESULT hr; 740 ULONG bytesread; 741 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 742 743 EnterCriticalSection(&This->lock); 744 745 if (!This->initialized) 746 { 747 hr = WINCODEC_ERR_NOTINITIALIZED; 748 goto fail; 749 } 750 751 if (This->header.idCount < index) 752 { 753 hr = E_INVALIDARG; 754 goto fail; 755 } 756 757 result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode)); 758 if (!result) 759 { 760 hr = E_OUTOFMEMORY; 761 goto fail; 762 } 763 764 result->lpVtbl = &IcoFrameDecode_Vtbl; 765 result->ref = 1; 766 result->parent = This; 767 result->bits = NULL; 768 769 /* read the icon entry */ 770 seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index; 771 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0); 772 if (FAILED(hr)) goto fail; 773 774 hr = IStream_Read(This->stream, &result->entry, sizeof(ICONDIRENTRY), &bytesread); 775 if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail; 776 777 IWICBitmapDecoder_AddRef(iface); 778 779 *ppIBitmapFrame = (IWICBitmapFrameDecode*)result; 780 781 LeaveCriticalSection(&This->lock); 782 783 return S_OK; 784 785 fail: 786 LeaveCriticalSection(&This->lock); 787 HeapFree(GetProcessHeap(), 0, result); 788 if (SUCCEEDED(hr)) hr = E_FAIL; 789 TRACE("<-- %x\n", hr); 790 return hr; 791 } 792 793 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = { 794 IcoDecoder_QueryInterface, 795 IcoDecoder_AddRef, 796 IcoDecoder_Release, 797 IcoDecoder_QueryCapability, 798 IcoDecoder_Initialize, 799 IcoDecoder_GetContainerFormat, 800 IcoDecoder_GetDecoderInfo, 801 IcoDecoder_CopyPalette, 802 IcoDecoder_GetMetadataQueryReader, 803 IcoDecoder_GetPreview, 804 IcoDecoder_GetColorContexts, 805 IcoDecoder_GetThumbnail, 806 IcoDecoder_GetFrameCount, 807 IcoDecoder_GetFrame 808 }; 809 810 HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) 811 { 812 IcoDecoder *This; 813 HRESULT ret; 814 815 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv); 816 817 *ppv = NULL; 818 819 if (pUnkOuter) return CLASS_E_NOAGGREGATION; 820 821 This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder)); 822 if (!This) return E_OUTOFMEMORY; 823 824 This->lpVtbl = &IcoDecoder_Vtbl; 825 This->ref = 1; 826 This->stream = NULL; 827 This->initialized = FALSE; 828 InitializeCriticalSection(&This->lock); 829 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock"); 830 831 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv); 832 IUnknown_Release((IUnknown*)This); 833 834 return ret; 835 } 836