xref: /reactos/dll/win32/windowscodecs/gifformat.c (revision 407c54ba)
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  * Copyright 2012,2016 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "config.h"
21 
22 #include <stdarg.h>
23 
24 #define COBJMACROS
25 #define NONAMELESSUNION
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
30 
31 #include "ungif.h"
32 
33 #include "wincodecs_private.h"
34 
35 #include "wine/debug.h"
36 
37 #ifdef __REACTOS__
38 #include <ole2.h>
39 #endif
40 
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
42 
43 #include "pshpack1.h"
44 
45 struct logical_screen_descriptor
46 {
47     char signature[6];
48     USHORT width;
49     USHORT height;
50     BYTE packed;
51     /* global_color_table_flag : 1;
52      * color_resolution : 3;
53      * sort_flag : 1;
54      * global_color_table_size : 3;
55      */
56     BYTE background_color_index;
57     BYTE pixel_aspect_ratio;
58 };
59 
60 struct image_descriptor
61 {
62     USHORT left;
63     USHORT top;
64     USHORT width;
65     USHORT height;
66     BYTE packed;
67     /* local_color_table_flag : 1;
68      * interlace_flag : 1;
69      * sort_flag : 1;
70      * reserved : 2;
71      * local_color_table_size : 3;
72      */
73 };
74 
75 #include "poppack.h"
76 
77 static LPWSTR strdupAtoW(const char *src)
78 {
79     int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
80     LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
81     if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
82     return dst;
83 }
84 
85 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
86                                  MetadataItem **items, DWORD *count)
87 {
88     struct logical_screen_descriptor lsd_data;
89     HRESULT hr;
90     ULONG bytesread, i;
91     MetadataItem *result;
92 
93     *items = NULL;
94     *count = 0;
95 
96     hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
97     if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
98 
99     result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9);
100     if (!result) return E_OUTOFMEMORY;
101 
102     for (i = 0; i < 9; i++)
103     {
104         PropVariantInit(&result[i].schema);
105         PropVariantInit(&result[i].id);
106         PropVariantInit(&result[i].value);
107     }
108 
109     result[0].id.vt = VT_LPWSTR;
110     result[0].id.u.pwszVal = strdupAtoW("Signature");
111     result[0].value.vt = VT_UI1|VT_VECTOR;
112     result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
113     result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
114     memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
115 
116     result[1].id.vt = VT_LPWSTR;
117     result[1].id.u.pwszVal = strdupAtoW("Width");
118     result[1].value.vt = VT_UI2;
119     result[1].value.u.uiVal = lsd_data.width;
120 
121     result[2].id.vt = VT_LPWSTR;
122     result[2].id.u.pwszVal = strdupAtoW("Height");
123     result[2].value.vt = VT_UI2;
124     result[2].value.u.uiVal = lsd_data.height;
125 
126     result[3].id.vt = VT_LPWSTR;
127     result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
128     result[3].value.vt = VT_BOOL;
129     result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;
130 
131     result[4].id.vt = VT_LPWSTR;
132     result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
133     result[4].value.vt = VT_UI1;
134     result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;
135 
136     result[5].id.vt = VT_LPWSTR;
137     result[5].id.u.pwszVal = strdupAtoW("SortFlag");
138     result[5].value.vt = VT_BOOL;
139     result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;
140 
141     result[6].id.vt = VT_LPWSTR;
142     result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
143     result[6].value.vt = VT_UI1;
144     result[6].value.u.bVal = lsd_data.packed & 7;
145 
146     result[7].id.vt = VT_LPWSTR;
147     result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
148     result[7].value.vt = VT_UI1;
149     result[7].value.u.bVal = lsd_data.background_color_index;
150 
151     result[8].id.vt = VT_LPWSTR;
152     result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
153     result[8].value.vt = VT_UI1;
154     result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;
155 
156     *items = result;
157     *count = 9;
158 
159     return S_OK;
160 }
161 
162 static const MetadataHandlerVtbl LSDReader_Vtbl = {
163     0,
164     &CLSID_WICLSDMetadataReader,
165     load_LSD_metadata
166 };
167 
168 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
169 {
170     return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
171 }
172 
173 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
174                                  MetadataItem **items, DWORD *count)
175 {
176     struct image_descriptor imd_data;
177     HRESULT hr;
178     ULONG bytesread, i;
179     MetadataItem *result;
180 
181     *items = NULL;
182     *count = 0;
183 
184     hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
185     if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
186 
187     result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8);
188     if (!result) return E_OUTOFMEMORY;
189 
190     for (i = 0; i < 8; i++)
191     {
192         PropVariantInit(&result[i].schema);
193         PropVariantInit(&result[i].id);
194         PropVariantInit(&result[i].value);
195     }
196 
197     result[0].id.vt = VT_LPWSTR;
198     result[0].id.u.pwszVal = strdupAtoW("Left");
199     result[0].value.vt = VT_UI2;
200     result[0].value.u.uiVal = imd_data.left;
201 
202     result[1].id.vt = VT_LPWSTR;
203     result[1].id.u.pwszVal = strdupAtoW("Top");
204     result[1].value.vt = VT_UI2;
205     result[1].value.u.uiVal = imd_data.top;
206 
207     result[2].id.vt = VT_LPWSTR;
208     result[2].id.u.pwszVal = strdupAtoW("Width");
209     result[2].value.vt = VT_UI2;
210     result[2].value.u.uiVal = imd_data.width;
211 
212     result[3].id.vt = VT_LPWSTR;
213     result[3].id.u.pwszVal = strdupAtoW("Height");
214     result[3].value.vt = VT_UI2;
215     result[3].value.u.uiVal = imd_data.height;
216 
217     result[4].id.vt = VT_LPWSTR;
218     result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag");
219     result[4].value.vt = VT_BOOL;
220     result[4].value.u.boolVal = (imd_data.packed >> 7) & 1;
221 
222     result[5].id.vt = VT_LPWSTR;
223     result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag");
224     result[5].value.vt = VT_BOOL;
225     result[5].value.u.boolVal = (imd_data.packed >> 6) & 1;
226 
227     result[6].id.vt = VT_LPWSTR;
228     result[6].id.u.pwszVal = strdupAtoW("SortFlag");
229     result[6].value.vt = VT_BOOL;
230     result[6].value.u.boolVal = (imd_data.packed >> 5) & 1;
231 
232     result[7].id.vt = VT_LPWSTR;
233     result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize");
234     result[7].value.vt = VT_UI1;
235     result[7].value.u.bVal = imd_data.packed & 7;
236 
237     *items = result;
238     *count = 8;
239 
240     return S_OK;
241 }
242 
243 static const MetadataHandlerVtbl IMDReader_Vtbl = {
244     0,
245     &CLSID_WICIMDMetadataReader,
246     load_IMD_metadata
247 };
248 
249 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv)
250 {
251     return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv);
252 }
253 
254 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
255                                  MetadataItem **items, DWORD *count)
256 {
257 #include "pshpack1.h"
258     struct graphic_control_extension
259     {
260         BYTE packed;
261         /* reservred: 3;
262          * disposal : 3;
263          * user_input_flag : 1;
264          * transparency_flag : 1;
265          */
266          USHORT delay;
267          BYTE transparent_color_index;
268     } gce_data;
269 #include "poppack.h"
270     HRESULT hr;
271     ULONG bytesread, i;
272     MetadataItem *result;
273 
274     *items = NULL;
275     *count = 0;
276 
277     hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
278     if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
279 
280     result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5);
281     if (!result) return E_OUTOFMEMORY;
282 
283     for (i = 0; i < 5; i++)
284     {
285         PropVariantInit(&result[i].schema);
286         PropVariantInit(&result[i].id);
287         PropVariantInit(&result[i].value);
288     }
289 
290     result[0].id.vt = VT_LPWSTR;
291     result[0].id.u.pwszVal = strdupAtoW("Disposal");
292     result[0].value.vt = VT_UI1;
293     result[0].value.u.bVal = (gce_data.packed >> 2) & 7;
294 
295     result[1].id.vt = VT_LPWSTR;
296     result[1].id.u.pwszVal = strdupAtoW("UserInputFlag");
297     result[1].value.vt = VT_BOOL;
298     result[1].value.u.boolVal = (gce_data.packed >> 1) & 1;
299 
300     result[2].id.vt = VT_LPWSTR;
301     result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag");
302     result[2].value.vt = VT_BOOL;
303     result[2].value.u.boolVal = gce_data.packed & 1;
304 
305     result[3].id.vt = VT_LPWSTR;
306     result[3].id.u.pwszVal = strdupAtoW("Delay");
307     result[3].value.vt = VT_UI2;
308     result[3].value.u.uiVal = gce_data.delay;
309 
310     result[4].id.vt = VT_LPWSTR;
311     result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex");
312     result[4].value.vt = VT_UI1;
313     result[4].value.u.bVal = gce_data.transparent_color_index;
314 
315     *items = result;
316     *count = 5;
317 
318     return S_OK;
319 }
320 
321 static const MetadataHandlerVtbl GCEReader_Vtbl = {
322     0,
323     &CLSID_WICGCEMetadataReader,
324     load_GCE_metadata
325 };
326 
327 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv)
328 {
329     return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv);
330 }
331 
332 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
333                                  MetadataItem **items, DWORD *count)
334 {
335 #include "pshpack1.h"
336     struct application_extension
337     {
338         BYTE extension_introducer;
339         BYTE extension_label;
340         BYTE block_size;
341         BYTE application[11];
342     } ape_data;
343 #include "poppack.h"
344     HRESULT hr;
345     ULONG bytesread, data_size, i;
346     MetadataItem *result;
347     BYTE subblock_size;
348     BYTE *data;
349 
350     *items = NULL;
351     *count = 0;
352 
353     hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
354     if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
355     if (ape_data.extension_introducer != 0x21 ||
356         ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
357         ape_data.block_size != 11)
358         return S_OK;
359 
360     data = NULL;
361     data_size = 0;
362 
363     for (;;)
364     {
365         hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
366         if (FAILED(hr) || bytesread != sizeof(subblock_size))
367         {
368             HeapFree(GetProcessHeap(), 0, data);
369             return S_OK;
370         }
371         if (!subblock_size) break;
372 
373         if (!data)
374             data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
375         else
376         {
377             BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
378             if (!new_data)
379             {
380                 HeapFree(GetProcessHeap(), 0, data);
381                 return S_OK;
382             }
383             data = new_data;
384         }
385         data[data_size] = subblock_size;
386         hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
387         if (FAILED(hr) || bytesread != subblock_size)
388         {
389             HeapFree(GetProcessHeap(), 0, data);
390             return S_OK;
391         }
392         data_size += subblock_size + 1;
393     }
394 
395     result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2);
396     if (!result)
397     {
398         HeapFree(GetProcessHeap(), 0, data);
399         return E_OUTOFMEMORY;
400     }
401 
402     for (i = 0; i < 2; i++)
403     {
404         PropVariantInit(&result[i].schema);
405         PropVariantInit(&result[i].id);
406         PropVariantInit(&result[i].value);
407     }
408 
409     result[0].id.vt = VT_LPWSTR;
410     result[0].id.u.pwszVal = strdupAtoW("Application");
411     result[0].value.vt = VT_UI1|VT_VECTOR;
412     result[0].value.u.caub.cElems = sizeof(ape_data.application);
413     result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application));
414     memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application));
415 
416     result[1].id.vt = VT_LPWSTR;
417     result[1].id.u.pwszVal = strdupAtoW("Data");
418     result[1].value.vt = VT_UI1|VT_VECTOR;
419     result[1].value.u.caub.cElems = data_size;
420     result[1].value.u.caub.pElems = data;
421 
422     *items = result;
423     *count = 2;
424 
425     return S_OK;
426 }
427 
428 static const MetadataHandlerVtbl APEReader_Vtbl = {
429     0,
430     &CLSID_WICAPEMetadataReader,
431     load_APE_metadata
432 };
433 
434 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv)
435 {
436     return MetadataReader_Create(&APEReader_Vtbl, iid, ppv);
437 }
438 
439 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
440                                         MetadataItem **items, DWORD *count)
441 {
442 #include "pshpack1.h"
443     struct gif_extension
444     {
445         BYTE extension_introducer;
446         BYTE extension_label;
447     } ext_data;
448 #include "poppack.h"
449     HRESULT hr;
450     ULONG bytesread, data_size;
451     MetadataItem *result;
452     BYTE subblock_size;
453     char *data;
454 
455     *items = NULL;
456     *count = 0;
457 
458     hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
459     if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
460     if (ext_data.extension_introducer != 0x21 ||
461         ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
462         return S_OK;
463 
464     data = NULL;
465     data_size = 0;
466 
467     for (;;)
468     {
469         hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
470         if (FAILED(hr) || bytesread != sizeof(subblock_size))
471         {
472             HeapFree(GetProcessHeap(), 0, data);
473             return S_OK;
474         }
475         if (!subblock_size) break;
476 
477         if (!data)
478             data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
479         else
480         {
481             char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
482             if (!new_data)
483             {
484                 HeapFree(GetProcessHeap(), 0, data);
485                 return S_OK;
486             }
487             data = new_data;
488         }
489         hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
490         if (FAILED(hr) || bytesread != subblock_size)
491         {
492             HeapFree(GetProcessHeap(), 0, data);
493             return S_OK;
494         }
495         data_size += subblock_size;
496     }
497 
498     data[data_size] = 0;
499 
500     result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem));
501     if (!result)
502     {
503         HeapFree(GetProcessHeap(), 0, data);
504         return E_OUTOFMEMORY;
505     }
506 
507     PropVariantInit(&result->schema);
508     PropVariantInit(&result->id);
509     PropVariantInit(&result->value);
510 
511     result->id.vt = VT_LPWSTR;
512     result->id.u.pwszVal = strdupAtoW("TextEntry");
513     result->value.vt = VT_LPSTR;
514     result->value.u.pszVal = data;
515 
516     *items = result;
517     *count = 1;
518 
519     return S_OK;
520 }
521 
522 static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
523     0,
524     &CLSID_WICGifCommentMetadataReader,
525     load_GifComment_metadata
526 };
527 
528 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv)
529 {
530     return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv);
531 }
532 
533 static IStream *create_stream(const void *data, int data_size)
534 {
535     HRESULT hr;
536     IStream *stream;
537     HGLOBAL hdata;
538     void *locked_data;
539 
540     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
541     if (!hdata) return NULL;
542 
543     locked_data = GlobalLock(hdata);
544     memcpy(locked_data, data, data_size);
545     GlobalUnlock(hdata);
546 
547     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
548     return FAILED(hr) ? NULL : stream;
549 }
550 
551 static HRESULT create_metadata_reader(const void *data, int data_size,
552                                       class_constructor constructor,
553                                       IWICMetadataReader **reader)
554 {
555     HRESULT hr;
556     IWICMetadataReader *metadata_reader;
557     IWICPersistStream *persist;
558     IStream *stream;
559 
560     /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
561 
562     hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader);
563     if (FAILED(hr)) return hr;
564 
565     hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
566     if (FAILED(hr))
567     {
568         IWICMetadataReader_Release(metadata_reader);
569         return hr;
570     }
571 
572     stream = create_stream(data, data_size);
573     IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
574     IStream_Release(stream);
575 
576     IWICPersistStream_Release(persist);
577 
578     *reader = metadata_reader;
579     return S_OK;
580 }
581 
582 typedef struct {
583     IWICBitmapDecoder IWICBitmapDecoder_iface;
584     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
585     IStream *stream;
586     BYTE LSD_data[13]; /* Logical Screen Descriptor */
587     LONG ref;
588     BOOL initialized;
589     GifFileType *gif;
590     UINT current_frame;
591     CRITICAL_SECTION lock;
592 } GifDecoder;
593 
594 typedef struct {
595     IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
596     IWICMetadataBlockReader IWICMetadataBlockReader_iface;
597     LONG ref;
598     SavedImage *frame;
599     GifDecoder *parent;
600 } GifFrameDecode;
601 
602 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
603 {
604     return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
605 }
606 
607 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
608 {
609     return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
610 }
611 
612 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
613 {
614     return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
615 }
616 
617 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
618 {
619     return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
620 }
621 
622 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
623     void **ppv)
624 {
625     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
626     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
627 
628     if (!ppv) return E_INVALIDARG;
629 
630     if (IsEqualIID(&IID_IUnknown, iid) ||
631         IsEqualIID(&IID_IWICBitmapSource, iid) ||
632         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
633     {
634         *ppv = &This->IWICBitmapFrameDecode_iface;
635     }
636     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
637     {
638         *ppv = &This->IWICMetadataBlockReader_iface;
639     }
640     else
641     {
642         *ppv = NULL;
643         return E_NOINTERFACE;
644     }
645 
646     IUnknown_AddRef((IUnknown*)*ppv);
647     return S_OK;
648 }
649 
650 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
651 {
652     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
653     ULONG ref = InterlockedIncrement(&This->ref);
654 
655     TRACE("(%p) refcount=%u\n", iface, ref);
656 
657     return ref;
658 }
659 
660 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
661 {
662     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
663     ULONG ref = InterlockedDecrement(&This->ref);
664 
665     TRACE("(%p) refcount=%u\n", iface, ref);
666 
667     if (ref == 0)
668     {
669         IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
670         HeapFree(GetProcessHeap(), 0, This);
671     }
672 
673     return ref;
674 }
675 
676 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
677     UINT *puiWidth, UINT *puiHeight)
678 {
679     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
680     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
681 
682     *puiWidth = This->frame->ImageDesc.Width;
683     *puiHeight = This->frame->ImageDesc.Height;
684 
685     return S_OK;
686 }
687 
688 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
689     WICPixelFormatGUID *pPixelFormat)
690 {
691     memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
692 
693     return S_OK;
694 }
695 
696 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
697     double *pDpiX, double *pDpiY)
698 {
699     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
700     const GifWord aspect_word = This->parent->gif->SAspectRatio;
701     const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
702     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
703 
704     *pDpiX = 96.0 / aspect;
705     *pDpiY = 96.0;
706 
707     return S_OK;
708 }
709 
710 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
711     IWICPalette *pIPalette)
712 {
713     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
714     WICColor colors[256];
715     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
716     int i, trans;
717     ExtensionBlock *eb;
718     TRACE("(%p,%p)\n", iface, pIPalette);
719 
720     if (!cm) cm = This->parent->gif->SColorMap;
721 
722     if (cm->ColorCount > 256)
723     {
724         ERR("GIF contains %i colors???\n", cm->ColorCount);
725         return E_FAIL;
726     }
727 
728     for (i = 0; i < cm->ColorCount; i++) {
729         colors[i] = 0xff000000| /* alpha */
730                     cm->Colors[i].Red << 16|
731                     cm->Colors[i].Green << 8|
732                     cm->Colors[i].Blue;
733     }
734 
735     /* look for the transparent color extension */
736     for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) {
737 	eb = This->frame->Extensions.ExtensionBlocks + i;
738 	if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) {
739 	    if (eb->Bytes[3] & 1) {
740 	        trans = (unsigned char)eb->Bytes[6];
741 	        colors[trans] &= 0xffffff; /* set alpha to 0 */
742 	        break;
743 	    }
744 	}
745     }
746 
747     return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
748 }
749 
750 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
751     UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
752     UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
753 {
754     UINT row_offset; /* number of bytes into the source rows where the data starts */
755     const BYTE *src;
756     BYTE *dst;
757     UINT y;
758     WICRect rect;
759 
760     if (!rc)
761     {
762         rect.X = 0;
763         rect.Y = 0;
764         rect.Width = srcwidth;
765         rect.Height = srcheight;
766         rc = &rect;
767     }
768     else
769     {
770         if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
771             return E_INVALIDARG;
772     }
773 
774     if (dststride < rc->Width)
775         return E_INVALIDARG;
776 
777     if ((dststride * rc->Height) > dstbuffersize)
778         return E_INVALIDARG;
779 
780     row_offset = rc->X;
781 
782     dst = dstbuffer;
783     for (y=rc->Y; y-rc->Y < rc->Height; y++)
784     {
785         if (y%8 == 0)
786             src = srcbuffer + srcstride * (y/8);
787         else if (y%4 == 0)
788             src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
789         else if (y%2 == 0)
790             src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
791         else /* y%2 == 1 */
792             src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
793         src += row_offset;
794         memcpy(dst, src, rc->Width);
795         dst += dststride;
796     }
797     return S_OK;
798 }
799 
800 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
801     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
802 {
803     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
804     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
805 
806     if (This->frame->ImageDesc.Interlace)
807     {
808         return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
809             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
810             prc, cbStride, cbBufferSize, pbBuffer);
811     }
812     else
813     {
814         return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
815             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
816             prc, cbStride, cbBufferSize, pbBuffer);
817     }
818 }
819 
820 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
821     IWICMetadataQueryReader **ppIMetadataQueryReader)
822 {
823     GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
824 
825     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
826 
827     if (!ppIMetadataQueryReader)
828         return E_INVALIDARG;
829 
830     return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
831 }
832 
833 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
834     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
835 {
836     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
837     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
838 }
839 
840 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
841     IWICBitmapSource **ppIThumbnail)
842 {
843     TRACE("(%p,%p)\n", iface, ppIThumbnail);
844     return WINCODEC_ERR_CODECNOTHUMBNAIL;
845 }
846 
847 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
848     GifFrameDecode_QueryInterface,
849     GifFrameDecode_AddRef,
850     GifFrameDecode_Release,
851     GifFrameDecode_GetSize,
852     GifFrameDecode_GetPixelFormat,
853     GifFrameDecode_GetResolution,
854     GifFrameDecode_CopyPalette,
855     GifFrameDecode_CopyPixels,
856     GifFrameDecode_GetMetadataQueryReader,
857     GifFrameDecode_GetColorContexts,
858     GifFrameDecode_GetThumbnail
859 };
860 
861 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
862     REFIID iid, void **ppv)
863 {
864     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
865     return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
866 }
867 
868 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
869 {
870     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
871     return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
872 }
873 
874 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
875 {
876     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
877     return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
878 }
879 
880 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
881     GUID *guid)
882 {
883     TRACE("(%p,%p)\n", iface, guid);
884 
885     if (!guid) return E_INVALIDARG;
886 
887     *guid = GUID_ContainerFormatGif;
888     return S_OK;
889 }
890 
891 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
892     UINT *count)
893 {
894     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
895 
896     TRACE("%p,%p\n", iface, count);
897 
898     if (!count) return E_INVALIDARG;
899 
900     *count = This->frame->Extensions.ExtensionBlockCount + 1;
901     return S_OK;
902 }
903 
904 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
905 {
906     HRESULT hr;
907     IWICMetadataReader *metadata_reader;
908     IWICPersistStream *persist;
909     IStream *stream;
910     struct image_descriptor IMD_data;
911 
912     /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
913 
914     hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader);
915     if (FAILED(hr)) return hr;
916 
917     hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
918     if (FAILED(hr))
919     {
920         IWICMetadataReader_Release(metadata_reader);
921         return hr;
922     }
923 
924     /* recreate IMD structure from GIF decoder data */
925     IMD_data.left = This->frame->ImageDesc.Left;
926     IMD_data.top = This->frame->ImageDesc.Top;
927     IMD_data.width = This->frame->ImageDesc.Width;
928     IMD_data.height = This->frame->ImageDesc.Height;
929     IMD_data.packed = 0;
930     /* interlace_flag */
931     IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0;
932     if (This->frame->ImageDesc.ColorMap)
933     {
934         /* local_color_table_flag */
935         IMD_data.packed |= 1 << 7;
936         /* local_color_table_size */
937         IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1;
938         /* sort_flag */
939         IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
940     }
941 
942     stream = create_stream(&IMD_data, sizeof(IMD_data));
943     IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
944     IStream_Release(stream);
945 
946     IWICPersistStream_Release(persist);
947 
948     *reader = metadata_reader;
949     return S_OK;
950 }
951 
952 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
953     UINT index, IWICMetadataReader **reader)
954 {
955     GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
956     int i, gce_index = -1, gce_skipped = 0;
957 
958     TRACE("(%p,%u,%p)\n", iface, index, reader);
959 
960     if (!reader) return E_INVALIDARG;
961 
962     if (index == 0)
963         return create_IMD_metadata_reader(This, reader);
964 
965     if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
966         return E_INVALIDARG;
967 
968     for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++)
969     {
970         class_constructor constructor;
971         const void *data;
972         int data_size;
973 
974         if (index != i + 1 - gce_skipped) continue;
975 
976         if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE)
977         {
978             gce_index = i;
979             gce_skipped = 1;
980             continue;
981         }
982         else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
983         {
984             constructor = GifCommentReader_CreateInstance;
985             data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
986             data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
987         }
988         else
989         {
990             constructor = UnknownMetadataReader_CreateInstance;
991             data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
992             data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
993         }
994         return create_metadata_reader(data, data_size, constructor, reader);
995     }
996 
997     if (gce_index == -1) return E_INVALIDARG;
998 
999     return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3,
1000                                   This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4,
1001                                   GCEReader_CreateInstance, reader);
1002 }
1003 
1004 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1005     IEnumUnknown **enumerator)
1006 {
1007     FIXME("(%p,%p): stub\n", iface, enumerator);
1008     return E_NOTIMPL;
1009 }
1010 
1011 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl =
1012 {
1013     GifFrameDecode_Block_QueryInterface,
1014     GifFrameDecode_Block_AddRef,
1015     GifFrameDecode_Block_Release,
1016     GifFrameDecode_Block_GetContainerFormat,
1017     GifFrameDecode_Block_GetCount,
1018     GifFrameDecode_Block_GetReaderByIndex,
1019     GifFrameDecode_Block_GetEnumerator
1020 };
1021 
1022 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1023     void **ppv)
1024 {
1025     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1026     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1027 
1028     if (!ppv) return E_INVALIDARG;
1029 
1030     if (IsEqualIID(&IID_IUnknown, iid) ||
1031         IsEqualIID(&IID_IWICBitmapDecoder, iid))
1032     {
1033         *ppv = &This->IWICBitmapDecoder_iface;
1034     }
1035     else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
1036     {
1037         *ppv = &This->IWICMetadataBlockReader_iface;
1038     }
1039     else
1040     {
1041         *ppv = NULL;
1042         return E_NOINTERFACE;
1043     }
1044 
1045     IUnknown_AddRef((IUnknown*)*ppv);
1046     return S_OK;
1047 }
1048 
1049 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
1050 {
1051     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1052     ULONG ref = InterlockedIncrement(&This->ref);
1053 
1054     TRACE("(%p) refcount=%u\n", iface, ref);
1055 
1056     return ref;
1057 }
1058 
1059 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
1060 {
1061     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1062     ULONG ref = InterlockedDecrement(&This->ref);
1063 
1064     TRACE("(%p) refcount=%u\n", iface, ref);
1065 
1066     if (ref == 0)
1067     {
1068         if (This->stream)
1069         {
1070             IStream_Release(This->stream);
1071             DGifCloseFile(This->gif);
1072         }
1073         This->lock.DebugInfo->Spare[0] = 0;
1074         DeleteCriticalSection(&This->lock);
1075         HeapFree(GetProcessHeap(), 0, This);
1076     }
1077 
1078     return ref;
1079 }
1080 
1081 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1082     DWORD *capability)
1083 {
1084     HRESULT hr;
1085 
1086     TRACE("(%p,%p,%p)\n", iface, stream, capability);
1087 
1088     if (!stream || !capability) return E_INVALIDARG;
1089 
1090     hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1091     if (hr != S_OK) return hr;
1092 
1093     *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
1094                   WICBitmapDecoderCapabilityCanDecodeSomeImages |
1095                   WICBitmapDecoderCapabilityCanEnumerateMetadata;
1096     return S_OK;
1097 }
1098 
1099 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1100     IStream *stream = gif->UserData;
1101     ULONG bytesread;
1102     HRESULT hr;
1103 
1104     if (!stream)
1105     {
1106         ERR("attempting to read file after initialization\n");
1107         return 0;
1108     }
1109 
1110     hr = IStream_Read(stream, data, len, &bytesread);
1111     if (FAILED(hr)) bytesread = 0;
1112     return bytesread;
1113 }
1114 
1115 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1116     WICDecodeOptions cacheOptions)
1117 {
1118     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1119     LARGE_INTEGER seek;
1120     int ret;
1121 
1122     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1123 
1124     EnterCriticalSection(&This->lock);
1125 
1126     if (This->initialized || This->gif)
1127     {
1128         WARN("already initialized\n");
1129         LeaveCriticalSection(&This->lock);
1130         return WINCODEC_ERR_WRONGSTATE;
1131     }
1132 
1133     /* seek to start of stream */
1134     seek.QuadPart = 0;
1135     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1136 
1137     /* read all data from the stream */
1138     This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1139     if (!This->gif)
1140     {
1141         LeaveCriticalSection(&This->lock);
1142         return E_FAIL;
1143     }
1144 
1145     ret = DGifSlurp(This->gif);
1146     if (ret == GIF_ERROR)
1147     {
1148         LeaveCriticalSection(&This->lock);
1149         return E_FAIL;
1150     }
1151 
1152     /* make sure we don't use the stream after this method returns */
1153     This->gif->UserData = NULL;
1154 
1155     seek.QuadPart = 0;
1156     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1157     IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL);
1158 
1159     This->stream = pIStream;
1160     IStream_AddRef(This->stream);
1161 
1162     This->initialized = TRUE;
1163 
1164     LeaveCriticalSection(&This->lock);
1165 
1166     return S_OK;
1167 }
1168 
1169 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1170     GUID *pguidContainerFormat)
1171 {
1172     memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1173     return S_OK;
1174 }
1175 
1176 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1177     IWICBitmapDecoderInfo **ppIDecoderInfo)
1178 {
1179     HRESULT hr;
1180     IWICComponentInfo *compinfo;
1181 
1182     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1183 
1184     hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
1185     if (FAILED(hr)) return hr;
1186 
1187     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
1188         (void**)ppIDecoderInfo);
1189 
1190     IWICComponentInfo_Release(compinfo);
1191 
1192     return hr;
1193 }
1194 
1195 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1196 {
1197     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1198     WICColor colors[256];
1199     ColorMapObject *cm;
1200     int i, trans, count;
1201     ExtensionBlock *eb;
1202 
1203     TRACE("(%p,%p)\n", iface, palette);
1204 
1205     if (!This->gif)
1206         return WINCODEC_ERR_WRONGSTATE;
1207 
1208     cm = This->gif->SColorMap;
1209     if (cm)
1210     {
1211         if (cm->ColorCount > 256)
1212         {
1213             ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
1214             return E_FAIL;
1215         }
1216 
1217         for (i = 0; i < cm->ColorCount; i++)
1218         {
1219             colors[i] = 0xff000000 | /* alpha */
1220                         cm->Colors[i].Red << 16 |
1221                         cm->Colors[i].Green << 8 |
1222                         cm->Colors[i].Blue;
1223         }
1224 
1225         count = cm->ColorCount;
1226     }
1227     else
1228     {
1229         colors[0] = 0xff000000;
1230         colors[1] = 0xffffffff;
1231 
1232         for (i = 2; i < 256; i++)
1233             colors[i] = 0xff000000;
1234 
1235         count = 256;
1236     }
1237 
1238     /* look for the transparent color extension */
1239     for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
1240     {
1241         eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
1242         if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
1243         {
1244             if (eb->Bytes[3] & 1)
1245             {
1246                 trans = (unsigned char)eb->Bytes[6];
1247                 colors[trans] &= 0xffffff; /* set alpha to 0 */
1248                 break;
1249             }
1250         }
1251     }
1252 
1253     return IWICPalette_InitializeCustom(palette, colors, count);
1254 }
1255 
1256 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1257     IWICMetadataQueryReader **ppIMetadataQueryReader)
1258 {
1259     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1260 
1261     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1262 
1263     if (!ppIMetadataQueryReader) return E_INVALIDARG;
1264 
1265     return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1266 }
1267 
1268 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1269     IWICBitmapSource **ppIBitmapSource)
1270 {
1271     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1272     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1273 }
1274 
1275 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1276     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1277 {
1278     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1279     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1280 }
1281 
1282 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1283     IWICBitmapSource **ppIThumbnail)
1284 {
1285     TRACE("(%p,%p)\n", iface, ppIThumbnail);
1286     return WINCODEC_ERR_CODECNOTHUMBNAIL;
1287 }
1288 
1289 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1290     UINT *pCount)
1291 {
1292     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1293 
1294     if (!pCount) return E_INVALIDARG;
1295 
1296     EnterCriticalSection(&This->lock);
1297     *pCount = This->gif ? This->gif->ImageCount : 0;
1298     LeaveCriticalSection(&This->lock);
1299 
1300     TRACE("(%p) <-- %d\n", iface, *pCount);
1301 
1302     return S_OK;
1303 }
1304 
1305 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1306     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1307 {
1308     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1309     GifFrameDecode *result;
1310     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1311 
1312     if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1313 
1314     if (index >= This->gif->ImageCount) return E_INVALIDARG;
1315 
1316     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1317     if (!result) return E_OUTOFMEMORY;
1318 
1319     result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1320     result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1321     result->ref = 1;
1322     result->frame = &This->gif->SavedImages[index];
1323     IWICBitmapDecoder_AddRef(iface);
1324     result->parent = This;
1325     This->current_frame = index;
1326 
1327     *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1328 
1329     return S_OK;
1330 }
1331 
1332 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1333     GifDecoder_QueryInterface,
1334     GifDecoder_AddRef,
1335     GifDecoder_Release,
1336     GifDecoder_QueryCapability,
1337     GifDecoder_Initialize,
1338     GifDecoder_GetContainerFormat,
1339     GifDecoder_GetDecoderInfo,
1340     GifDecoder_CopyPalette,
1341     GifDecoder_GetMetadataQueryReader,
1342     GifDecoder_GetPreview,
1343     GifDecoder_GetColorContexts,
1344     GifDecoder_GetThumbnail,
1345     GifDecoder_GetFrameCount,
1346     GifDecoder_GetFrame
1347 };
1348 
1349 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1350     REFIID iid, void **ppv)
1351 {
1352     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1353     return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1354 }
1355 
1356 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1357 {
1358     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1359     return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1360 }
1361 
1362 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1363 {
1364     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1365     return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1366 }
1367 
1368 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1369     GUID *guid)
1370 {
1371     TRACE("(%p,%p)\n", iface, guid);
1372 
1373     if (!guid) return E_INVALIDARG;
1374 
1375     *guid = GUID_ContainerFormatGif;
1376     return S_OK;
1377 }
1378 
1379 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1380     UINT *count)
1381 {
1382     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1383 
1384     TRACE("%p,%p\n", iface, count);
1385 
1386     if (!count) return E_INVALIDARG;
1387 
1388     *count = This->gif->Extensions.ExtensionBlockCount + 1;
1389     return S_OK;
1390 }
1391 
1392 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1393     UINT index, IWICMetadataReader **reader)
1394 {
1395     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1396     int i;
1397 
1398     TRACE("(%p,%u,%p)\n", iface, index, reader);
1399 
1400     if (!reader) return E_INVALIDARG;
1401 
1402     if (index == 0)
1403         return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1404                                       LSDReader_CreateInstance, reader);
1405 
1406     for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1407     {
1408         class_constructor constructor;
1409 
1410         if (index != i + 1) continue;
1411 
1412         if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1413             constructor = APEReader_CreateInstance;
1414         else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1415             constructor = GifCommentReader_CreateInstance;
1416         else
1417             constructor = UnknownMetadataReader_CreateInstance;
1418 
1419         return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1420                                       This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1421                                       constructor, reader);
1422     }
1423 
1424     return E_INVALIDARG;
1425 }
1426 
1427 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1428     IEnumUnknown **enumerator)
1429 {
1430     FIXME("(%p,%p): stub\n", iface, enumerator);
1431     return E_NOTIMPL;
1432 }
1433 
1434 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1435 {
1436     GifDecoder_Block_QueryInterface,
1437     GifDecoder_Block_AddRef,
1438     GifDecoder_Block_Release,
1439     GifDecoder_Block_GetContainerFormat,
1440     GifDecoder_Block_GetCount,
1441     GifDecoder_Block_GetReaderByIndex,
1442     GifDecoder_Block_GetEnumerator
1443 };
1444 
1445 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
1446 {
1447     GifDecoder *This;
1448     HRESULT ret;
1449 
1450     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1451 
1452     *ppv = NULL;
1453 
1454     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1455     if (!This) return E_OUTOFMEMORY;
1456 
1457     This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1458     This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1459     This->stream = NULL;
1460     This->ref = 1;
1461     This->initialized = FALSE;
1462     This->gif = NULL;
1463     This->current_frame = 0;
1464     InitializeCriticalSection(&This->lock);
1465     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1466 
1467     ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1468     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1469 
1470     return ret;
1471 }
1472 
1473 typedef struct GifEncoder
1474 {
1475     IWICBitmapEncoder IWICBitmapEncoder_iface;
1476     LONG ref;
1477     IStream *stream;
1478     CRITICAL_SECTION lock;
1479     BOOL initialized, info_written, committed;
1480     UINT n_frames;
1481     WICColor palette[256];
1482     UINT colors;
1483 } GifEncoder;
1484 
1485 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1486 {
1487     return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
1488 }
1489 
1490 typedef struct GifFrameEncode
1491 {
1492     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1493     LONG ref;
1494     GifEncoder *encoder;
1495     BOOL initialized, interlace, committed;
1496     UINT width, height, lines;
1497     double xres, yres;
1498     WICColor palette[256];
1499     UINT colors;
1500     BYTE *image_data;
1501 } GifFrameEncode;
1502 
1503 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1504 {
1505     return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
1506 }
1507 
1508 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1509 {
1510     TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
1511 
1512     if (!ppv) return E_INVALIDARG;
1513 
1514     if (IsEqualIID(&IID_IUnknown, iid) ||
1515         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1516     {
1517         IWICBitmapFrameEncode_AddRef(iface);
1518         *ppv = iface;
1519         return S_OK;
1520     }
1521 
1522     *ppv = NULL;
1523     return E_NOINTERFACE;
1524 }
1525 
1526 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1527 {
1528     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1529     ULONG ref = InterlockedIncrement(&This->ref);
1530 
1531     TRACE("%p -> %u\n", iface, ref);
1532     return ref;
1533 }
1534 
1535 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
1536 {
1537     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1538     ULONG ref = InterlockedDecrement(&This->ref);
1539 
1540     TRACE("%p -> %u\n", iface, ref);
1541 
1542     if (!ref)
1543     {
1544         IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
1545         HeapFree(GetProcessHeap(), 0, This->image_data);
1546         HeapFree(GetProcessHeap(), 0, This);
1547     }
1548 
1549     return ref;
1550 }
1551 
1552 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
1553 {
1554     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1555     HRESULT hr;
1556 
1557     TRACE("%p,%p\n", iface, options);
1558 
1559     EnterCriticalSection(&This->encoder->lock);
1560 
1561     if (!This->initialized)
1562     {
1563         This->initialized = TRUE;
1564         hr = S_OK;
1565     }
1566     else
1567         hr = WINCODEC_ERR_WRONGSTATE;
1568 
1569     LeaveCriticalSection(&This->encoder->lock);
1570 
1571     return hr;
1572 }
1573 
1574 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
1575 {
1576     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1577     HRESULT hr;
1578 
1579     TRACE("%p,%u,%u\n", iface, width, height);
1580 
1581     if (!width || !height) return E_INVALIDARG;
1582 
1583     EnterCriticalSection(&This->encoder->lock);
1584 
1585     if (This->initialized)
1586     {
1587         HeapFree(GetProcessHeap(), 0, This->image_data);
1588 
1589         This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height);
1590         if (This->image_data)
1591         {
1592             This->width = width;
1593             This->height = height;
1594             hr = S_OK;
1595         }
1596         else
1597             hr = E_OUTOFMEMORY;
1598     }
1599     else
1600         hr = WINCODEC_ERR_WRONGSTATE;
1601 
1602     LeaveCriticalSection(&This->encoder->lock);
1603 
1604     return hr;
1605 }
1606 
1607 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
1608 {
1609     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1610     HRESULT hr;
1611 
1612     TRACE("%p,%f,%f\n", iface, xres, yres);
1613 
1614     EnterCriticalSection(&This->encoder->lock);
1615 
1616     if (This->initialized)
1617     {
1618         This->xres = xres;
1619         This->yres = yres;
1620         hr = S_OK;
1621     }
1622     else
1623         hr = WINCODEC_ERR_WRONGSTATE;
1624 
1625     LeaveCriticalSection(&This->encoder->lock);
1626 
1627     return hr;
1628 }
1629 
1630 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
1631 {
1632     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1633     HRESULT hr;
1634 
1635     TRACE("%p,%s\n", iface, debugstr_guid(format));
1636 
1637     if (!format) return E_INVALIDARG;
1638 
1639     EnterCriticalSection(&This->encoder->lock);
1640 
1641     if (This->initialized)
1642     {
1643         *format = GUID_WICPixelFormat8bppIndexed;
1644         hr = S_OK;
1645     }
1646     else
1647         hr = WINCODEC_ERR_WRONGSTATE;
1648 
1649     LeaveCriticalSection(&This->encoder->lock);
1650 
1651     return hr;
1652 }
1653 
1654 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
1655 {
1656     FIXME("%p,%u,%p: stub\n", iface, count, context);
1657     return E_NOTIMPL;
1658 }
1659 
1660 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
1661 {
1662     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1663     HRESULT hr;
1664 
1665     TRACE("%p,%p\n", iface, palette);
1666 
1667     if (!palette) return E_INVALIDARG;
1668 
1669     EnterCriticalSection(&This->encoder->lock);
1670 
1671     if (This->initialized)
1672         hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1673     else
1674         hr = WINCODEC_ERR_NOTINITIALIZED;
1675 
1676     LeaveCriticalSection(&This->encoder->lock);
1677     return hr;
1678 }
1679 
1680 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
1681 {
1682     FIXME("%p,%p: stub\n", iface, thumbnail);
1683     return E_NOTIMPL;
1684 }
1685 
1686 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
1687 {
1688     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1689     HRESULT hr;
1690 
1691     TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
1692 
1693     if (!pixels) return E_INVALIDARG;
1694 
1695     EnterCriticalSection(&This->encoder->lock);
1696 
1697     if (This->initialized && This->image_data)
1698     {
1699         if (This->lines + lines <= This->height)
1700         {
1701             UINT i;
1702             BYTE *src, *dst;
1703 
1704             src = pixels;
1705             dst = This->image_data + This->lines * This->width;
1706 
1707             for (i = 0; i < lines; i++)
1708             {
1709                 memcpy(dst, src, This->width);
1710                 src += stride;
1711                 dst += This->width;
1712             }
1713 
1714             This->lines += lines;
1715             hr = S_OK;
1716         }
1717         else
1718             hr = E_INVALIDARG;
1719     }
1720     else
1721         hr = WINCODEC_ERR_WRONGSTATE;
1722 
1723     LeaveCriticalSection(&This->encoder->lock);
1724     return hr;
1725 }
1726 
1727 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
1728 {
1729     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1730     HRESULT hr;
1731 
1732     TRACE("%p,%p,%p\n", iface, source, rc);
1733 
1734     if (!source) return E_INVALIDARG;
1735 
1736     EnterCriticalSection(&This->encoder->lock);
1737 
1738     if (This->initialized)
1739     {
1740         const GUID *format = &GUID_WICPixelFormat8bppIndexed;
1741 
1742         hr = configure_write_source(iface, source, rc, format,
1743                                     This->width, This->height, This->xres, This->yres);
1744         if (hr == S_OK)
1745             hr = write_source(iface, source, rc, format, 8, This->width, This->height);
1746     }
1747     else
1748         hr = WINCODEC_ERR_WRONGSTATE;
1749 
1750     LeaveCriticalSection(&This->encoder->lock);
1751     return hr;
1752 }
1753 
1754 #define LZW_DICT_SIZE (1 << 12)
1755 
1756 struct lzw_dict
1757 {
1758     short prefix[LZW_DICT_SIZE];
1759     unsigned char suffix[LZW_DICT_SIZE];
1760 };
1761 
1762 struct lzw_state
1763 {
1764     struct lzw_dict dict;
1765     short init_code_bits, code_bits, next_code, clear_code, eof_code;
1766     unsigned bits_buf;
1767     int bits_count;
1768     int (*user_write_data)(void *user_ptr, void *data, int length);
1769     void *user_ptr;
1770 };
1771 
1772 struct input_stream
1773 {
1774     unsigned len;
1775     const BYTE *in;
1776 };
1777 
1778 struct output_stream
1779 {
1780     struct
1781     {
1782         unsigned char len;
1783         char data[255];
1784     } gif_block;
1785     IStream *out;
1786 };
1787 
1788 static int lzw_output_code(struct lzw_state *state, short code)
1789 {
1790     state->bits_buf |= code << state->bits_count;
1791     state->bits_count += state->code_bits;
1792 
1793     while (state->bits_count >= 8)
1794     {
1795         unsigned char byte = (unsigned char)state->bits_buf;
1796         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1797             return 0;
1798         state->bits_buf >>= 8;
1799         state->bits_count -= 8;
1800     }
1801 
1802     return 1;
1803 }
1804 
1805 static inline int lzw_output_clear_code(struct lzw_state *state)
1806 {
1807     return lzw_output_code(state, state->clear_code);
1808 }
1809 
1810 static inline int lzw_output_eof_code(struct lzw_state *state)
1811 {
1812     return lzw_output_code(state, state->eof_code);
1813 }
1814 
1815 static int lzw_flush_bits(struct lzw_state *state)
1816 {
1817     unsigned char byte;
1818 
1819     while (state->bits_count >= 8)
1820     {
1821         byte = (unsigned char)state->bits_buf;
1822         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1823             return 0;
1824         state->bits_buf >>= 8;
1825         state->bits_count -= 8;
1826     }
1827 
1828     if (state->bits_count)
1829     {
1830         static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1831 
1832         byte = (unsigned char)state->bits_buf & mask[state->bits_count];
1833         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1834             return 0;
1835     }
1836 
1837     state->bits_buf = 0;
1838     state->bits_count = 0;
1839 
1840     return 1;
1841 }
1842 
1843 static void lzw_dict_reset(struct lzw_state *state)
1844 {
1845     int i;
1846 
1847     state->code_bits = state->init_code_bits + 1;
1848     state->next_code = (1 << state->init_code_bits) + 2;
1849 
1850     for(i = 0; i < LZW_DICT_SIZE; i++)
1851     {
1852         state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
1853         state->dict.suffix[i] = 0;
1854     }
1855 }
1856 
1857 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
1858 {
1859     state->init_code_bits = init_code_bits;
1860     state->clear_code = 1 << init_code_bits;
1861     state->eof_code = state->clear_code + 1;
1862     state->bits_buf = 0;
1863     state->bits_count = 0;
1864     state->user_write_data = user_write_data;
1865     state->user_ptr = user_ptr;
1866 
1867     lzw_dict_reset(state);
1868 }
1869 
1870 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
1871 {
1872     if (state->next_code < LZW_DICT_SIZE)
1873     {
1874         state->dict.prefix[state->next_code] = prefix;
1875         state->dict.suffix[state->next_code] = suffix;
1876 
1877         if ((state->next_code & (state->next_code - 1)) == 0)
1878             state->code_bits++;
1879 
1880         state->next_code++;
1881         return state->next_code;
1882     }
1883 
1884     return -1;
1885 }
1886 
1887 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
1888 {
1889     short i;
1890 
1891     for (i = 0; i < state->next_code; i++)
1892     {
1893         if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
1894             return i;
1895     }
1896 
1897     return -1;
1898 }
1899 
1900 static inline int write_byte(struct output_stream *out, char byte)
1901 {
1902     if (out->gif_block.len == 255)
1903     {
1904         if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
1905             return 0;
1906 
1907         out->gif_block.len = 0;
1908     }
1909 
1910     out->gif_block.data[out->gif_block.len++] = byte;
1911 
1912     return 1;
1913 }
1914 
1915 static int write_data(void *user_ptr, void *user_data, int length)
1916 {
1917     unsigned char *data = user_data;
1918     struct output_stream *out = user_ptr;
1919     int len = length;
1920 
1921     while (len-- > 0)
1922     {
1923         if (!write_byte(out, *data++)) return 0;
1924     }
1925 
1926     return length;
1927 }
1928 
1929 static int flush_output_data(void *user_ptr)
1930 {
1931     struct output_stream *out = user_ptr;
1932 
1933     if (out->gif_block.len)
1934     {
1935         if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
1936             return 0;
1937     }
1938 
1939     /* write GIF block terminator */
1940     out->gif_block.len = 0;
1941     return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
1942 }
1943 
1944 static inline int read_byte(struct input_stream *in, unsigned char *byte)
1945 {
1946     if (in->len)
1947     {
1948         in->len--;
1949         *byte = *in->in++;
1950         return 1;
1951     }
1952 
1953     return 0;
1954 }
1955 
1956 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
1957 {
1958     struct input_stream in;
1959     struct output_stream out;
1960     struct lzw_state state;
1961     short init_code_bits, prefix, code;
1962     unsigned char suffix;
1963 
1964     in.in = in_data;
1965     in.len = in_size;
1966 
1967     out.gif_block.len = 0;
1968     out.out = out_stream;
1969 
1970     init_code_bits = suffix = 8;
1971     if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
1972         return E_FAIL;
1973 
1974     lzw_state_init(&state, init_code_bits, write_data, &out);
1975 
1976     if (!lzw_output_clear_code(&state))
1977         return E_FAIL;
1978 
1979     if (read_byte(&in, &suffix))
1980     {
1981         prefix = suffix;
1982 
1983         while (read_byte(&in, &suffix))
1984         {
1985             code = lzw_dict_lookup(&state, prefix, suffix);
1986             if (code == -1)
1987             {
1988                 if (!lzw_output_code(&state, prefix))
1989                     return E_FAIL;
1990 
1991                 if (lzw_dict_add(&state, prefix, suffix) == -1)
1992                 {
1993                     if (!lzw_output_clear_code(&state))
1994                         return E_FAIL;
1995                     lzw_dict_reset(&state);
1996                 }
1997 
1998                 prefix = suffix;
1999             }
2000             else
2001                 prefix = code;
2002         }
2003 
2004         if (!lzw_output_code(&state, prefix))
2005             return E_FAIL;
2006         if (!lzw_output_eof_code(&state))
2007             return E_FAIL;
2008         if (!lzw_flush_bits(&state))
2009             return E_FAIL;
2010     }
2011 
2012     return flush_output_data(&out) ? S_OK : E_FAIL;
2013 }
2014 
2015 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
2016 {
2017     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
2018     HRESULT hr;
2019 
2020     TRACE("%p\n", iface);
2021 
2022     EnterCriticalSection(&This->encoder->lock);
2023 
2024     if (This->image_data && This->lines == This->height && !This->committed)
2025     {
2026         BYTE gif_palette[256][3];
2027 
2028         hr = S_OK;
2029 
2030         if (!This->encoder->info_written)
2031         {
2032             struct logical_screen_descriptor lsd;
2033 
2034             /* Logical Screen Descriptor */
2035             memcpy(lsd.signature, "GIF89a", 6);
2036             lsd.width = This->width;
2037             lsd.height = This->height;
2038             lsd.packed = 0;
2039             if (This->encoder->colors)
2040                 lsd.packed |= 0x80; /* global color table flag */
2041             lsd.packed |= 0x07 << 4; /* color resolution */
2042             lsd.packed |= 0x07; /* global color table size */
2043             lsd.background_color_index = 0; /* FIXME */
2044             lsd.pixel_aspect_ratio = 0;
2045             hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
2046             if (hr == S_OK && This->encoder->colors)
2047             {
2048                 UINT i;
2049 
2050                 /* Global Color Table */
2051                 memset(gif_palette, 0, sizeof(gif_palette));
2052                 for (i = 0; i < This->encoder->colors; i++)
2053                 {
2054                     gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
2055                     gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
2056                     gif_palette[i][2] = This->encoder->palette[i] & 0xff;
2057                 }
2058                 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2059             }
2060 
2061             /* FIXME: write GCE, APE, etc. GIF extensions */
2062 
2063             if (hr == S_OK)
2064                 This->encoder->info_written = TRUE;
2065         }
2066 
2067         if (hr == S_OK)
2068         {
2069             char image_separator = 0x2c;
2070 
2071             hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
2072             if (hr == S_OK)
2073             {
2074                 struct image_descriptor imd;
2075 
2076                 /* Image Descriptor */
2077                 imd.left = 0;
2078                 imd.top = 0;
2079                 imd.width = This->width;
2080                 imd.height = This->height;
2081                 imd.packed = 0;
2082                 if (This->colors)
2083                 {
2084                     imd.packed |= 0x80; /* local color table flag */
2085                     imd.packed |= 0x07; /* local color table size */
2086                 }
2087                 /* FIXME: interlace flag */
2088                 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
2089                 if (hr == S_OK && This->colors)
2090                 {
2091                     UINT i;
2092 
2093                     /* Local Color Table */
2094                     memset(gif_palette, 0, sizeof(gif_palette));
2095                     for (i = 0; i < This->colors; i++)
2096                     {
2097                         gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
2098                         gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
2099                         gif_palette[i][2] = This->palette[i] & 0xff;
2100                     }
2101                     hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2102                     if (hr == S_OK)
2103                     {
2104                         /* Image Data */
2105                         hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
2106                         if (hr == S_OK)
2107                             This->committed = TRUE;
2108                     }
2109                 }
2110             }
2111         }
2112     }
2113     else
2114         hr = WINCODEC_ERR_WRONGSTATE;
2115 
2116     LeaveCriticalSection(&This->encoder->lock);
2117     return hr;
2118 }
2119 
2120 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
2121 {
2122     FIXME("%p, %p: stub\n", iface, writer);
2123     return E_NOTIMPL;
2124 }
2125 
2126 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
2127 {
2128     GifFrameEncode_QueryInterface,
2129     GifFrameEncode_AddRef,
2130     GifFrameEncode_Release,
2131     GifFrameEncode_Initialize,
2132     GifFrameEncode_SetSize,
2133     GifFrameEncode_SetResolution,
2134     GifFrameEncode_SetPixelFormat,
2135     GifFrameEncode_SetColorContexts,
2136     GifFrameEncode_SetPalette,
2137     GifFrameEncode_SetThumbnail,
2138     GifFrameEncode_WritePixels,
2139     GifFrameEncode_WriteSource,
2140     GifFrameEncode_Commit,
2141     GifFrameEncode_GetMetadataQueryWriter
2142 };
2143 
2144 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
2145 {
2146     TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
2147 
2148     if (!ppv) return E_INVALIDARG;
2149 
2150     if (IsEqualIID(&IID_IUnknown, iid) ||
2151         IsEqualIID(&IID_IWICBitmapEncoder, iid))
2152     {
2153         IWICBitmapEncoder_AddRef(iface);
2154         *ppv = iface;
2155         return S_OK;
2156     }
2157 
2158     *ppv = NULL;
2159     return E_NOINTERFACE;
2160 }
2161 
2162 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
2163 {
2164     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2165     ULONG ref = InterlockedIncrement(&This->ref);
2166 
2167     TRACE("%p -> %u\n", iface, ref);
2168     return ref;
2169 }
2170 
2171 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
2172 {
2173     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2174     ULONG ref = InterlockedDecrement(&This->ref);
2175 
2176     TRACE("%p -> %u\n", iface, ref);
2177 
2178     if (!ref)
2179     {
2180         if (This->stream) IStream_Release(This->stream);
2181         This->lock.DebugInfo->Spare[0] = 0;
2182         DeleteCriticalSection(&This->lock);
2183         HeapFree(GetProcessHeap(), 0, This);
2184     }
2185 
2186     return ref;
2187 }
2188 
2189 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
2190 {
2191     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2192     HRESULT hr;
2193 
2194     TRACE("%p,%p,%#x\n", iface, stream, option);
2195 
2196     if (!stream) return E_INVALIDARG;
2197 
2198     EnterCriticalSection(&This->lock);
2199 
2200     if (!This->initialized)
2201     {
2202         IStream_AddRef(stream);
2203         This->stream = stream;
2204         This->initialized = TRUE;
2205         hr = S_OK;
2206     }
2207     else
2208         hr = WINCODEC_ERR_WRONGSTATE;
2209 
2210     LeaveCriticalSection(&This->lock);
2211 
2212     return hr;
2213 }
2214 
2215 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
2216 {
2217     if (!format) return E_INVALIDARG;
2218 
2219     *format = GUID_ContainerFormatGif;
2220     return S_OK;
2221 }
2222 
2223 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
2224 {
2225     IWICComponentInfo *comp_info;
2226     HRESULT hr;
2227 
2228     TRACE("%p,%p\n", iface, info);
2229 
2230     if (!info) return E_INVALIDARG;
2231 
2232     hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
2233     if (hr == S_OK)
2234     {
2235         hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2236         IWICComponentInfo_Release(comp_info);
2237     }
2238     return hr;
2239 }
2240 
2241 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
2242 {
2243     FIXME("%p,%u,%p: stub\n", iface, count, context);
2244     return E_NOTIMPL;
2245 }
2246 
2247 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2248 {
2249     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2250     HRESULT hr;
2251 
2252     TRACE("%p,%p\n", iface, palette);
2253 
2254     if (!palette) return E_INVALIDARG;
2255 
2256     EnterCriticalSection(&This->lock);
2257 
2258     if (This->initialized)
2259         hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
2260     else
2261         hr = WINCODEC_ERR_NOTINITIALIZED;
2262 
2263     LeaveCriticalSection(&This->lock);
2264     return hr;
2265 }
2266 
2267 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
2268 {
2269     TRACE("%p,%p\n", iface, thumbnail);
2270     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2271 }
2272 
2273 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
2274 {
2275     TRACE("%p,%p\n", iface, preview);
2276     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2277 }
2278 
2279 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
2280 {
2281     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2282     HRESULT hr;
2283 
2284     TRACE("%p,%p,%p\n", iface, frame, options);
2285 
2286     if (!frame) return E_INVALIDARG;
2287 
2288     EnterCriticalSection(&This->lock);
2289 
2290     if (This->initialized && !This->committed)
2291     {
2292         GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
2293         if (ret)
2294         {
2295             This->n_frames++;
2296 
2297             ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
2298             ret->ref = 1;
2299             ret->encoder = This;
2300             ret->initialized = FALSE;
2301             ret->interlace = FALSE; /* FIXME: read from the properties */
2302             ret->committed = FALSE;
2303             ret->width = 0;
2304             ret->height = 0;
2305             ret->lines = 0;
2306             ret->xres = 0.0;
2307             ret->yres = 0.0;
2308             ret->colors = 0;
2309             ret->image_data = NULL;
2310             IWICBitmapEncoder_AddRef(iface);
2311             *frame = &ret->IWICBitmapFrameEncode_iface;
2312 
2313             hr = S_OK;
2314 
2315             if (options)
2316             {
2317                 hr = CreatePropertyBag2(NULL, 0, options);
2318                 if (hr != S_OK)
2319                 {
2320                     IWICBitmapFrameEncode_Release(*frame);
2321                     *frame = NULL;
2322                 }
2323             }
2324         }
2325         else
2326             hr = E_OUTOFMEMORY;
2327     }
2328     else
2329         hr = WINCODEC_ERR_WRONGSTATE;
2330 
2331     LeaveCriticalSection(&This->lock);
2332 
2333     return hr;
2334 
2335 }
2336 
2337 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
2338 {
2339     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2340     HRESULT hr;
2341 
2342     TRACE("%p\n", iface);
2343 
2344     EnterCriticalSection(&This->lock);
2345 
2346     if (This->initialized && !This->committed)
2347     {
2348         char gif_trailer = 0x3b;
2349 
2350         /* FIXME: write text, comment GIF extensions */
2351 
2352         hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
2353         if (hr == S_OK)
2354             This->committed = TRUE;
2355     }
2356     else
2357         hr = WINCODEC_ERR_WRONGSTATE;
2358 
2359     LeaveCriticalSection(&This->lock);
2360     return hr;
2361 }
2362 
2363 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
2364 {
2365     FIXME("%p,%p: stub\n", iface, writer);
2366     return E_NOTIMPL;
2367 }
2368 
2369 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
2370 {
2371     GifEncoder_QueryInterface,
2372     GifEncoder_AddRef,
2373     GifEncoder_Release,
2374     GifEncoder_Initialize,
2375     GifEncoder_GetContainerFormat,
2376     GifEncoder_GetEncoderInfo,
2377     GifEncoder_SetColorContexts,
2378     GifEncoder_SetPalette,
2379     GifEncoder_SetThumbnail,
2380     GifEncoder_SetPreview,
2381     GifEncoder_CreateNewFrame,
2382     GifEncoder_Commit,
2383     GifEncoder_GetMetadataQueryWriter
2384 };
2385 
2386 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
2387 {
2388     GifEncoder *This;
2389     HRESULT ret;
2390 
2391     TRACE("%s,%p\n", debugstr_guid(iid), ppv);
2392 
2393     *ppv = NULL;
2394 
2395     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2396     if (!This) return E_OUTOFMEMORY;
2397 
2398     This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
2399     This->ref = 1;
2400     This->stream = NULL;
2401     InitializeCriticalSection(&This->lock);
2402     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
2403     This->initialized = FALSE;
2404     This->info_written = FALSE;
2405     This->committed = FALSE;
2406     This->n_frames = 0;
2407     This->colors = 0;
2408 
2409     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2410     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2411 
2412     return ret;
2413 }
2414