windowscodecs: Add support for decoding RLE8-encoded BMP files.
[wine] / dlls / windowscodecs / bmpdecode.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winreg.h"
28 #include "wingdi.h"
29 #include "objbase.h"
30 #include "wincodec.h"
31
32 #include "wincodecs_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37
38 typedef struct {
39     DWORD bc2Size;
40     DWORD bc2Width;
41     DWORD bc2Height;
42     WORD  bc2Planes;
43     WORD  bc2BitCount;
44     DWORD bc2Compression;
45     DWORD bc2SizeImage;
46     DWORD bc2XRes;
47     DWORD bc2YRes;
48     DWORD bc2ClrUsed;
49     DWORD bc2ClrImportant;
50     /* same as BITMAPINFOHEADER until this point */
51     WORD  bc2ResUnit;
52     WORD  bc2Reserved;
53     WORD  bc2Orientation;
54     WORD  bc2Halftoning;
55     DWORD bc2HalftoneSize1;
56     DWORD bc2HalftoneSize2;
57     DWORD bc2ColorSpace;
58     DWORD bc2AppData;
59 } BITMAPCOREHEADER2;
60
61 struct BmpFrameDecode;
62 typedef HRESULT (*ReadDataFunc)(struct BmpFrameDecode* This);
63
64 typedef struct BmpFrameDecode {
65     const IWICBitmapFrameDecodeVtbl *lpVtbl;
66     LONG ref;
67     IStream *stream;
68     BITMAPFILEHEADER bfh;
69     BITMAPV5HEADER bih;
70     const WICPixelFormatGUID *pixelformat;
71     int bitsperpixel;
72     ReadDataFunc read_data_func;
73     INT stride;
74     BYTE *imagedata;
75     BYTE *imagedatastart;
76 } BmpFrameDecode;
77
78 static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
79     void **ppv)
80 {
81     BmpFrameDecode *This = (BmpFrameDecode*)iface;
82     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
83
84     if (!ppv) return E_INVALIDARG;
85
86     if (IsEqualIID(&IID_IUnknown, iid) ||
87         IsEqualIID(&IID_IWICBitmapSource, iid) ||
88         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
89     {
90         *ppv = This;
91     }
92     else
93     {
94         *ppv = NULL;
95         return E_NOINTERFACE;
96     }
97
98     IUnknown_AddRef((IUnknown*)*ppv);
99     return S_OK;
100 }
101
102 static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
103 {
104     BmpFrameDecode *This = (BmpFrameDecode*)iface;
105     ULONG ref = InterlockedIncrement(&This->ref);
106
107     TRACE("(%p) refcount=%u\n", iface, ref);
108
109     return ref;
110 }
111
112 static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
113 {
114     BmpFrameDecode *This = (BmpFrameDecode*)iface;
115     ULONG ref = InterlockedDecrement(&This->ref);
116
117     TRACE("(%p) refcount=%u\n", iface, ref);
118
119     if (ref == 0)
120     {
121         IStream_Release(This->stream);
122         HeapFree(GetProcessHeap(), 0, This->imagedata);
123         HeapFree(GetProcessHeap(), 0, This);
124     }
125
126     return ref;
127 }
128
129 static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
130     UINT *puiWidth, UINT *puiHeight)
131 {
132     BmpFrameDecode *This = (BmpFrameDecode*)iface;
133     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
134
135     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
136     {
137         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
138         *puiWidth = bch->bcWidth;
139         *puiHeight = bch->bcHeight;
140     }
141     else
142     {
143         *puiWidth = This->bih.bV5Width;
144         *puiHeight = abs(This->bih.bV5Height);
145     }
146     return S_OK;
147 }
148
149 static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
150     WICPixelFormatGUID *pPixelFormat)
151 {
152     BmpFrameDecode *This = (BmpFrameDecode*)iface;
153     TRACE("(%p,%p)\n", iface, pPixelFormat);
154
155     memcpy(pPixelFormat, This->pixelformat, sizeof(GUID));
156
157     return S_OK;
158 }
159
160 static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY)
161 {
162     switch (bih->bV5Size)
163     {
164     case sizeof(BITMAPCOREHEADER):
165         *pDpiX = 96.0;
166         *pDpiY = 96.0;
167         return S_OK;
168     case sizeof(BITMAPCOREHEADER2):
169     case sizeof(BITMAPINFOHEADER):
170     case sizeof(BITMAPV4HEADER):
171     case sizeof(BITMAPV5HEADER):
172         *pDpiX = bih->bV5XPelsPerMeter * 0.0254;
173         *pDpiY = bih->bV5YPelsPerMeter * 0.0254;
174         return S_OK;
175     default:
176         return E_FAIL;
177     }
178 }
179
180 static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
181     double *pDpiX, double *pDpiY)
182 {
183     BmpFrameDecode *This = (BmpFrameDecode*)iface;
184     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
185
186     return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY);
187 }
188
189 static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
190     IWICPalette *pIPalette)
191 {
192     HRESULT hr;
193     BmpFrameDecode *This = (BmpFrameDecode*)iface;
194     TRACE("(%p,%p)\n", iface, pIPalette);
195
196     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
197     {
198         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
199         if (bch->bcBitCount <= 8)
200         {
201             /* 2**n colors in BGR format after the header */
202             int count = 1 << bch->bcBitCount;
203             WICColor *wiccolors;
204             ULONG tablesize, bytesread;
205             RGBTRIPLE *bgrcolors;
206             LARGE_INTEGER offset;
207             int i;
208
209             wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
210             tablesize = sizeof(RGBTRIPLE) * count;
211             bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
212             if (!wiccolors || !bgrcolors)
213             {
214                 HeapFree(GetProcessHeap(), 0, wiccolors);
215                 HeapFree(GetProcessHeap(), 0, bgrcolors);
216                 return E_OUTOFMEMORY;
217             }
218
219             offset.QuadPart = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER);
220             hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
221             if (FAILED(hr)) return hr;
222
223             hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread);
224             if (FAILED(hr)) return hr;
225             if (bytesread != tablesize) return E_FAIL;
226
227             for (i=0; i<count; i++)
228             {
229                 wiccolors[i] = 0xff000000|
230                                (bgrcolors[i].rgbtRed<<16)|
231                                (bgrcolors[i].rgbtGreen<<8)|
232                                bgrcolors[i].rgbtBlue;
233             }
234
235             hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
236
237             HeapFree(GetProcessHeap(), 0, wiccolors);
238             HeapFree(GetProcessHeap(), 0, bgrcolors);
239             return hr;
240         }
241         else
242         {
243             return WINCODEC_ERR_PALETTEUNAVAILABLE;
244         }
245     }
246     else
247     {
248         if (This->bih.bV5BitCount <= 8)
249         {
250             int count;
251             WICColor *wiccolors;
252             ULONG tablesize, bytesread;
253             LARGE_INTEGER offset;
254             int i;
255
256             if (This->bih.bV5ClrUsed == 0)
257                 count = 1 << This->bih.bV5BitCount;
258             else
259                 count = This->bih.bV5ClrUsed;
260
261             tablesize = sizeof(WICColor) * count;
262             wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
263             if (!wiccolors) return E_OUTOFMEMORY;
264
265             offset.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
266             hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
267             if (FAILED(hr)) return hr;
268
269             hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread);
270             if (FAILED(hr)) return hr;
271             if (bytesread != tablesize) return E_FAIL;
272
273             /* convert from BGR to BGRA by setting alpha to 100% */
274             for (i=0; i<count; i++)
275                 wiccolors[i] |= 0xff000000;
276
277             hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
278
279             HeapFree(GetProcessHeap(), 0, wiccolors);
280             return hr;
281         }
282         else
283         {
284             return WINCODEC_ERR_PALETTEUNAVAILABLE;
285         }
286     }
287 }
288
289 static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
290     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
291 {
292     BmpFrameDecode *This = (BmpFrameDecode*)iface;
293     HRESULT hr;
294     UINT width, height;
295     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
296
297     if (!This->imagedata)
298     {
299         hr = This->read_data_func(This);
300         if (FAILED(hr)) return hr;
301     }
302
303     hr = BmpFrameDecode_GetSize(iface, &width, &height);
304     if (FAILED(hr)) return hr;
305
306     return copy_pixels(This->bitsperpixel, This->imagedatastart,
307         width, height, This->stride,
308         prc, cbStride, cbBufferSize, pbBuffer);
309 }
310
311 static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
312     IWICMetadataQueryReader **ppIMetadataQueryReader)
313 {
314     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
315     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
316 }
317
318 static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
319     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
320 {
321     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
322     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
323 }
324
325 static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
326     IWICBitmapSource **ppIThumbnail)
327 {
328     TRACE("(%p,%p)\n", iface, ppIThumbnail);
329     return WINCODEC_ERR_CODECNOTHUMBNAIL;
330 }
331
332 static HRESULT BmpFrameDecode_ReadUncompressed(BmpFrameDecode* This)
333 {
334     UINT bytesperrow;
335     UINT width, height;
336     UINT datasize;
337     int bottomup;
338     HRESULT hr;
339     LARGE_INTEGER offbits;
340     ULONG bytesread;
341
342     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
343     {
344         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
345         width = bch->bcWidth;
346         height = bch->bcHeight;
347         bottomup = 1;
348     }
349     else
350     {
351         width = This->bih.bV5Width;
352         height = abs(This->bih.bV5Height);
353         bottomup = (This->bih.bV5Height > 0);
354     }
355
356     /* row sizes in BMP files must be divisible by 4 bytes */
357     bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
358     datasize = bytesperrow * height;
359
360     This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
361     if (!This->imagedata) return E_OUTOFMEMORY;
362
363     offbits.QuadPart = This->bfh.bfOffBits;
364     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
365     if (FAILED(hr)) goto fail;
366
367     hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread);
368     if (FAILED(hr) || bytesread != datasize) goto fail;
369
370     if (bottomup)
371     {
372         This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
373         This->stride = -bytesperrow;
374     }
375     else
376     {
377         This->imagedatastart = This->imagedata;
378         This->stride = bytesperrow;
379     }
380     return S_OK;
381
382 fail:
383     HeapFree(GetProcessHeap(), 0, This->imagedata);
384     This->imagedata = NULL;
385     if (SUCCEEDED(hr)) hr = E_FAIL;
386     return hr;
387 }
388
389 static HRESULT BmpFrameDecode_ReadRLE8(BmpFrameDecode* This)
390 {
391     UINT bytesperrow;
392     UINT width, height;
393     BYTE *rledata, *cursor, *rledataend;
394     UINT rlesize, datasize, palettesize;
395     DWORD palette[256];
396     UINT x, y;
397     DWORD *bgrdata;
398     HRESULT hr;
399     LARGE_INTEGER offbits;
400     ULONG bytesread;
401
402     width = This->bih.bV5Width;
403     height = abs(This->bih.bV5Height);
404     bytesperrow = width * 4;
405     datasize = bytesperrow * height;
406     rlesize = This->bih.bV5SizeImage;
407     if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256)
408         palettesize = 4 * This->bih.bV5ClrUsed;
409     else
410         palettesize = 4 * 256;
411
412     rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
413     This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
414     if (!This->imagedata || !rledata)
415     {
416         hr = E_OUTOFMEMORY;
417         goto fail;
418     }
419
420     /* read palette */
421     offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
422     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
423     if (FAILED(hr)) goto fail;
424
425     hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
426     if (FAILED(hr) || bytesread != palettesize) goto fail;
427
428     /* read RLE data */
429     offbits.QuadPart = This->bfh.bfOffBits;
430     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
431     if (FAILED(hr)) goto fail;
432
433     hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
434     if (FAILED(hr) || bytesread != rlesize) goto fail;
435
436     /* decode RLE */
437     bgrdata = (DWORD*)This->imagedata;
438     x = 0;
439     y = 0;
440     rledataend = rledata + rlesize;
441     cursor = rledata;
442     while (cursor < rledataend && y < height)
443     {
444         BYTE length = *cursor++;
445         if (length == 0)
446         {
447             /* escape code */
448             BYTE escape = *cursor++;
449             switch(escape)
450             {
451             case 0: /* end of line */
452                 x = 0;
453                 y++;
454                 break;
455             case 1: /* end of bitmap */
456                 goto end;
457             case 2: /* delta */
458                 if (cursor < rledataend)
459                 {
460                     x += *cursor++;
461                     y += *cursor++;
462                 }
463                 break;
464             default: /* absolute mode */
465                 length = escape;
466                 while (cursor < rledataend && length-- && x < width)
467                     bgrdata[y*width + x++] = palette[*cursor++];
468                 if (escape & 1) cursor++; /* skip pad byte */
469             }
470         }
471         else
472         {
473             DWORD color = palette[*cursor++];
474             while (length-- && x < width)
475                 bgrdata[y*width + x++] = color;
476         }
477     }
478
479 end:
480     HeapFree(GetProcessHeap(), 0, rledata);
481
482     This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
483     This->stride = -bytesperrow;
484
485     return S_OK;
486
487 fail:
488     HeapFree(GetProcessHeap(), 0, rledata);
489     HeapFree(GetProcessHeap(), 0, This->imagedata);
490     This->imagedata = NULL;
491     if (SUCCEEDED(hr)) hr = E_FAIL;
492     return hr;
493 }
494
495 static HRESULT BmpFrameDecode_ReadUnsupported(BmpFrameDecode* This)
496 {
497     return E_FAIL;
498 }
499
500 static const IWICBitmapFrameDecodeVtbl BmpFrameDecode_Vtbl = {
501     BmpFrameDecode_QueryInterface,
502     BmpFrameDecode_AddRef,
503     BmpFrameDecode_Release,
504     BmpFrameDecode_GetSize,
505     BmpFrameDecode_GetPixelFormat,
506     BmpFrameDecode_GetResolution,
507     BmpFrameDecode_CopyPalette,
508     BmpFrameDecode_CopyPixels,
509     BmpFrameDecode_GetMetadataQueryReader,
510     BmpFrameDecode_GetColorContexts,
511     BmpFrameDecode_GetThumbnail
512 };
513
514 typedef struct {
515     const IWICBitmapDecoderVtbl *lpVtbl;
516     LONG ref;
517     BOOL initialized;
518     IStream *stream;
519     BITMAPFILEHEADER bfh;
520     BITMAPV5HEADER bih;
521     BmpFrameDecode *framedecode;
522     const WICPixelFormatGUID *pixelformat;
523     int bitsperpixel;
524     ReadDataFunc read_data_func;
525 } BmpDecoder;
526
527 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
528 {
529     HRESULT hr;
530     ULONG bytestoread, bytesread;
531     LARGE_INTEGER seek;
532
533     if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
534
535     seek.QuadPart = 0;
536     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
537     if (FAILED(hr)) return hr;
538
539     hr = IStream_Read(stream, &This->bfh, sizeof(BITMAPFILEHEADER), &bytesread);
540     if (FAILED(hr)) return hr;
541     if (bytesread != sizeof(BITMAPFILEHEADER) ||
542         This->bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
543
544     hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
545     if (FAILED(hr)) return hr;
546     if (bytesread != sizeof(DWORD) ||
547         (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) &&
548          This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) &&
549          This->bih.bV5Size != sizeof(BITMAPINFOHEADER) &&
550          This->bih.bV5Size != sizeof(BITMAPV4HEADER) &&
551          This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL;
552
553     bytestoread = This->bih.bV5Size-sizeof(DWORD);
554     hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread);
555     if (FAILED(hr)) return hr;
556     if (bytestoread != bytesread) return E_FAIL;
557
558     /* decide what kind of bitmap this is and how/if we can read it */
559     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
560     {
561         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
562         TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
563         This->bitsperpixel = bch->bcBitCount;
564         This->read_data_func = BmpFrameDecode_ReadUncompressed;
565         switch(bch->bcBitCount)
566         {
567         case 1:
568             This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
569             break;
570         case 2:
571             This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
572             break;
573         case 4:
574             This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
575             break;
576         case 8:
577             This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
578             break;
579         case 24:
580             This->pixelformat = &GUID_WICPixelFormat24bppBGR;
581             break;
582         default:
583             This->pixelformat = &GUID_WICPixelFormatUndefined;
584             WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
585             break;
586         }
587     }
588     else /* struct is compatible with BITMAPINFOHEADER */
589     {
590         TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
591         switch(This->bih.bV5Compression)
592         {
593         case BI_RGB:
594             This->bitsperpixel = This->bih.bV5BitCount;
595             This->read_data_func = BmpFrameDecode_ReadUncompressed;
596             switch(This->bih.bV5BitCount)
597             {
598             case 1:
599                 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
600                 break;
601             case 2:
602                 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
603                 break;
604             case 4:
605                 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
606                 break;
607             case 8:
608                 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
609                 break;
610             case 16:
611                 This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
612                 break;
613             case 24:
614                 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
615                 break;
616             case 32:
617                 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
618                 break;
619             default:
620                 This->pixelformat = &GUID_WICPixelFormatUndefined;
621                 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
622             }
623             break;
624         case BI_RLE8:
625             This->bitsperpixel = 32;
626             This->read_data_func = BmpFrameDecode_ReadRLE8;
627             This->pixelformat = &GUID_WICPixelFormat32bppBGR;
628             break;
629         default:
630             This->bitsperpixel = 0;
631             This->read_data_func = BmpFrameDecode_ReadUnsupported;
632             This->pixelformat = &GUID_WICPixelFormatUndefined;
633             FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
634             break;
635         }
636     }
637
638     This->initialized = TRUE;
639
640     return S_OK;
641 }
642
643 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
644     void **ppv)
645 {
646     BmpDecoder *This = (BmpDecoder*)iface;
647     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
648
649     if (!ppv) return E_INVALIDARG;
650
651     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
652     {
653         *ppv = This;
654     }
655     else
656     {
657         *ppv = NULL;
658         return E_NOINTERFACE;
659     }
660
661     IUnknown_AddRef((IUnknown*)*ppv);
662     return S_OK;
663 }
664
665 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
666 {
667     BmpDecoder *This = (BmpDecoder*)iface;
668     ULONG ref = InterlockedIncrement(&This->ref);
669
670     TRACE("(%p) refcount=%u\n", iface, ref);
671
672     return ref;
673 }
674
675 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
676 {
677     BmpDecoder *This = (BmpDecoder*)iface;
678     ULONG ref = InterlockedDecrement(&This->ref);
679
680     TRACE("(%p) refcount=%u\n", iface, ref);
681
682     if (ref == 0)
683     {
684         if (This->stream) IStream_Release(This->stream);
685         if (This->framedecode) IUnknown_Release((IUnknown*)This->framedecode);
686         HeapFree(GetProcessHeap(), 0, This);
687     }
688
689     return ref;
690 }
691
692 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
693     DWORD *pdwCapability)
694 {
695     HRESULT hr;
696     BmpDecoder *This = (BmpDecoder*)iface;
697
698     hr = BmpDecoder_ReadHeaders(This, pIStream);
699     if (FAILED(hr)) return hr;
700
701     if (This->read_data_func == BmpFrameDecode_ReadUnsupported)
702         *pdwCapability = 0;
703     else
704         *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages;
705
706     return S_OK;
707 }
708
709 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
710     WICDecodeOptions cacheOptions)
711 {
712     HRESULT hr;
713     BmpDecoder *This = (BmpDecoder*)iface;
714
715     hr = BmpDecoder_ReadHeaders(This, pIStream);
716
717     if (SUCCEEDED(hr))
718     {
719         This->stream = pIStream;
720         IStream_AddRef(pIStream);
721     }
722
723     return hr;
724 }
725
726 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
727     GUID *pguidContainerFormat)
728 {
729     memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
730     return S_OK;
731 }
732
733 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
734     IWICBitmapDecoderInfo **ppIDecoderInfo)
735 {
736     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
737     return E_NOTIMPL;
738 }
739
740 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
741     IWICPalette *pIPalette)
742 {
743     TRACE("(%p,%p)\n", iface, pIPalette);
744
745     return WINCODEC_ERR_PALETTEUNAVAILABLE;
746 }
747
748 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
749     IWICMetadataQueryReader **ppIMetadataQueryReader)
750 {
751     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
752     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
753 }
754
755 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface,
756     IWICBitmapSource **ppIBitmapSource)
757 {
758     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
759     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
760 }
761
762 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface,
763     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
764 {
765     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
766     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
767 }
768
769 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
770     IWICBitmapSource **ppIThumbnail)
771 {
772     TRACE("(%p,%p)\n", iface, ppIThumbnail);
773     return WINCODEC_ERR_CODECNOTHUMBNAIL;
774 }
775
776 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
777     UINT *pCount)
778 {
779     *pCount = 1;
780     return S_OK;
781 }
782
783 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
784     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
785 {
786     BmpDecoder *This = (BmpDecoder*)iface;
787
788     if (index != 0) return E_INVALIDARG;
789
790     if (!This->stream) return WINCODEC_ERR_WRONGSTATE;
791
792     if (!This->framedecode)
793     {
794         This->framedecode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameDecode));
795         if (!This->framedecode) return E_OUTOFMEMORY;
796
797         This->framedecode->lpVtbl = &BmpFrameDecode_Vtbl;
798         This->framedecode->ref = 1;
799         This->framedecode->stream = This->stream;
800         IStream_AddRef(This->stream);
801         This->framedecode->bfh = This->bfh;
802         This->framedecode->bih = This->bih;
803         This->framedecode->pixelformat = This->pixelformat;
804         This->framedecode->bitsperpixel = This->bitsperpixel;
805         This->framedecode->read_data_func = This->read_data_func;
806         This->framedecode->imagedata = NULL;
807     }
808
809     *ppIBitmapFrame = (IWICBitmapFrameDecode*)This->framedecode;
810     IWICBitmapFrameDecode_AddRef((IWICBitmapFrameDecode*)This->framedecode);
811
812     return S_OK;
813 }
814
815 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
816     BmpDecoder_QueryInterface,
817     BmpDecoder_AddRef,
818     BmpDecoder_Release,
819     BmpDecoder_QueryCapability,
820     BmpDecoder_Initialize,
821     BmpDecoder_GetContainerFormat,
822     BmpDecoder_GetDecoderInfo,
823     BmpDecoder_CopyPalette,
824     BmpDecoder_GetMetadataQueryReader,
825     BmpDecoder_GetPreview,
826     BmpDecoder_GetColorContexts,
827     BmpDecoder_GetThumbnail,
828     BmpDecoder_GetFrameCount,
829     BmpDecoder_GetFrame
830 };
831
832 HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
833 {
834     BmpDecoder *This;
835     HRESULT ret;
836
837     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
838
839     *ppv = NULL;
840
841     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
842
843     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
844     if (!This) return E_OUTOFMEMORY;
845
846     This->lpVtbl = &BmpDecoder_Vtbl;
847     This->ref = 1;
848     This->initialized = FALSE;
849     This->stream = NULL;
850     This->framedecode = NULL;
851
852     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
853     IUnknown_Release((IUnknown*)This);
854
855     return ret;
856 }