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