1 /* 2 * Copyright 2010 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 #include "wine/port.h" 21 22 #include <stdarg.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "objbase.h" 29 30 #include "wincodecs_private.h" 31 32 #include "wine/debug.h" 33 #include "wine/library.h" 34 35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 36 37 #include "pshpack1.h" 38 39 typedef struct { 40 BYTE id_length; 41 BYTE colormap_type; 42 BYTE image_type; 43 /* Colormap Specification */ 44 WORD colormap_firstentry; 45 WORD colormap_length; 46 BYTE colormap_entrysize; 47 /* Image Specification */ 48 WORD xorigin; 49 WORD yorigin; 50 WORD width; 51 WORD height; 52 BYTE depth; 53 BYTE image_descriptor; 54 } tga_header; 55 56 #define IMAGETYPE_COLORMAPPED 1 57 #define IMAGETYPE_TRUECOLOR 2 58 #define IMAGETYPE_GRAYSCALE 3 59 #define IMAGETYPE_RLE 8 60 61 #define IMAGE_ATTRIBUTE_BITCOUNT_MASK 0xf 62 #define IMAGE_RIGHTTOLEFT 0x10 63 #define IMAGE_TOPTOBOTTOM 0x20 64 65 typedef struct { 66 DWORD extension_area_offset; 67 DWORD developer_directory_offset; 68 char magic[18]; 69 } tga_footer; 70 71 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE."; 72 73 typedef struct { 74 WORD size; 75 char author_name[41]; 76 char author_comments[324]; 77 WORD timestamp[6]; 78 char job_name[41]; 79 WORD job_timestamp[6]; 80 char software_id[41]; 81 WORD software_version; 82 char software_version_letter; 83 DWORD key_color; 84 WORD pixel_width; 85 WORD pixel_height; 86 WORD gamma_numerator; 87 WORD gamma_denominator; 88 DWORD color_correction_offset; 89 DWORD thumbnail_offset; 90 DWORD scanline_offset; 91 BYTE attributes_type; 92 } tga_extension_area; 93 94 #define ATTRIBUTE_NO_ALPHA 0 95 #define ATTRIBUTE_UNDEFINED 1 96 #define ATTRIBUTE_UNDEFINED_PRESERVE 2 97 #define ATTRIBUTE_ALPHA 3 98 #define ATTRIBUTE_PALPHA 4 99 100 #include "poppack.h" 101 102 typedef struct { 103 IWICBitmapDecoder IWICBitmapDecoder_iface; 104 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 105 LONG ref; 106 BOOL initialized; 107 IStream *stream; 108 tga_header header; 109 tga_extension_area extension_area; 110 BYTE *imagebits; 111 BYTE *origin; 112 int stride; 113 ULONG id_offset; 114 ULONG colormap_length; 115 ULONG colormap_offset; 116 ULONG image_offset; 117 ULONG extension_area_offset; 118 ULONG developer_directory_offset; 119 CRITICAL_SECTION lock; 120 } TgaDecoder; 121 122 static inline TgaDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 123 { 124 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapDecoder_iface); 125 } 126 127 static inline TgaDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 128 { 129 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapFrameDecode_iface); 130 } 131 132 static HRESULT WINAPI TgaDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 133 void **ppv) 134 { 135 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 136 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 137 138 if (!ppv) return E_INVALIDARG; 139 140 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) 141 { 142 *ppv = &This->IWICBitmapDecoder_iface; 143 } 144 else 145 { 146 *ppv = NULL; 147 return E_NOINTERFACE; 148 } 149 150 IUnknown_AddRef((IUnknown*)*ppv); 151 return S_OK; 152 } 153 154 static ULONG WINAPI TgaDecoder_AddRef(IWICBitmapDecoder *iface) 155 { 156 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 157 ULONG ref = InterlockedIncrement(&This->ref); 158 159 TRACE("(%p) refcount=%u\n", iface, ref); 160 161 return ref; 162 } 163 164 static ULONG WINAPI TgaDecoder_Release(IWICBitmapDecoder *iface) 165 { 166 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 167 ULONG ref = InterlockedDecrement(&This->ref); 168 169 TRACE("(%p) refcount=%u\n", iface, ref); 170 171 if (ref == 0) 172 { 173 This->lock.DebugInfo->Spare[0] = 0; 174 DeleteCriticalSection(&This->lock); 175 if (This->stream) 176 IStream_Release(This->stream); 177 HeapFree(GetProcessHeap(), 0, This->imagebits); 178 HeapFree(GetProcessHeap(), 0, This); 179 } 180 181 return ref; 182 } 183 184 static HRESULT WINAPI TgaDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 185 DWORD *capability) 186 { 187 HRESULT hr; 188 189 TRACE("(%p,%p,%p)\n", iface, stream, capability); 190 191 if (!stream || !capability) return E_INVALIDARG; 192 193 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 194 if (hr != S_OK) return hr; 195 196 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 197 WICBitmapDecoderCapabilityCanDecodeSomeImages; 198 return S_OK; 199 } 200 201 static HRESULT WINAPI TgaDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 202 WICDecodeOptions cacheOptions) 203 { 204 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 205 HRESULT hr=S_OK; 206 DWORD bytesread; 207 LARGE_INTEGER seek; 208 tga_footer footer; 209 int attribute_bitcount; 210 int mapped_depth=0; 211 212 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions); 213 214 EnterCriticalSection(&This->lock); 215 216 if (This->initialized) 217 { 218 hr = WINCODEC_ERR_WRONGSTATE; 219 goto end; 220 } 221 222 seek.QuadPart = 0; 223 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 224 if (FAILED(hr)) goto end; 225 226 hr = IStream_Read(pIStream, &This->header, sizeof(tga_header), &bytesread); 227 if (SUCCEEDED(hr) && bytesread != sizeof(tga_header)) 228 { 229 TRACE("got only %u bytes\n", bytesread); 230 hr = E_FAIL; 231 } 232 if (FAILED(hr)) goto end; 233 234 TRACE("imagetype=%u, colormap type=%u, depth=%u, image descriptor=0x%x\n", 235 This->header.image_type, This->header.colormap_type, 236 This->header.depth, This->header.image_descriptor); 237 238 /* Sanity checking. Since TGA has no clear identifying markers, we need 239 * to be careful to not load a non-TGA image. */ 240 switch (This->header.image_type) 241 { 242 case IMAGETYPE_COLORMAPPED: 243 case IMAGETYPE_COLORMAPPED|IMAGETYPE_RLE: 244 if (This->header.colormap_type != 1) 245 hr = E_FAIL; 246 mapped_depth = This->header.colormap_entrysize; 247 break; 248 case IMAGETYPE_TRUECOLOR: 249 case IMAGETYPE_TRUECOLOR|IMAGETYPE_RLE: 250 if (This->header.colormap_type != 0 && This->header.colormap_type != 1) 251 hr = E_FAIL; 252 mapped_depth = This->header.depth; 253 break; 254 case IMAGETYPE_GRAYSCALE: 255 case IMAGETYPE_GRAYSCALE|IMAGETYPE_RLE: 256 if (This->header.colormap_type != 0) 257 hr = E_FAIL; 258 mapped_depth = 0; 259 break; 260 default: 261 hr = E_FAIL; 262 } 263 264 if (This->header.depth != 8 && This->header.depth != 16 && 265 This->header.depth != 24 && This->header.depth != 32) 266 hr = E_FAIL; 267 268 if ((This->header.image_descriptor & 0xc0) != 0) 269 hr = E_FAIL; 270 271 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 272 273 if (attribute_bitcount && 274 !((mapped_depth == 32 && attribute_bitcount == 8) || 275 (mapped_depth == 16 && attribute_bitcount == 1))) 276 hr = E_FAIL; 277 278 if (FAILED(hr)) 279 { 280 WARN("bad tga header\n"); 281 goto end; 282 } 283 284 /* Locate data in the file based on the header. */ 285 This->id_offset = sizeof(tga_header); 286 This->colormap_offset = This->id_offset + This->header.id_length; 287 if (This->header.colormap_type == 1) 288 This->colormap_length = ((This->header.colormap_entrysize+7)/8) * This->header.colormap_length; 289 else 290 This->colormap_length = 0; 291 This->image_offset = This->colormap_offset + This->colormap_length; 292 293 /* Read footer if there is one */ 294 seek.QuadPart = -(LONGLONG)sizeof(tga_footer); 295 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_END, NULL); 296 297 if (SUCCEEDED(hr)) { 298 hr = IStream_Read(pIStream, &footer, sizeof(tga_footer), &bytesread); 299 if (SUCCEEDED(hr) && bytesread != sizeof(tga_footer)) 300 { 301 TRACE("got only %u footer bytes\n", bytesread); 302 hr = E_FAIL; 303 } 304 305 if (memcmp(footer.magic, tga_footer_magic, sizeof(tga_footer_magic)) == 0) 306 { 307 This->extension_area_offset = footer.extension_area_offset; 308 This->developer_directory_offset = footer.developer_directory_offset; 309 } 310 else 311 { 312 This->extension_area_offset = 0; 313 This->developer_directory_offset = 0; 314 } 315 } 316 else 317 { 318 /* File is too small to have a footer. */ 319 This->extension_area_offset = 0; 320 This->developer_directory_offset = 0; 321 hr = S_OK; 322 } 323 324 if (This->extension_area_offset) 325 { 326 seek.QuadPart = This->extension_area_offset; 327 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 328 if (FAILED(hr)) goto end; 329 330 hr = IStream_Read(pIStream, &This->extension_area, sizeof(tga_extension_area), &bytesread); 331 if (SUCCEEDED(hr) && bytesread != sizeof(tga_extension_area)) 332 { 333 TRACE("got only %u extension area bytes\n", bytesread); 334 hr = E_FAIL; 335 } 336 if (SUCCEEDED(hr) && This->extension_area.size < 495) 337 { 338 TRACE("extension area is only %u bytes long\n", This->extension_area.size); 339 hr = E_FAIL; 340 } 341 if (FAILED(hr)) goto end; 342 } 343 344 IStream_AddRef(pIStream); 345 This->stream = pIStream; 346 This->initialized = TRUE; 347 348 end: 349 LeaveCriticalSection(&This->lock); 350 return hr; 351 } 352 353 static HRESULT WINAPI TgaDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 354 GUID *pguidContainerFormat) 355 { 356 memcpy(pguidContainerFormat, &GUID_WineContainerFormatTga, sizeof(GUID)); 357 return S_OK; 358 } 359 360 static HRESULT WINAPI TgaDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 361 IWICBitmapDecoderInfo **ppIDecoderInfo) 362 { 363 HRESULT hr; 364 IWICComponentInfo *compinfo; 365 366 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 367 368 hr = CreateComponentInfo(&CLSID_WineTgaDecoder, &compinfo); 369 if (FAILED(hr)) return hr; 370 371 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 372 (void**)ppIDecoderInfo); 373 374 IWICComponentInfo_Release(compinfo); 375 376 return hr; 377 } 378 379 static HRESULT WINAPI TgaDecoder_CopyPalette(IWICBitmapDecoder *iface, 380 IWICPalette *pIPalette) 381 { 382 FIXME("(%p,%p): stub\n", iface, pIPalette); 383 return E_NOTIMPL; 384 } 385 386 static HRESULT WINAPI TgaDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 387 IWICMetadataQueryReader **ppIMetadataQueryReader) 388 { 389 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 390 return E_NOTIMPL; 391 } 392 393 static HRESULT WINAPI TgaDecoder_GetPreview(IWICBitmapDecoder *iface, 394 IWICBitmapSource **ppIBitmapSource) 395 { 396 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource); 397 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 398 } 399 400 static HRESULT WINAPI TgaDecoder_GetColorContexts(IWICBitmapDecoder *iface, 401 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 402 { 403 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 404 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 405 } 406 407 static HRESULT WINAPI TgaDecoder_GetThumbnail(IWICBitmapDecoder *iface, 408 IWICBitmapSource **ppIThumbnail) 409 { 410 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 411 return WINCODEC_ERR_CODECNOTHUMBNAIL; 412 } 413 414 static HRESULT WINAPI TgaDecoder_GetFrameCount(IWICBitmapDecoder *iface, 415 UINT *pCount) 416 { 417 if (!pCount) return E_INVALIDARG; 418 419 *pCount = 1; 420 return S_OK; 421 } 422 423 static HRESULT WINAPI TgaDecoder_GetFrame(IWICBitmapDecoder *iface, 424 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 425 { 426 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 427 TRACE("(%p,%p)\n", iface, ppIBitmapFrame); 428 429 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 430 431 if (index != 0) return E_INVALIDARG; 432 433 IWICBitmapDecoder_AddRef(iface); 434 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 435 436 return S_OK; 437 } 438 439 static const IWICBitmapDecoderVtbl TgaDecoder_Vtbl = { 440 TgaDecoder_QueryInterface, 441 TgaDecoder_AddRef, 442 TgaDecoder_Release, 443 TgaDecoder_QueryCapability, 444 TgaDecoder_Initialize, 445 TgaDecoder_GetContainerFormat, 446 TgaDecoder_GetDecoderInfo, 447 TgaDecoder_CopyPalette, 448 TgaDecoder_GetMetadataQueryReader, 449 TgaDecoder_GetPreview, 450 TgaDecoder_GetColorContexts, 451 TgaDecoder_GetThumbnail, 452 TgaDecoder_GetFrameCount, 453 TgaDecoder_GetFrame 454 }; 455 456 static HRESULT WINAPI TgaDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 457 void **ppv) 458 { 459 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 460 461 if (!ppv) return E_INVALIDARG; 462 463 if (IsEqualIID(&IID_IUnknown, iid) || 464 IsEqualIID(&IID_IWICBitmapSource, iid) || 465 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 466 { 467 *ppv = iface; 468 } 469 else 470 { 471 *ppv = NULL; 472 return E_NOINTERFACE; 473 } 474 475 IUnknown_AddRef((IUnknown*)*ppv); 476 return S_OK; 477 } 478 479 static ULONG WINAPI TgaDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) 480 { 481 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 482 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 483 } 484 485 static ULONG WINAPI TgaDecoder_Frame_Release(IWICBitmapFrameDecode *iface) 486 { 487 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 488 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 489 } 490 491 static HRESULT WINAPI TgaDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, 492 UINT *puiWidth, UINT *puiHeight) 493 { 494 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 495 496 *puiWidth = This->header.width; 497 *puiHeight = This->header.height; 498 499 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); 500 501 return S_OK; 502 } 503 504 static HRESULT WINAPI TgaDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, 505 WICPixelFormatGUID *pPixelFormat) 506 { 507 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 508 int attribute_bitcount; 509 byte attribute_type; 510 511 TRACE("(%p,%p)\n", iface, pPixelFormat); 512 513 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 514 515 if (attribute_bitcount && This->extension_area_offset) 516 attribute_type = This->extension_area.attributes_type; 517 else if (attribute_bitcount) 518 attribute_type = ATTRIBUTE_ALPHA; 519 else 520 attribute_type = ATTRIBUTE_NO_ALPHA; 521 522 switch (This->header.image_type & ~IMAGETYPE_RLE) 523 { 524 case IMAGETYPE_COLORMAPPED: 525 switch (This->header.depth) 526 { 527 case 8: 528 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); 529 break; 530 default: 531 FIXME("Unhandled indexed color depth %u\n", This->header.depth); 532 return E_NOTIMPL; 533 } 534 break; 535 case IMAGETYPE_TRUECOLOR: 536 switch (This->header.depth) 537 { 538 case 16: 539 switch (attribute_type) 540 { 541 case ATTRIBUTE_NO_ALPHA: 542 case ATTRIBUTE_UNDEFINED: 543 case ATTRIBUTE_UNDEFINED_PRESERVE: 544 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGR555, sizeof(GUID)); 545 break; 546 case ATTRIBUTE_ALPHA: 547 case ATTRIBUTE_PALPHA: 548 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGRA5551, sizeof(GUID)); 549 break; 550 default: 551 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 552 return E_NOTIMPL; 553 } 554 break; 555 case 24: 556 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID)); 557 break; 558 case 32: 559 switch (attribute_type) 560 { 561 case ATTRIBUTE_NO_ALPHA: 562 case ATTRIBUTE_UNDEFINED: 563 case ATTRIBUTE_UNDEFINED_PRESERVE: 564 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGR, sizeof(GUID)); 565 break; 566 case ATTRIBUTE_ALPHA: 567 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)); 568 break; 569 case ATTRIBUTE_PALPHA: 570 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppPBGRA, sizeof(GUID)); 571 break; 572 default: 573 FIXME("Unhandled 32-bit attribute type %u\n", attribute_type); 574 return E_NOTIMPL; 575 } 576 break; 577 default: 578 FIXME("Unhandled truecolor depth %u\n", This->header.depth); 579 return E_NOTIMPL; 580 } 581 break; 582 case IMAGETYPE_GRAYSCALE: 583 switch (This->header.depth) 584 { 585 case 8: 586 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID)); 587 break; 588 case 16: 589 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppGray, sizeof(GUID)); 590 break; 591 default: 592 FIXME("Unhandled grayscale depth %u\n", This->header.depth); 593 return E_NOTIMPL; 594 } 595 break; 596 default: 597 ERR("Unknown image type %u\n", This->header.image_type); 598 return E_FAIL; 599 } 600 601 return S_OK; 602 } 603 604 static HRESULT WINAPI TgaDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, 605 double *pDpiX, double *pDpiY) 606 { 607 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY); 608 return E_NOTIMPL; 609 } 610 611 static HRESULT WINAPI TgaDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, 612 IWICPalette *pIPalette) 613 { 614 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 615 HRESULT hr=S_OK; 616 WICColor colors[256], *color; 617 BYTE *colormap_data; 618 WORD *wcolormap_data; 619 DWORD *dwcolormap_data; 620 LARGE_INTEGER seek; 621 ULONG bytesread; 622 int depth, attribute_bitcount, attribute_type; 623 int i; 624 625 TRACE("(%p,%p)\n", iface, pIPalette); 626 627 if (!This->colormap_length) 628 { 629 WARN("no colormap present in this file\n"); 630 return WINCODEC_ERR_PALETTEUNAVAILABLE; 631 } 632 633 if (This->header.colormap_firstentry + This->header.colormap_length > 256) 634 { 635 FIXME("cannot read colormap with %i entries starting at %i\n", 636 This->header.colormap_firstentry + This->header.colormap_length, 637 This->header.colormap_firstentry); 638 return E_FAIL; 639 } 640 641 colormap_data = HeapAlloc(GetProcessHeap(), 0, This->colormap_length); 642 if (!colormap_data) return E_OUTOFMEMORY; 643 644 wcolormap_data = (WORD*)colormap_data; 645 dwcolormap_data = (DWORD*)colormap_data; 646 647 EnterCriticalSection(&This->lock); 648 649 seek.QuadPart = This->colormap_offset; 650 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL); 651 652 if (SUCCEEDED(hr)) 653 { 654 hr = IStream_Read(This->stream, colormap_data, This->colormap_length, &bytesread); 655 if (SUCCEEDED(hr) && bytesread != This->colormap_length) 656 { 657 WARN("expected %i bytes in colormap, got %i\n", This->colormap_length, bytesread); 658 hr = E_FAIL; 659 } 660 } 661 662 LeaveCriticalSection(&This->lock); 663 664 if (SUCCEEDED(hr)) 665 { 666 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 667 668 if (attribute_bitcount && This->extension_area_offset) 669 attribute_type = This->extension_area.attributes_type; 670 else if (attribute_bitcount) 671 attribute_type = ATTRIBUTE_ALPHA; 672 else 673 attribute_type = ATTRIBUTE_NO_ALPHA; 674 675 depth = This->header.colormap_entrysize; 676 if (depth == 15) 677 { 678 depth = 16; 679 attribute_type = ATTRIBUTE_NO_ALPHA; 680 } 681 682 memset(colors, 0, sizeof(colors)); 683 684 color = &colors[This->header.colormap_firstentry]; 685 686 /* Colormap entries can be in any truecolor format, and we have to convert them. */ 687 switch (depth) 688 { 689 case 16: 690 switch (attribute_type) 691 { 692 case ATTRIBUTE_NO_ALPHA: 693 case ATTRIBUTE_UNDEFINED: 694 case ATTRIBUTE_UNDEFINED_PRESERVE: 695 for (i=0; i<This->header.colormap_length; i++) 696 { 697 WORD srcval = wcolormap_data[i]; 698 *color++=0xff000000 | /* constant 255 alpha */ 699 ((srcval << 9) & 0xf80000) | /* r */ 700 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 701 ((srcval << 6) & 0x00f800) | /* g */ 702 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 703 ((srcval << 3) & 0x0000f8) | /* b */ 704 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 705 } 706 break; 707 case ATTRIBUTE_ALPHA: 708 case ATTRIBUTE_PALPHA: 709 for (i=0; i<This->header.colormap_length; i++) 710 { 711 WORD srcval = wcolormap_data[i]; 712 *color++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */ 713 ((srcval << 9) & 0xf80000) | /* r */ 714 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 715 ((srcval << 6) & 0x00f800) | /* g */ 716 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 717 ((srcval << 3) & 0x0000f8) | /* b */ 718 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 719 } 720 break; 721 default: 722 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 723 hr = E_NOTIMPL; 724 } 725 break; 726 case 24: 727 for (i=0; i<This->header.colormap_length; i++) 728 { 729 *color++=0xff000000 | /* alpha */ 730 colormap_data[i*3+2] | /* red */ 731 colormap_data[i*3+1] | /* green */ 732 colormap_data[i*3]; /* blue */ 733 } 734 break; 735 case 32: 736 switch (attribute_type) 737 { 738 case ATTRIBUTE_NO_ALPHA: 739 case ATTRIBUTE_UNDEFINED: 740 case ATTRIBUTE_UNDEFINED_PRESERVE: 741 for (i=0; i<This->header.colormap_length; i++) 742 *color++=dwcolormap_data[i]|0xff000000; 743 break; 744 case ATTRIBUTE_ALPHA: 745 for (i=0; i<This->header.colormap_length; i++) 746 *color++=dwcolormap_data[i]; 747 break; 748 case ATTRIBUTE_PALPHA: 749 /* FIXME: Unpremultiply alpha */ 750 default: 751 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 752 hr = E_NOTIMPL; 753 } 754 break; 755 default: 756 FIXME("Unhandled truecolor depth %u\n", This->header.depth); 757 hr = E_NOTIMPL; 758 } 759 } 760 761 HeapFree(GetProcessHeap(), 0, colormap_data); 762 763 if (SUCCEEDED(hr)) 764 hr = IWICPalette_InitializeCustom(pIPalette, colors, 256); 765 766 return hr; 767 } 768 769 static HRESULT TgaDecoder_ReadRLE(TgaDecoder *This, BYTE *imagebits, int datasize) 770 { 771 int i=0, j, bytesperpixel; 772 ULONG bytesread; 773 HRESULT hr=S_OK; 774 775 bytesperpixel = This->header.depth / 8; 776 777 while (i<datasize) 778 { 779 BYTE rc; 780 int count, size; 781 BYTE pixeldata[4]; 782 783 hr = IStream_Read(This->stream, &rc, 1, &bytesread); 784 if (bytesread != 1) hr = E_FAIL; 785 if (FAILED(hr)) break; 786 787 count = (rc&0x7f)+1; 788 size = count * bytesperpixel; 789 790 if (size + i > datasize) 791 { 792 WARN("RLE packet too large\n"); 793 hr = E_FAIL; 794 break; 795 } 796 797 if (rc&0x80) 798 { 799 /* Run-length packet */ 800 hr = IStream_Read(This->stream, pixeldata, bytesperpixel, &bytesread); 801 if (bytesread != bytesperpixel) hr = E_FAIL; 802 if (FAILED(hr)) break; 803 804 if (bytesperpixel == 1) 805 memset(&imagebits[i], pixeldata[0], count); 806 else 807 { 808 for (j=0; j<count; j++) 809 memcpy(&imagebits[i+j*bytesperpixel], pixeldata, bytesperpixel); 810 } 811 } 812 else 813 { 814 /* Raw packet */ 815 hr = IStream_Read(This->stream, &imagebits[i], size, &bytesread); 816 if (bytesread != size) hr = E_FAIL; 817 if (FAILED(hr)) break; 818 } 819 820 i += size; 821 } 822 823 return hr; 824 } 825 826 static HRESULT TgaDecoder_ReadImage(TgaDecoder *This) 827 { 828 HRESULT hr=S_OK; 829 int datasize; 830 LARGE_INTEGER seek; 831 ULONG bytesread; 832 833 if (This->imagebits) 834 return S_OK; 835 836 EnterCriticalSection(&This->lock); 837 838 if (!This->imagebits) 839 { 840 if (This->header.image_descriptor & IMAGE_RIGHTTOLEFT) 841 { 842 FIXME("Right to left image reading not implemented\n"); 843 hr = E_NOTIMPL; 844 } 845 846 if (SUCCEEDED(hr)) 847 { 848 datasize = This->header.width * This->header.height * (This->header.depth / 8); 849 This->imagebits = HeapAlloc(GetProcessHeap(), 0, datasize); 850 if (!This->imagebits) hr = E_OUTOFMEMORY; 851 } 852 853 if (SUCCEEDED(hr)) 854 { 855 seek.QuadPart = This->image_offset; 856 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL); 857 } 858 859 if (SUCCEEDED(hr)) 860 { 861 if (This->header.image_type & IMAGETYPE_RLE) 862 { 863 hr = TgaDecoder_ReadRLE(This, This->imagebits, datasize); 864 } 865 else 866 { 867 hr = IStream_Read(This->stream, This->imagebits, datasize, &bytesread); 868 if (SUCCEEDED(hr) && bytesread != datasize) 869 hr = E_FAIL; 870 } 871 } 872 873 if (SUCCEEDED(hr)) 874 { 875 if (This->header.image_descriptor & IMAGE_TOPTOBOTTOM) 876 { 877 This->origin = This->imagebits; 878 This->stride = This->header.width * (This->header.depth / 8); 879 } 880 else 881 { 882 This->stride = -This->header.width * (This->header.depth / 8); 883 This->origin = This->imagebits + This->header.width * (This->header.height - 1) * (This->header.depth / 8); 884 } 885 } 886 else 887 { 888 HeapFree(GetProcessHeap(), 0, This->imagebits); 889 This->imagebits = NULL; 890 } 891 } 892 893 LeaveCriticalSection(&This->lock); 894 895 return hr; 896 } 897 898 static HRESULT WINAPI TgaDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, 899 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 900 { 901 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 902 HRESULT hr; 903 904 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 905 906 hr = TgaDecoder_ReadImage(This); 907 908 if (SUCCEEDED(hr)) 909 { 910 hr = copy_pixels(This->header.depth, This->origin, 911 This->header.width, This->header.height, This->stride, 912 prc, cbStride, cbBufferSize, pbBuffer); 913 } 914 915 return hr; 916 } 917 918 static HRESULT WINAPI TgaDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 919 IWICMetadataQueryReader **ppIMetadataQueryReader) 920 { 921 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 922 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 923 } 924 925 static HRESULT WINAPI TgaDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, 926 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 927 { 928 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 929 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 930 } 931 932 static HRESULT WINAPI TgaDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, 933 IWICBitmapSource **ppIThumbnail) 934 { 935 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 936 return WINCODEC_ERR_CODECNOTHUMBNAIL; 937 } 938 939 static const IWICBitmapFrameDecodeVtbl TgaDecoder_Frame_Vtbl = { 940 TgaDecoder_Frame_QueryInterface, 941 TgaDecoder_Frame_AddRef, 942 TgaDecoder_Frame_Release, 943 TgaDecoder_Frame_GetSize, 944 TgaDecoder_Frame_GetPixelFormat, 945 TgaDecoder_Frame_GetResolution, 946 TgaDecoder_Frame_CopyPalette, 947 TgaDecoder_Frame_CopyPixels, 948 TgaDecoder_Frame_GetMetadataQueryReader, 949 TgaDecoder_Frame_GetColorContexts, 950 TgaDecoder_Frame_GetThumbnail 951 }; 952 953 HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv) 954 { 955 TgaDecoder *This; 956 HRESULT ret; 957 958 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 959 960 *ppv = NULL; 961 962 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TgaDecoder)); 963 if (!This) return E_OUTOFMEMORY; 964 965 This->IWICBitmapDecoder_iface.lpVtbl = &TgaDecoder_Vtbl; 966 This->IWICBitmapFrameDecode_iface.lpVtbl = &TgaDecoder_Frame_Vtbl; 967 This->ref = 1; 968 This->initialized = FALSE; 969 This->stream = NULL; 970 This->imagebits = NULL; 971 InitializeCriticalSection(&This->lock); 972 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TgaDecoder.lock"); 973 974 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 975 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 976 977 return ret; 978 } 979