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