jscript: Added String_link implementation.
[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_ReadRLE4(BmpFrameDecode* This)
496 {
497     UINT bytesperrow;
498     UINT width, height;
499     BYTE *rledata, *cursor, *rledataend;
500     UINT rlesize, datasize, palettesize;
501     DWORD palette[16];
502     UINT x, y;
503     DWORD *bgrdata;
504     HRESULT hr;
505     LARGE_INTEGER offbits;
506     ULONG bytesread;
507
508     width = This->bih.bV5Width;
509     height = abs(This->bih.bV5Height);
510     bytesperrow = width * 4;
511     datasize = bytesperrow * height;
512     rlesize = This->bih.bV5SizeImage;
513     if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16)
514         palettesize = 4 * This->bih.bV5ClrUsed;
515     else
516         palettesize = 4 * 16;
517
518     rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
519     This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
520     if (!This->imagedata || !rledata)
521     {
522         hr = E_OUTOFMEMORY;
523         goto fail;
524     }
525
526     /* read palette */
527     offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
528     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
529     if (FAILED(hr)) goto fail;
530
531     hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
532     if (FAILED(hr) || bytesread != palettesize) goto fail;
533
534     /* read RLE data */
535     offbits.QuadPart = This->bfh.bfOffBits;
536     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
537     if (FAILED(hr)) goto fail;
538
539     hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
540     if (FAILED(hr) || bytesread != rlesize) goto fail;
541
542     /* decode RLE */
543     bgrdata = (DWORD*)This->imagedata;
544     x = 0;
545     y = 0;
546     rledataend = rledata + rlesize;
547     cursor = rledata;
548     while (cursor < rledataend && y < height)
549     {
550         BYTE length = *cursor++;
551         if (length == 0)
552         {
553             /* escape code */
554             BYTE escape = *cursor++;
555             switch(escape)
556             {
557             case 0: /* end of line */
558                 x = 0;
559                 y++;
560                 break;
561             case 1: /* end of bitmap */
562                 goto end;
563             case 2: /* delta */
564                 if (cursor < rledataend)
565                 {
566                     x += *cursor++;
567                     y += *cursor++;
568                 }
569                 break;
570             default: /* absolute mode */
571                 length = escape;
572                 while (cursor < rledataend && length-- && x < width)
573                 {
574                     BYTE colors = *cursor++;
575                     bgrdata[y*width + x++] = palette[colors>>4];
576                     if (length-- && x < width)
577                         bgrdata[y*width + x++] = palette[colors&0xf];
578                     else
579                         break;
580                 }
581                 if ((cursor - rledata) & 1) cursor++; /* skip pad byte */
582             }
583         }
584         else
585         {
586             BYTE colors = *cursor++;
587             DWORD color1 = palette[colors>>4];
588             DWORD color2 = palette[colors&0xf];
589             while (length-- && x < width)
590             {
591                 bgrdata[y*width + x++] = color1;
592                 if (length-- && x < width)
593                     bgrdata[y*width + x++] = color2;
594                 else
595                     break;
596             }
597         }
598     }
599
600 end:
601     HeapFree(GetProcessHeap(), 0, rledata);
602
603     This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
604     This->stride = -bytesperrow;
605
606     return S_OK;
607
608 fail:
609     HeapFree(GetProcessHeap(), 0, rledata);
610     HeapFree(GetProcessHeap(), 0, This->imagedata);
611     This->imagedata = NULL;
612     if (SUCCEEDED(hr)) hr = E_FAIL;
613     return hr;
614 }
615
616 static HRESULT BmpFrameDecode_ReadUnsupported(BmpFrameDecode* This)
617 {
618     return E_FAIL;
619 }
620
621 static const IWICBitmapFrameDecodeVtbl BmpFrameDecode_Vtbl = {
622     BmpFrameDecode_QueryInterface,
623     BmpFrameDecode_AddRef,
624     BmpFrameDecode_Release,
625     BmpFrameDecode_GetSize,
626     BmpFrameDecode_GetPixelFormat,
627     BmpFrameDecode_GetResolution,
628     BmpFrameDecode_CopyPalette,
629     BmpFrameDecode_CopyPixels,
630     BmpFrameDecode_GetMetadataQueryReader,
631     BmpFrameDecode_GetColorContexts,
632     BmpFrameDecode_GetThumbnail
633 };
634
635 typedef struct {
636     const IWICBitmapDecoderVtbl *lpVtbl;
637     LONG ref;
638     BOOL initialized;
639     IStream *stream;
640     BITMAPFILEHEADER bfh;
641     BITMAPV5HEADER bih;
642     BmpFrameDecode *framedecode;
643     const WICPixelFormatGUID *pixelformat;
644     int bitsperpixel;
645     ReadDataFunc read_data_func;
646 } BmpDecoder;
647
648 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
649 {
650     HRESULT hr;
651     ULONG bytestoread, bytesread;
652     LARGE_INTEGER seek;
653
654     if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
655
656     seek.QuadPart = 0;
657     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
658     if (FAILED(hr)) return hr;
659
660     hr = IStream_Read(stream, &This->bfh, sizeof(BITMAPFILEHEADER), &bytesread);
661     if (FAILED(hr)) return hr;
662     if (bytesread != sizeof(BITMAPFILEHEADER) ||
663         This->bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
664
665     hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
666     if (FAILED(hr)) return hr;
667     if (bytesread != sizeof(DWORD) ||
668         (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) &&
669          This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) &&
670          This->bih.bV5Size != sizeof(BITMAPINFOHEADER) &&
671          This->bih.bV5Size != sizeof(BITMAPV4HEADER) &&
672          This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL;
673
674     bytestoread = This->bih.bV5Size-sizeof(DWORD);
675     hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread);
676     if (FAILED(hr)) return hr;
677     if (bytestoread != bytesread) return E_FAIL;
678
679     /* decide what kind of bitmap this is and how/if we can read it */
680     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
681     {
682         BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
683         TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
684         This->bitsperpixel = bch->bcBitCount;
685         This->read_data_func = BmpFrameDecode_ReadUncompressed;
686         switch(bch->bcBitCount)
687         {
688         case 1:
689             This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
690             break;
691         case 2:
692             This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
693             break;
694         case 4:
695             This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
696             break;
697         case 8:
698             This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
699             break;
700         case 24:
701             This->pixelformat = &GUID_WICPixelFormat24bppBGR;
702             break;
703         default:
704             This->pixelformat = &GUID_WICPixelFormatUndefined;
705             WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
706             break;
707         }
708     }
709     else /* struct is compatible with BITMAPINFOHEADER */
710     {
711         TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
712         switch(This->bih.bV5Compression)
713         {
714         case BI_RGB:
715             This->bitsperpixel = This->bih.bV5BitCount;
716             This->read_data_func = BmpFrameDecode_ReadUncompressed;
717             switch(This->bih.bV5BitCount)
718             {
719             case 1:
720                 This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
721                 break;
722             case 2:
723                 This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
724                 break;
725             case 4:
726                 This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
727                 break;
728             case 8:
729                 This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
730                 break;
731             case 16:
732                 This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
733                 break;
734             case 24:
735                 This->pixelformat = &GUID_WICPixelFormat24bppBGR;
736                 break;
737             case 32:
738                 This->pixelformat = &GUID_WICPixelFormat32bppBGR;
739                 break;
740             default:
741                 This->pixelformat = &GUID_WICPixelFormatUndefined;
742                 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
743             }
744             break;
745         case BI_RLE8:
746             This->bitsperpixel = 32;
747             This->read_data_func = BmpFrameDecode_ReadRLE8;
748             This->pixelformat = &GUID_WICPixelFormat32bppBGR;
749             break;
750         case BI_RLE4:
751             This->bitsperpixel = 32;
752             This->read_data_func = BmpFrameDecode_ReadRLE4;
753             This->pixelformat = &GUID_WICPixelFormat32bppBGR;
754             break;
755         default:
756             This->bitsperpixel = 0;
757             This->read_data_func = BmpFrameDecode_ReadUnsupported;
758             This->pixelformat = &GUID_WICPixelFormatUndefined;
759             FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
760             break;
761         }
762     }
763
764     This->initialized = TRUE;
765
766     return S_OK;
767 }
768
769 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
770     void **ppv)
771 {
772     BmpDecoder *This = (BmpDecoder*)iface;
773     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
774
775     if (!ppv) return E_INVALIDARG;
776
777     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
778     {
779         *ppv = This;
780     }
781     else
782     {
783         *ppv = NULL;
784         return E_NOINTERFACE;
785     }
786
787     IUnknown_AddRef((IUnknown*)*ppv);
788     return S_OK;
789 }
790
791 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
792 {
793     BmpDecoder *This = (BmpDecoder*)iface;
794     ULONG ref = InterlockedIncrement(&This->ref);
795
796     TRACE("(%p) refcount=%u\n", iface, ref);
797
798     return ref;
799 }
800
801 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
802 {
803     BmpDecoder *This = (BmpDecoder*)iface;
804     ULONG ref = InterlockedDecrement(&This->ref);
805
806     TRACE("(%p) refcount=%u\n", iface, ref);
807
808     if (ref == 0)
809     {
810         if (This->stream) IStream_Release(This->stream);
811         if (This->framedecode) IUnknown_Release((IUnknown*)This->framedecode);
812         HeapFree(GetProcessHeap(), 0, This);
813     }
814
815     return ref;
816 }
817
818 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
819     DWORD *pdwCapability)
820 {
821     HRESULT hr;
822     BmpDecoder *This = (BmpDecoder*)iface;
823
824     hr = BmpDecoder_ReadHeaders(This, pIStream);
825     if (FAILED(hr)) return hr;
826
827     if (This->read_data_func == BmpFrameDecode_ReadUnsupported)
828         *pdwCapability = 0;
829     else
830         *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages;
831
832     return S_OK;
833 }
834
835 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
836     WICDecodeOptions cacheOptions)
837 {
838     HRESULT hr;
839     BmpDecoder *This = (BmpDecoder*)iface;
840
841     hr = BmpDecoder_ReadHeaders(This, pIStream);
842
843     if (SUCCEEDED(hr))
844     {
845         This->stream = pIStream;
846         IStream_AddRef(pIStream);
847     }
848
849     return hr;
850 }
851
852 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
853     GUID *pguidContainerFormat)
854 {
855     memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
856     return S_OK;
857 }
858
859 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
860     IWICBitmapDecoderInfo **ppIDecoderInfo)
861 {
862     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
863     return E_NOTIMPL;
864 }
865
866 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
867     IWICPalette *pIPalette)
868 {
869     TRACE("(%p,%p)\n", iface, pIPalette);
870
871     return WINCODEC_ERR_PALETTEUNAVAILABLE;
872 }
873
874 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
875     IWICMetadataQueryReader **ppIMetadataQueryReader)
876 {
877     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
878     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
879 }
880
881 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface,
882     IWICBitmapSource **ppIBitmapSource)
883 {
884     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
885     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
886 }
887
888 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface,
889     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
890 {
891     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
892     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
893 }
894
895 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
896     IWICBitmapSource **ppIThumbnail)
897 {
898     TRACE("(%p,%p)\n", iface, ppIThumbnail);
899     return WINCODEC_ERR_CODECNOTHUMBNAIL;
900 }
901
902 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
903     UINT *pCount)
904 {
905     *pCount = 1;
906     return S_OK;
907 }
908
909 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
910     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
911 {
912     BmpDecoder *This = (BmpDecoder*)iface;
913
914     if (index != 0) return E_INVALIDARG;
915
916     if (!This->stream) return WINCODEC_ERR_WRONGSTATE;
917
918     if (!This->framedecode)
919     {
920         This->framedecode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameDecode));
921         if (!This->framedecode) return E_OUTOFMEMORY;
922
923         This->framedecode->lpVtbl = &BmpFrameDecode_Vtbl;
924         This->framedecode->ref = 1;
925         This->framedecode->stream = This->stream;
926         IStream_AddRef(This->stream);
927         This->framedecode->bfh = This->bfh;
928         This->framedecode->bih = This->bih;
929         This->framedecode->pixelformat = This->pixelformat;
930         This->framedecode->bitsperpixel = This->bitsperpixel;
931         This->framedecode->read_data_func = This->read_data_func;
932         This->framedecode->imagedata = NULL;
933     }
934
935     *ppIBitmapFrame = (IWICBitmapFrameDecode*)This->framedecode;
936     IWICBitmapFrameDecode_AddRef((IWICBitmapFrameDecode*)This->framedecode);
937
938     return S_OK;
939 }
940
941 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
942     BmpDecoder_QueryInterface,
943     BmpDecoder_AddRef,
944     BmpDecoder_Release,
945     BmpDecoder_QueryCapability,
946     BmpDecoder_Initialize,
947     BmpDecoder_GetContainerFormat,
948     BmpDecoder_GetDecoderInfo,
949     BmpDecoder_CopyPalette,
950     BmpDecoder_GetMetadataQueryReader,
951     BmpDecoder_GetPreview,
952     BmpDecoder_GetColorContexts,
953     BmpDecoder_GetThumbnail,
954     BmpDecoder_GetFrameCount,
955     BmpDecoder_GetFrame
956 };
957
958 HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
959 {
960     BmpDecoder *This;
961     HRESULT ret;
962
963     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
964
965     *ppv = NULL;
966
967     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
968
969     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
970     if (!This) return E_OUTOFMEMORY;
971
972     This->lpVtbl = &BmpDecoder_Vtbl;
973     This->ref = 1;
974     This->initialized = FALSE;
975     This->stream = NULL;
976     This->framedecode = NULL;
977
978     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
979     IUnknown_Release((IUnknown*)This);
980
981     return ret;
982 }