oleaut32: Implement ITypeLibComp::BindType.
[wine] / dlls / windowscodecs / icoformat.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 "wingdi.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30
31 #include "wincodecs_private.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36
37 #include "pshpack1.h"
38
39 typedef struct {
40     BYTE bWidth;
41     BYTE bHeight;
42     BYTE bColorCount;
43     BYTE bReserved;
44     WORD wPlanes;
45     WORD wBitCount;
46     DWORD dwDIBSize;
47     DWORD dwDIBOffset;
48 } ICONDIRENTRY;
49
50 typedef struct
51 {
52     WORD idReserved;
53     WORD idType;
54     WORD idCount;
55 } ICONHEADER;
56
57 #include "poppack.h"
58
59 typedef struct {
60     const IWICBitmapDecoderVtbl *lpVtbl;
61     LONG ref;
62     BOOL initialized;
63     IStream *stream;
64     ICONHEADER header;
65 } IcoDecoder;
66
67 typedef struct {
68     const IWICBitmapFrameDecodeVtbl *lpVtbl;
69     LONG ref;
70     ICONDIRENTRY entry;
71     IcoDecoder *parent;
72     BYTE *bits;
73 } IcoFrameDecode;
74
75 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
76     void **ppv)
77 {
78     IcoFrameDecode *This = (IcoFrameDecode*)iface;
79     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
80
81     if (!ppv) return E_INVALIDARG;
82
83     if (IsEqualIID(&IID_IUnknown, iid) ||
84         IsEqualIID(&IID_IWICBitmapSource, iid) ||
85         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
86     {
87         *ppv = This;
88     }
89     else
90     {
91         *ppv = NULL;
92         return E_NOINTERFACE;
93     }
94
95     IUnknown_AddRef((IUnknown*)*ppv);
96     return S_OK;
97 }
98
99 static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
100 {
101     IcoFrameDecode *This = (IcoFrameDecode*)iface;
102     ULONG ref = InterlockedIncrement(&This->ref);
103
104     TRACE("(%p) refcount=%u\n", iface, ref);
105
106     return ref;
107 }
108
109 static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
110 {
111     IcoFrameDecode *This = (IcoFrameDecode*)iface;
112     ULONG ref = InterlockedDecrement(&This->ref);
113
114     TRACE("(%p) refcount=%u\n", iface, ref);
115
116     if (ref == 0)
117     {
118         IUnknown_Release((IUnknown*)This->parent);
119         HeapFree(GetProcessHeap(), 0, This->bits);
120         HeapFree(GetProcessHeap(), 0, This);
121     }
122
123     return ref;
124 }
125
126 static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
127     UINT *puiWidth, UINT *puiHeight)
128 {
129     IcoFrameDecode *This = (IcoFrameDecode*)iface;
130
131     *puiWidth = This->entry.bWidth ? This->entry.bWidth : 256;
132     *puiHeight = This->entry.bHeight ? This->entry.bHeight : 256;
133
134     TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
135
136     return S_OK;
137 }
138
139 static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
140     WICPixelFormatGUID *pPixelFormat)
141 {
142     memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
143     return S_OK;
144 }
145
146 static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
147     double *pDpiX, double *pDpiY)
148 {
149     FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
150     return E_NOTIMPL;
151 }
152
153 static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
154     IWICPalette *pIPalette)
155 {
156     TRACE("(%p,%p)\n", iface, pIPalette);
157     return WINCODEC_ERR_PALETTEUNAVAILABLE;
158 }
159
160 static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
161 {
162     if (transparent) *pixel = 0;
163     else *pixel |= 0xff000000;
164 }
165
166 static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
167 {
168     BITMAPINFOHEADER bih;
169     DWORD colors[256];
170     UINT colorcount=0;
171     LARGE_INTEGER seek;
172     ULONG bytesread;
173     HRESULT hr;
174     BYTE *tempdata = NULL;
175     BYTE *bits = NULL;
176     UINT bitsStride;
177     UINT bitsSize;
178     UINT width, height;
179
180     width = This->entry.bWidth ? This->entry.bWidth : 256;
181     height = This->entry.bHeight ? This->entry.bHeight : 256;
182
183     /* read the BITMAPINFOHEADER */
184     seek.QuadPart = This->entry.dwDIBOffset;
185     hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL);
186     if (FAILED(hr)) goto fail;
187
188     hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
189     if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
190
191     if (This->entry.wBitCount <= 8)
192     {
193         /* read the palette */
194         colorcount = This->entry.bColorCount ? This->entry.bColorCount : 256;
195
196         hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
197         if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
198     }
199
200     bitsStride = width * 4;
201     bitsSize = bitsStride * height;
202
203     /* read the XOR data */
204     switch (This->entry.wBitCount)
205     {
206     case 1:
207     {
208         UINT xorBytesPerRow = (width+31)/32*4;
209         UINT xorBytes = xorBytesPerRow * height;
210         INT xorStride;
211         BYTE *xorRow;
212         BYTE *bitsRow;
213         UINT x, y;
214
215         tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
216         if (!tempdata)
217         {
218             hr = E_OUTOFMEMORY;
219             goto fail;
220         }
221
222         hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
223         if (FAILED(hr) || bytesread != xorBytes) goto fail;
224
225         if (bih.biHeight > 0) /* bottom-up DIB */
226         {
227             xorStride = -xorBytesPerRow;
228             xorRow = tempdata + (height-1)*xorBytesPerRow;
229         }
230         else /* top-down DIB */
231         {
232             xorStride = xorBytesPerRow;
233             xorRow = tempdata;
234         }
235
236         bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
237
238         /* palette-map the 1-bit data */
239         bitsRow = bits;
240         for (y=0; y<height; y++) {
241             BYTE *xorByte=xorRow;
242             DWORD *bitsPixel=(DWORD*)bitsRow;
243             for (x=0; x<width; x+=8) {
244                 BYTE xorVal;
245                 xorVal=*xorByte++;
246                 *bitsPixel++ = colors[xorVal>>7];
247                 if (x+1 < width) *bitsPixel++ = colors[xorVal>>6&1];
248                 if (x+2 < width) *bitsPixel++ = colors[xorVal>>5&1];
249                 if (x+3 < width) *bitsPixel++ = colors[xorVal>>4&1];
250                 if (x+4 < width) *bitsPixel++ = colors[xorVal>>3&1];
251                 if (x+5 < width) *bitsPixel++ = colors[xorVal>>2&1];
252                 if (x+6 < width) *bitsPixel++ = colors[xorVal>>1&1];
253                 if (x+7 < width) *bitsPixel++ = colors[xorVal&1];
254             }
255             xorRow += xorStride;
256             bitsRow += bitsStride;
257         }
258
259         HeapFree(GetProcessHeap(), 0, tempdata);
260         break;
261     }
262     case 4:
263     {
264         UINT xorBytesPerRow = (width+7)/8*4;
265         UINT xorBytes = xorBytesPerRow * height;
266         INT xorStride;
267         BYTE *xorRow;
268         BYTE *bitsRow;
269         UINT x, y;
270
271         tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
272         if (!tempdata)
273         {
274             hr = E_OUTOFMEMORY;
275             goto fail;
276         }
277
278         hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
279         if (FAILED(hr) || bytesread != xorBytes) goto fail;
280
281         if (bih.biHeight > 0) /* bottom-up DIB */
282         {
283             xorStride = -xorBytesPerRow;
284             xorRow = tempdata + (height-1)*xorBytesPerRow;
285         }
286         else /* top-down DIB */
287         {
288             xorStride = xorBytesPerRow;
289             xorRow = tempdata;
290         }
291
292         bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
293
294         /* palette-map the 4-bit data */
295         bitsRow = bits;
296         for (y=0; y<height; y++) {
297             BYTE *xorByte=xorRow;
298             DWORD *bitsPixel=(DWORD*)bitsRow;
299             for (x=0; x<width; x+=2) {
300                 BYTE xorVal;
301                 xorVal=*xorByte++;
302                 *bitsPixel++ = colors[xorVal>>4];
303                 if (x+1 < width) *bitsPixel++ = colors[xorVal&0xf];
304             }
305             xorRow += xorStride;
306             bitsRow += bitsStride;
307         }
308
309         HeapFree(GetProcessHeap(), 0, tempdata);
310         break;
311     }
312     case 8:
313     {
314         UINT xorBytesPerRow = (width+3)/4*4;
315         UINT xorBytes = xorBytesPerRow * height;
316         INT xorStride;
317         BYTE *xorRow;
318         BYTE *bitsRow;
319         UINT x, y;
320
321         tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
322         if (!tempdata)
323         {
324             hr = E_OUTOFMEMORY;
325             goto fail;
326         }
327
328         hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
329         if (FAILED(hr) || bytesread != xorBytes) goto fail;
330
331         if (bih.biHeight > 0) /* bottom-up DIB */
332         {
333             xorStride = -xorBytesPerRow;
334             xorRow = tempdata + (height-1)*xorBytesPerRow;
335         }
336         else /* top-down DIB */
337         {
338             xorStride = xorBytesPerRow;
339             xorRow = tempdata;
340         }
341
342         bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
343
344         /* palette-map the 8-bit data */
345         bitsRow = bits;
346         for (y=0; y<height; y++) {
347             BYTE *xorByte=xorRow;
348             DWORD *bitsPixel=(DWORD*)bitsRow;
349             for (x=0; x<width; x++)
350                 *bitsPixel++ = colors[*xorByte++];
351             xorRow += xorStride;
352             bitsRow += bitsStride;
353         }
354
355         HeapFree(GetProcessHeap(), 0, tempdata);
356         break;
357     }
358     case 24:
359     {
360         UINT xorBytesPerRow = (width*3+3)/4*4;
361         UINT xorBytes = xorBytesPerRow * height;
362         INT xorStride;
363         BYTE *xorRow;
364         BYTE *bitsRow;
365         UINT x, y;
366
367         tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
368         if (!tempdata)
369         {
370             hr = E_OUTOFMEMORY;
371             goto fail;
372         }
373
374         hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
375         if (FAILED(hr) || bytesread != xorBytes) goto fail;
376
377         if (bih.biHeight > 0) /* bottom-up DIB */
378         {
379             xorStride = -xorBytesPerRow;
380             xorRow = tempdata + (height-1)*xorBytesPerRow;
381         }
382         else /* top-down DIB */
383         {
384             xorStride = xorBytesPerRow;
385             xorRow = tempdata;
386         }
387
388         bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
389
390         /* copy BGR->BGRA */
391         bitsRow = bits;
392         for (y=0; y<height; y++) {
393             BYTE *xorByte=xorRow;
394             BYTE *bitsByte=bitsRow;
395             for (x=0; x<width; x++)
396             {
397                 *bitsByte++ = *xorByte++; /* blue */
398                 *bitsByte++ = *xorByte++; /* green */
399                 *bitsByte++ = *xorByte++; /* red */
400                 bitsByte++; /* alpha */
401             }
402             xorRow += xorStride;
403             bitsRow += bitsStride;
404         }
405
406         HeapFree(GetProcessHeap(), 0, tempdata);
407         break;
408     }
409     case 32:
410     {
411         UINT xorBytesPerRow = width*4;
412         UINT xorBytes = xorBytesPerRow * height;
413
414         bits = HeapAlloc(GetProcessHeap(), 0, xorBytes);
415         if (!bits)
416         {
417             hr = E_OUTOFMEMORY;
418             goto fail;
419         }
420
421         if (bih.biHeight > 0) /* bottom-up DIB */
422         {
423             /* read the rows backwards so we get a top-down DIB */
424             UINT i;
425             BYTE *xorRow = bits + xorBytesPerRow * (height-1);
426
427             for (i=0; i<height; i++)
428             {
429                 hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread);
430                 if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail;
431                 xorRow -= xorBytesPerRow;
432             }
433         }
434         else /* top-down DIB */
435         {
436             hr = IStream_Read(This->parent->stream, bits, xorBytes, &bytesread);
437             if (FAILED(hr) || bytesread != xorBytes) goto fail;
438         }
439         break;
440     }
441     default:
442         FIXME("unsupported bitcount: %u\n", This->entry.wBitCount);
443         goto fail;
444     }
445
446     if (This->entry.wBitCount < 32)
447     {
448         /* set alpha data based on the AND mask */
449         UINT andBytesPerRow = (width+31)/32*4;
450         UINT andBytes = andBytesPerRow * height;
451         INT andStride;
452         BYTE *andRow;
453         BYTE *bitsRow;
454         UINT x, y;
455
456         tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
457         if (!tempdata)
458         {
459             hr = E_OUTOFMEMORY;
460             goto fail;
461         }
462
463         hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread);
464         if (FAILED(hr) || bytesread != andBytes) goto fail;
465
466         if (bih.biHeight > 0) /* bottom-up DIB */
467         {
468             andStride = -andBytesPerRow;
469             andRow = tempdata + (height-1)*andBytesPerRow;
470         }
471         else /* top-down DIB */
472         {
473             andStride = andBytesPerRow;
474             andRow = tempdata;
475         }
476
477         bitsRow = bits;
478         for (y=0; y<height; y++) {
479             BYTE *andByte=andRow;
480             DWORD *bitsPixel=(DWORD*)bitsRow;
481             for (x=0; x<width; x+=8) {
482                 BYTE andVal=*andByte++;
483                 pixel_set_trans(bitsPixel++, andVal>>7&1);
484                 if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1);
485                 if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1);
486                 if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1);
487                 if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1);
488                 if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1);
489                 if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1);
490                 if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1);
491             }
492             andRow += andStride;
493             bitsRow += bitsStride;
494         }
495
496         HeapFree(GetProcessHeap(), 0, tempdata);
497     }
498
499     This->bits = bits;
500
501     return S_OK;
502
503 fail:
504     HeapFree(GetProcessHeap(), 0, tempdata);
505     HeapFree(GetProcessHeap(), 0, bits);
506     if (SUCCEEDED(hr)) hr = E_FAIL;
507     TRACE("<-- %x\n", hr);
508     return hr;
509 }
510
511 static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
512     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
513 {
514     IcoFrameDecode *This = (IcoFrameDecode*)iface;
515     HRESULT hr;
516     UINT width, height, stride;
517     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
518
519     if (!This->bits)
520     {
521         hr = IcoFrameDecode_ReadPixels(This);
522         if (FAILED(hr)) return hr;
523     }
524
525     width = This->entry.bWidth ? This->entry.bWidth : 256;
526     height = This->entry.bHeight ? This->entry.bHeight : 256;
527     stride = width * 4;
528
529     return copy_pixels(32, This->bits, width, height, stride,
530         prc, cbStride, cbBufferSize, pbBuffer);
531 }
532
533 static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
534     IWICMetadataQueryReader **ppIMetadataQueryReader)
535 {
536     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
537     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
538 }
539
540 static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
541     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
542 {
543     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
544     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
545 }
546
547 static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
548     IWICBitmapSource **ppIThumbnail)
549 {
550     TRACE("(%p,%p)\n", iface, ppIThumbnail);
551     return WINCODEC_ERR_CODECNOTHUMBNAIL;
552 }
553
554 static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
555     IcoFrameDecode_QueryInterface,
556     IcoFrameDecode_AddRef,
557     IcoFrameDecode_Release,
558     IcoFrameDecode_GetSize,
559     IcoFrameDecode_GetPixelFormat,
560     IcoFrameDecode_GetResolution,
561     IcoFrameDecode_CopyPalette,
562     IcoFrameDecode_CopyPixels,
563     IcoFrameDecode_GetMetadataQueryReader,
564     IcoFrameDecode_GetColorContexts,
565     IcoFrameDecode_GetThumbnail
566 };
567
568 static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
569     void **ppv)
570 {
571     IcoDecoder *This = (IcoDecoder*)iface;
572     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
573
574     if (!ppv) return E_INVALIDARG;
575
576     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
577     {
578         *ppv = This;
579     }
580     else
581     {
582         *ppv = NULL;
583         return E_NOINTERFACE;
584     }
585
586     IUnknown_AddRef((IUnknown*)*ppv);
587     return S_OK;
588 }
589
590 static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
591 {
592     IcoDecoder *This = (IcoDecoder*)iface;
593     ULONG ref = InterlockedIncrement(&This->ref);
594
595     TRACE("(%p) refcount=%u\n", iface, ref);
596
597     return ref;
598 }
599
600 static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
601 {
602     IcoDecoder *This = (IcoDecoder*)iface;
603     ULONG ref = InterlockedDecrement(&This->ref);
604
605     TRACE("(%p) refcount=%u\n", iface, ref);
606
607     if (ref == 0)
608     {
609         if (This->stream) IStream_Release(This->stream);
610         HeapFree(GetProcessHeap(), 0, This);
611     }
612
613     return ref;
614 }
615
616 static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
617     DWORD *pdwCapability)
618 {
619     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
620     return E_NOTIMPL;
621 }
622
623 static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
624     WICDecodeOptions cacheOptions)
625 {
626     IcoDecoder *This = (IcoDecoder*)iface;
627     LARGE_INTEGER seek;
628     HRESULT hr;
629     ULONG bytesread;
630     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
631
632     if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
633
634     seek.QuadPart = 0;
635     hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
636     if (FAILED(hr)) return hr;
637
638     hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread);
639     if (FAILED(hr)) return hr;
640     if (bytesread != sizeof(ICONHEADER) ||
641         This->header.idReserved != 0 ||
642         This->header.idType != 1) return E_FAIL;
643
644     This->initialized = TRUE;
645     This->stream = pIStream;
646     IStream_AddRef(pIStream);
647
648     return S_OK;
649 }
650
651 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
652     GUID *pguidContainerFormat)
653 {
654     FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
655     return E_NOTIMPL;
656 }
657
658 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
659     IWICBitmapDecoderInfo **ppIDecoderInfo)
660 {
661     FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
662     return E_NOTIMPL;
663 }
664
665 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
666     IWICPalette *pIPalette)
667 {
668     TRACE("(%p,%p)\n", iface, pIPalette);
669     return WINCODEC_ERR_PALETTEUNAVAILABLE;
670 }
671
672 static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
673     IWICMetadataQueryReader **ppIMetadataQueryReader)
674 {
675     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
676     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
677 }
678
679 static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface,
680     IWICBitmapSource **ppIBitmapSource)
681 {
682     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
683     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
684 }
685
686 static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface,
687     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
688 {
689     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
690     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
691 }
692
693 static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface,
694     IWICBitmapSource **ppIThumbnail)
695 {
696     TRACE("(%p,%p)\n", iface, ppIThumbnail);
697     return WINCODEC_ERR_CODECNOTHUMBNAIL;
698 }
699
700 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
701     UINT *pCount)
702 {
703     IcoDecoder *This = (IcoDecoder*)iface;
704     TRACE("(%p,%p)\n", iface, pCount);
705
706     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
707
708     *pCount = This->header.idCount;
709     TRACE("<-- %u\n", *pCount);
710
711     return S_OK;
712 }
713
714 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
715     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
716 {
717     IcoDecoder *This = (IcoDecoder*)iface;
718     IcoFrameDecode *result;
719     LARGE_INTEGER seek;
720     HRESULT hr;
721     ULONG bytesread;
722     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
723
724     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
725
726     if (This->header.idCount < index) return E_INVALIDARG;
727
728     result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode));
729     if (!result) return E_OUTOFMEMORY;
730
731     result->lpVtbl = &IcoFrameDecode_Vtbl;
732     result->ref = 1;
733     result->parent = This;
734     result->bits = NULL;
735
736     /* read the icon entry */
737     seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index;
738     hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
739     if (FAILED(hr)) goto fail;
740
741     hr = IStream_Read(This->stream, &result->entry, sizeof(ICONDIRENTRY), &bytesread);
742     if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail;
743
744     IWICBitmapDecoder_AddRef(iface);
745
746     *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
747
748     return S_OK;
749
750 fail:
751     HeapFree(GetProcessHeap(), 0, result);
752     if (SUCCEEDED(hr)) hr = E_FAIL;
753     TRACE("<-- %x\n", hr);
754     return hr;
755 }
756
757 static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = {
758     IcoDecoder_QueryInterface,
759     IcoDecoder_AddRef,
760     IcoDecoder_Release,
761     IcoDecoder_QueryCapability,
762     IcoDecoder_Initialize,
763     IcoDecoder_GetContainerFormat,
764     IcoDecoder_GetDecoderInfo,
765     IcoDecoder_CopyPalette,
766     IcoDecoder_GetMetadataQueryReader,
767     IcoDecoder_GetPreview,
768     IcoDecoder_GetColorContexts,
769     IcoDecoder_GetThumbnail,
770     IcoDecoder_GetFrameCount,
771     IcoDecoder_GetFrame
772 };
773
774 HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
775 {
776     IcoDecoder *This;
777     HRESULT ret;
778
779     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
780
781     *ppv = NULL;
782
783     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
784
785     This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder));
786     if (!This) return E_OUTOFMEMORY;
787
788     This->lpVtbl = &IcoDecoder_Vtbl;
789     This->ref = 1;
790     This->stream = NULL;
791     This->initialized = FALSE;
792
793     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
794     IUnknown_Release((IUnknown*)This);
795
796     return ret;
797 }