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