xref: /reactos/dll/win32/windowscodecs/gifformat.c (revision cc439606)
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     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1180 
1181     return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo);
1182 }
1183 
1184 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1185 {
1186     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1187     WICColor colors[256];
1188     ColorMapObject *cm;
1189     int i, trans, count;
1190     ExtensionBlock *eb;
1191 
1192     TRACE("(%p,%p)\n", iface, palette);
1193 
1194     if (!This->gif)
1195         return WINCODEC_ERR_WRONGSTATE;
1196 
1197     cm = This->gif->SColorMap;
1198     if (cm)
1199     {
1200         if (cm->ColorCount > 256)
1201         {
1202             ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
1203             return E_FAIL;
1204         }
1205 
1206         for (i = 0; i < cm->ColorCount; i++)
1207         {
1208             colors[i] = 0xff000000 | /* alpha */
1209                         cm->Colors[i].Red << 16 |
1210                         cm->Colors[i].Green << 8 |
1211                         cm->Colors[i].Blue;
1212         }
1213 
1214         count = cm->ColorCount;
1215     }
1216     else
1217     {
1218         colors[0] = 0xff000000;
1219         colors[1] = 0xffffffff;
1220 
1221         for (i = 2; i < 256; i++)
1222             colors[i] = 0xff000000;
1223 
1224         count = 256;
1225     }
1226 
1227     /* look for the transparent color extension */
1228     for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
1229     {
1230         eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
1231         if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
1232         {
1233             if (eb->Bytes[3] & 1)
1234             {
1235                 trans = (unsigned char)eb->Bytes[6];
1236                 colors[trans] &= 0xffffff; /* set alpha to 0 */
1237                 break;
1238             }
1239         }
1240     }
1241 
1242     return IWICPalette_InitializeCustom(palette, colors, count);
1243 }
1244 
1245 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1246     IWICMetadataQueryReader **ppIMetadataQueryReader)
1247 {
1248     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1249 
1250     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1251 
1252     if (!ppIMetadataQueryReader) return E_INVALIDARG;
1253 
1254     return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1255 }
1256 
1257 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1258     IWICBitmapSource **ppIBitmapSource)
1259 {
1260     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1261     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1262 }
1263 
1264 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1265     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1266 {
1267     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1268     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1269 }
1270 
1271 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1272     IWICBitmapSource **ppIThumbnail)
1273 {
1274     TRACE("(%p,%p)\n", iface, ppIThumbnail);
1275     return WINCODEC_ERR_CODECNOTHUMBNAIL;
1276 }
1277 
1278 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1279     UINT *pCount)
1280 {
1281     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1282 
1283     if (!pCount) return E_INVALIDARG;
1284 
1285     EnterCriticalSection(&This->lock);
1286     *pCount = This->gif ? This->gif->ImageCount : 0;
1287     LeaveCriticalSection(&This->lock);
1288 
1289     TRACE("(%p) <-- %d\n", iface, *pCount);
1290 
1291     return S_OK;
1292 }
1293 
1294 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1295     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1296 {
1297     GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1298     GifFrameDecode *result;
1299     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1300 
1301     if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1302 
1303     if (index >= This->gif->ImageCount) return E_INVALIDARG;
1304 
1305     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1306     if (!result) return E_OUTOFMEMORY;
1307 
1308     result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1309     result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1310     result->ref = 1;
1311     result->frame = &This->gif->SavedImages[index];
1312     IWICBitmapDecoder_AddRef(iface);
1313     result->parent = This;
1314     This->current_frame = index;
1315 
1316     *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1317 
1318     return S_OK;
1319 }
1320 
1321 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1322     GifDecoder_QueryInterface,
1323     GifDecoder_AddRef,
1324     GifDecoder_Release,
1325     GifDecoder_QueryCapability,
1326     GifDecoder_Initialize,
1327     GifDecoder_GetContainerFormat,
1328     GifDecoder_GetDecoderInfo,
1329     GifDecoder_CopyPalette,
1330     GifDecoder_GetMetadataQueryReader,
1331     GifDecoder_GetPreview,
1332     GifDecoder_GetColorContexts,
1333     GifDecoder_GetThumbnail,
1334     GifDecoder_GetFrameCount,
1335     GifDecoder_GetFrame
1336 };
1337 
1338 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1339     REFIID iid, void **ppv)
1340 {
1341     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1342     return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1343 }
1344 
1345 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1346 {
1347     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1348     return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1349 }
1350 
1351 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1352 {
1353     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1354     return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1355 }
1356 
1357 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1358     GUID *guid)
1359 {
1360     TRACE("(%p,%p)\n", iface, guid);
1361 
1362     if (!guid) return E_INVALIDARG;
1363 
1364     *guid = GUID_ContainerFormatGif;
1365     return S_OK;
1366 }
1367 
1368 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1369     UINT *count)
1370 {
1371     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1372 
1373     TRACE("%p,%p\n", iface, count);
1374 
1375     if (!count) return E_INVALIDARG;
1376 
1377     *count = This->gif->Extensions.ExtensionBlockCount + 1;
1378     return S_OK;
1379 }
1380 
1381 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1382     UINT index, IWICMetadataReader **reader)
1383 {
1384     GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1385     int i;
1386 
1387     TRACE("(%p,%u,%p)\n", iface, index, reader);
1388 
1389     if (!reader) return E_INVALIDARG;
1390 
1391     if (index == 0)
1392         return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1393                                       LSDReader_CreateInstance, reader);
1394 
1395     for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1396     {
1397         class_constructor constructor;
1398 
1399         if (index != i + 1) continue;
1400 
1401         if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1402             constructor = APEReader_CreateInstance;
1403         else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1404             constructor = GifCommentReader_CreateInstance;
1405         else
1406             constructor = UnknownMetadataReader_CreateInstance;
1407 
1408         return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1409                                       This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1410                                       constructor, reader);
1411     }
1412 
1413     return E_INVALIDARG;
1414 }
1415 
1416 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1417     IEnumUnknown **enumerator)
1418 {
1419     FIXME("(%p,%p): stub\n", iface, enumerator);
1420     return E_NOTIMPL;
1421 }
1422 
1423 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1424 {
1425     GifDecoder_Block_QueryInterface,
1426     GifDecoder_Block_AddRef,
1427     GifDecoder_Block_Release,
1428     GifDecoder_Block_GetContainerFormat,
1429     GifDecoder_Block_GetCount,
1430     GifDecoder_Block_GetReaderByIndex,
1431     GifDecoder_Block_GetEnumerator
1432 };
1433 
1434 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
1435 {
1436     GifDecoder *This;
1437     HRESULT ret;
1438 
1439     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1440 
1441     *ppv = NULL;
1442 
1443     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1444     if (!This) return E_OUTOFMEMORY;
1445 
1446     This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1447     This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1448     This->stream = NULL;
1449     This->ref = 1;
1450     This->initialized = FALSE;
1451     This->gif = NULL;
1452     This->current_frame = 0;
1453     InitializeCriticalSection(&This->lock);
1454     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1455 
1456     ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1457     IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1458 
1459     return ret;
1460 }
1461 
1462 typedef struct GifEncoder
1463 {
1464     IWICBitmapEncoder IWICBitmapEncoder_iface;
1465     LONG ref;
1466     IStream *stream;
1467     CRITICAL_SECTION lock;
1468     BOOL initialized, info_written, committed;
1469     UINT n_frames;
1470     WICColor palette[256];
1471     UINT colors;
1472 } GifEncoder;
1473 
1474 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1475 {
1476     return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
1477 }
1478 
1479 typedef struct GifFrameEncode
1480 {
1481     IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1482     LONG ref;
1483     GifEncoder *encoder;
1484     BOOL initialized, interlace, committed;
1485     UINT width, height, lines;
1486     double xres, yres;
1487     WICColor palette[256];
1488     UINT colors;
1489     BYTE *image_data;
1490 } GifFrameEncode;
1491 
1492 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1493 {
1494     return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
1495 }
1496 
1497 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1498 {
1499     TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
1500 
1501     if (!ppv) return E_INVALIDARG;
1502 
1503     if (IsEqualIID(&IID_IUnknown, iid) ||
1504         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1505     {
1506         IWICBitmapFrameEncode_AddRef(iface);
1507         *ppv = iface;
1508         return S_OK;
1509     }
1510 
1511     *ppv = NULL;
1512     return E_NOINTERFACE;
1513 }
1514 
1515 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1516 {
1517     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1518     ULONG ref = InterlockedIncrement(&This->ref);
1519 
1520     TRACE("%p -> %u\n", iface, ref);
1521     return ref;
1522 }
1523 
1524 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
1525 {
1526     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1527     ULONG ref = InterlockedDecrement(&This->ref);
1528 
1529     TRACE("%p -> %u\n", iface, ref);
1530 
1531     if (!ref)
1532     {
1533         IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
1534         HeapFree(GetProcessHeap(), 0, This->image_data);
1535         HeapFree(GetProcessHeap(), 0, This);
1536     }
1537 
1538     return ref;
1539 }
1540 
1541 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
1542 {
1543     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1544     HRESULT hr;
1545 
1546     TRACE("%p,%p\n", iface, options);
1547 
1548     EnterCriticalSection(&This->encoder->lock);
1549 
1550     if (!This->initialized)
1551     {
1552         This->initialized = TRUE;
1553         hr = S_OK;
1554     }
1555     else
1556         hr = WINCODEC_ERR_WRONGSTATE;
1557 
1558     LeaveCriticalSection(&This->encoder->lock);
1559 
1560     return hr;
1561 }
1562 
1563 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
1564 {
1565     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1566     HRESULT hr;
1567 
1568     TRACE("%p,%u,%u\n", iface, width, height);
1569 
1570     if (!width || !height) return E_INVALIDARG;
1571 
1572     EnterCriticalSection(&This->encoder->lock);
1573 
1574     if (This->initialized)
1575     {
1576         HeapFree(GetProcessHeap(), 0, This->image_data);
1577 
1578         This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height);
1579         if (This->image_data)
1580         {
1581             This->width = width;
1582             This->height = height;
1583             hr = S_OK;
1584         }
1585         else
1586             hr = E_OUTOFMEMORY;
1587     }
1588     else
1589         hr = WINCODEC_ERR_WRONGSTATE;
1590 
1591     LeaveCriticalSection(&This->encoder->lock);
1592 
1593     return hr;
1594 }
1595 
1596 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
1597 {
1598     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1599     HRESULT hr;
1600 
1601     TRACE("%p,%f,%f\n", iface, xres, yres);
1602 
1603     EnterCriticalSection(&This->encoder->lock);
1604 
1605     if (This->initialized)
1606     {
1607         This->xres = xres;
1608         This->yres = yres;
1609         hr = S_OK;
1610     }
1611     else
1612         hr = WINCODEC_ERR_WRONGSTATE;
1613 
1614     LeaveCriticalSection(&This->encoder->lock);
1615 
1616     return hr;
1617 }
1618 
1619 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
1620 {
1621     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1622     HRESULT hr;
1623 
1624     TRACE("%p,%s\n", iface, debugstr_guid(format));
1625 
1626     if (!format) return E_INVALIDARG;
1627 
1628     EnterCriticalSection(&This->encoder->lock);
1629 
1630     if (This->initialized)
1631     {
1632         *format = GUID_WICPixelFormat8bppIndexed;
1633         hr = S_OK;
1634     }
1635     else
1636         hr = WINCODEC_ERR_WRONGSTATE;
1637 
1638     LeaveCriticalSection(&This->encoder->lock);
1639 
1640     return hr;
1641 }
1642 
1643 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
1644 {
1645     FIXME("%p,%u,%p: stub\n", iface, count, context);
1646     return E_NOTIMPL;
1647 }
1648 
1649 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
1650 {
1651     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1652     HRESULT hr;
1653 
1654     TRACE("%p,%p\n", iface, palette);
1655 
1656     if (!palette) return E_INVALIDARG;
1657 
1658     EnterCriticalSection(&This->encoder->lock);
1659 
1660     if (This->initialized)
1661         hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1662     else
1663         hr = WINCODEC_ERR_NOTINITIALIZED;
1664 
1665     LeaveCriticalSection(&This->encoder->lock);
1666     return hr;
1667 }
1668 
1669 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
1670 {
1671     FIXME("%p,%p: stub\n", iface, thumbnail);
1672     return E_NOTIMPL;
1673 }
1674 
1675 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
1676 {
1677     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1678     HRESULT hr;
1679 
1680     TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
1681 
1682     if (!pixels) return E_INVALIDARG;
1683 
1684     EnterCriticalSection(&This->encoder->lock);
1685 
1686     if (This->initialized && This->image_data)
1687     {
1688         if (This->lines + lines <= This->height)
1689         {
1690             UINT i;
1691             BYTE *src, *dst;
1692 
1693             src = pixels;
1694             dst = This->image_data + This->lines * This->width;
1695 
1696             for (i = 0; i < lines; i++)
1697             {
1698                 memcpy(dst, src, This->width);
1699                 src += stride;
1700                 dst += This->width;
1701             }
1702 
1703             This->lines += lines;
1704             hr = S_OK;
1705         }
1706         else
1707             hr = E_INVALIDARG;
1708     }
1709     else
1710         hr = WINCODEC_ERR_WRONGSTATE;
1711 
1712     LeaveCriticalSection(&This->encoder->lock);
1713     return hr;
1714 }
1715 
1716 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
1717 {
1718     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1719     HRESULT hr;
1720 
1721     TRACE("%p,%p,%p\n", iface, source, rc);
1722 
1723     if (!source) return E_INVALIDARG;
1724 
1725     EnterCriticalSection(&This->encoder->lock);
1726 
1727     if (This->initialized)
1728     {
1729         const GUID *format = &GUID_WICPixelFormat8bppIndexed;
1730 
1731         hr = configure_write_source(iface, source, rc, format,
1732                                     This->width, This->height, This->xres, This->yres);
1733         if (hr == S_OK)
1734             hr = write_source(iface, source, rc, format, 8, This->width, This->height);
1735     }
1736     else
1737         hr = WINCODEC_ERR_WRONGSTATE;
1738 
1739     LeaveCriticalSection(&This->encoder->lock);
1740     return hr;
1741 }
1742 
1743 #define LZW_DICT_SIZE (1 << 12)
1744 
1745 struct lzw_dict
1746 {
1747     short prefix[LZW_DICT_SIZE];
1748     unsigned char suffix[LZW_DICT_SIZE];
1749 };
1750 
1751 struct lzw_state
1752 {
1753     struct lzw_dict dict;
1754     short init_code_bits, code_bits, next_code, clear_code, eof_code;
1755     unsigned bits_buf;
1756     int bits_count;
1757     int (*user_write_data)(void *user_ptr, void *data, int length);
1758     void *user_ptr;
1759 };
1760 
1761 struct input_stream
1762 {
1763     unsigned len;
1764     const BYTE *in;
1765 };
1766 
1767 struct output_stream
1768 {
1769     struct
1770     {
1771         unsigned char len;
1772         char data[255];
1773     } gif_block;
1774     IStream *out;
1775 };
1776 
1777 static int lzw_output_code(struct lzw_state *state, short code)
1778 {
1779     state->bits_buf |= code << state->bits_count;
1780     state->bits_count += state->code_bits;
1781 
1782     while (state->bits_count >= 8)
1783     {
1784         unsigned char byte = (unsigned char)state->bits_buf;
1785         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1786             return 0;
1787         state->bits_buf >>= 8;
1788         state->bits_count -= 8;
1789     }
1790 
1791     return 1;
1792 }
1793 
1794 static inline int lzw_output_clear_code(struct lzw_state *state)
1795 {
1796     return lzw_output_code(state, state->clear_code);
1797 }
1798 
1799 static inline int lzw_output_eof_code(struct lzw_state *state)
1800 {
1801     return lzw_output_code(state, state->eof_code);
1802 }
1803 
1804 static int lzw_flush_bits(struct lzw_state *state)
1805 {
1806     unsigned char byte;
1807 
1808     while (state->bits_count >= 8)
1809     {
1810         byte = (unsigned char)state->bits_buf;
1811         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1812             return 0;
1813         state->bits_buf >>= 8;
1814         state->bits_count -= 8;
1815     }
1816 
1817     if (state->bits_count)
1818     {
1819         static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1820 
1821         byte = (unsigned char)state->bits_buf & mask[state->bits_count];
1822         if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1823             return 0;
1824     }
1825 
1826     state->bits_buf = 0;
1827     state->bits_count = 0;
1828 
1829     return 1;
1830 }
1831 
1832 static void lzw_dict_reset(struct lzw_state *state)
1833 {
1834     int i;
1835 
1836     state->code_bits = state->init_code_bits + 1;
1837     state->next_code = (1 << state->init_code_bits) + 2;
1838 
1839     for(i = 0; i < LZW_DICT_SIZE; i++)
1840     {
1841         state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
1842         state->dict.suffix[i] = 0;
1843     }
1844 }
1845 
1846 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
1847 {
1848     state->init_code_bits = init_code_bits;
1849     state->clear_code = 1 << init_code_bits;
1850     state->eof_code = state->clear_code + 1;
1851     state->bits_buf = 0;
1852     state->bits_count = 0;
1853     state->user_write_data = user_write_data;
1854     state->user_ptr = user_ptr;
1855 
1856     lzw_dict_reset(state);
1857 }
1858 
1859 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
1860 {
1861     if (state->next_code < LZW_DICT_SIZE)
1862     {
1863         state->dict.prefix[state->next_code] = prefix;
1864         state->dict.suffix[state->next_code] = suffix;
1865 
1866         if ((state->next_code & (state->next_code - 1)) == 0)
1867             state->code_bits++;
1868 
1869         state->next_code++;
1870         return state->next_code;
1871     }
1872 
1873     return -1;
1874 }
1875 
1876 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
1877 {
1878     short i;
1879 
1880     for (i = 0; i < state->next_code; i++)
1881     {
1882         if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
1883             return i;
1884     }
1885 
1886     return -1;
1887 }
1888 
1889 static inline int write_byte(struct output_stream *out, char byte)
1890 {
1891     if (out->gif_block.len == 255)
1892     {
1893         if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
1894             return 0;
1895 
1896         out->gif_block.len = 0;
1897     }
1898 
1899     out->gif_block.data[out->gif_block.len++] = byte;
1900 
1901     return 1;
1902 }
1903 
1904 static int write_data(void *user_ptr, void *user_data, int length)
1905 {
1906     unsigned char *data = user_data;
1907     struct output_stream *out = user_ptr;
1908     int len = length;
1909 
1910     while (len-- > 0)
1911     {
1912         if (!write_byte(out, *data++)) return 0;
1913     }
1914 
1915     return length;
1916 }
1917 
1918 static int flush_output_data(void *user_ptr)
1919 {
1920     struct output_stream *out = user_ptr;
1921 
1922     if (out->gif_block.len)
1923     {
1924         if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
1925             return 0;
1926     }
1927 
1928     /* write GIF block terminator */
1929     out->gif_block.len = 0;
1930     return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
1931 }
1932 
1933 static inline int read_byte(struct input_stream *in, unsigned char *byte)
1934 {
1935     if (in->len)
1936     {
1937         in->len--;
1938         *byte = *in->in++;
1939         return 1;
1940     }
1941 
1942     return 0;
1943 }
1944 
1945 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
1946 {
1947     struct input_stream in;
1948     struct output_stream out;
1949     struct lzw_state state;
1950     short init_code_bits, prefix, code;
1951     unsigned char suffix;
1952 
1953     in.in = in_data;
1954     in.len = in_size;
1955 
1956     out.gif_block.len = 0;
1957     out.out = out_stream;
1958 
1959     init_code_bits = suffix = 8;
1960     if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
1961         return E_FAIL;
1962 
1963     lzw_state_init(&state, init_code_bits, write_data, &out);
1964 
1965     if (!lzw_output_clear_code(&state))
1966         return E_FAIL;
1967 
1968     if (read_byte(&in, &suffix))
1969     {
1970         prefix = suffix;
1971 
1972         while (read_byte(&in, &suffix))
1973         {
1974             code = lzw_dict_lookup(&state, prefix, suffix);
1975             if (code == -1)
1976             {
1977                 if (!lzw_output_code(&state, prefix))
1978                     return E_FAIL;
1979 
1980                 if (lzw_dict_add(&state, prefix, suffix) == -1)
1981                 {
1982                     if (!lzw_output_clear_code(&state))
1983                         return E_FAIL;
1984                     lzw_dict_reset(&state);
1985                 }
1986 
1987                 prefix = suffix;
1988             }
1989             else
1990                 prefix = code;
1991         }
1992 
1993         if (!lzw_output_code(&state, prefix))
1994             return E_FAIL;
1995         if (!lzw_output_eof_code(&state))
1996             return E_FAIL;
1997         if (!lzw_flush_bits(&state))
1998             return E_FAIL;
1999     }
2000 
2001     return flush_output_data(&out) ? S_OK : E_FAIL;
2002 }
2003 
2004 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
2005 {
2006     GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
2007     HRESULT hr;
2008 
2009     TRACE("%p\n", iface);
2010 
2011     EnterCriticalSection(&This->encoder->lock);
2012 
2013     if (This->image_data && This->lines == This->height && !This->committed)
2014     {
2015         BYTE gif_palette[256][3];
2016 
2017         hr = S_OK;
2018 
2019         if (!This->encoder->info_written)
2020         {
2021             struct logical_screen_descriptor lsd;
2022 
2023             /* Logical Screen Descriptor */
2024             memcpy(lsd.signature, "GIF89a", 6);
2025             lsd.width = This->width;
2026             lsd.height = This->height;
2027             lsd.packed = 0;
2028             if (This->encoder->colors)
2029                 lsd.packed |= 0x80; /* global color table flag */
2030             lsd.packed |= 0x07 << 4; /* color resolution */
2031             lsd.packed |= 0x07; /* global color table size */
2032             lsd.background_color_index = 0; /* FIXME */
2033             lsd.pixel_aspect_ratio = 0;
2034             hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
2035             if (hr == S_OK && This->encoder->colors)
2036             {
2037                 UINT i;
2038 
2039                 /* Global Color Table */
2040                 memset(gif_palette, 0, sizeof(gif_palette));
2041                 for (i = 0; i < This->encoder->colors; i++)
2042                 {
2043                     gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
2044                     gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
2045                     gif_palette[i][2] = This->encoder->palette[i] & 0xff;
2046                 }
2047                 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2048             }
2049 
2050             /* FIXME: write GCE, APE, etc. GIF extensions */
2051 
2052             if (hr == S_OK)
2053                 This->encoder->info_written = TRUE;
2054         }
2055 
2056         if (hr == S_OK)
2057         {
2058             char image_separator = 0x2c;
2059 
2060             hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
2061             if (hr == S_OK)
2062             {
2063                 struct image_descriptor imd;
2064 
2065                 /* Image Descriptor */
2066                 imd.left = 0;
2067                 imd.top = 0;
2068                 imd.width = This->width;
2069                 imd.height = This->height;
2070                 imd.packed = 0;
2071                 if (This->colors)
2072                 {
2073                     imd.packed |= 0x80; /* local color table flag */
2074                     imd.packed |= 0x07; /* local color table size */
2075                 }
2076                 /* FIXME: interlace flag */
2077                 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
2078                 if (hr == S_OK && This->colors)
2079                 {
2080                     UINT i;
2081 
2082                     /* Local Color Table */
2083                     memset(gif_palette, 0, sizeof(gif_palette));
2084                     for (i = 0; i < This->colors; i++)
2085                     {
2086                         gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
2087                         gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
2088                         gif_palette[i][2] = This->palette[i] & 0xff;
2089                     }
2090                     hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2091                     if (hr == S_OK)
2092                     {
2093                         /* Image Data */
2094                         hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
2095                         if (hr == S_OK)
2096                             This->committed = TRUE;
2097                     }
2098                 }
2099             }
2100         }
2101     }
2102     else
2103         hr = WINCODEC_ERR_WRONGSTATE;
2104 
2105     LeaveCriticalSection(&This->encoder->lock);
2106     return hr;
2107 }
2108 
2109 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
2110 {
2111     FIXME("%p, %p: stub\n", iface, writer);
2112     return E_NOTIMPL;
2113 }
2114 
2115 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
2116 {
2117     GifFrameEncode_QueryInterface,
2118     GifFrameEncode_AddRef,
2119     GifFrameEncode_Release,
2120     GifFrameEncode_Initialize,
2121     GifFrameEncode_SetSize,
2122     GifFrameEncode_SetResolution,
2123     GifFrameEncode_SetPixelFormat,
2124     GifFrameEncode_SetColorContexts,
2125     GifFrameEncode_SetPalette,
2126     GifFrameEncode_SetThumbnail,
2127     GifFrameEncode_WritePixels,
2128     GifFrameEncode_WriteSource,
2129     GifFrameEncode_Commit,
2130     GifFrameEncode_GetMetadataQueryWriter
2131 };
2132 
2133 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
2134 {
2135     TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
2136 
2137     if (!ppv) return E_INVALIDARG;
2138 
2139     if (IsEqualIID(&IID_IUnknown, iid) ||
2140         IsEqualIID(&IID_IWICBitmapEncoder, iid))
2141     {
2142         IWICBitmapEncoder_AddRef(iface);
2143         *ppv = iface;
2144         return S_OK;
2145     }
2146 
2147     *ppv = NULL;
2148     return E_NOINTERFACE;
2149 }
2150 
2151 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
2152 {
2153     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2154     ULONG ref = InterlockedIncrement(&This->ref);
2155 
2156     TRACE("%p -> %u\n", iface, ref);
2157     return ref;
2158 }
2159 
2160 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
2161 {
2162     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2163     ULONG ref = InterlockedDecrement(&This->ref);
2164 
2165     TRACE("%p -> %u\n", iface, ref);
2166 
2167     if (!ref)
2168     {
2169         if (This->stream) IStream_Release(This->stream);
2170         This->lock.DebugInfo->Spare[0] = 0;
2171         DeleteCriticalSection(&This->lock);
2172         HeapFree(GetProcessHeap(), 0, This);
2173     }
2174 
2175     return ref;
2176 }
2177 
2178 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
2179 {
2180     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2181     HRESULT hr;
2182 
2183     TRACE("%p,%p,%#x\n", iface, stream, option);
2184 
2185     if (!stream) return E_INVALIDARG;
2186 
2187     EnterCriticalSection(&This->lock);
2188 
2189     if (!This->initialized)
2190     {
2191         IStream_AddRef(stream);
2192         This->stream = stream;
2193         This->initialized = TRUE;
2194         hr = S_OK;
2195     }
2196     else
2197         hr = WINCODEC_ERR_WRONGSTATE;
2198 
2199     LeaveCriticalSection(&This->lock);
2200 
2201     return hr;
2202 }
2203 
2204 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
2205 {
2206     if (!format) return E_INVALIDARG;
2207 
2208     *format = GUID_ContainerFormatGif;
2209     return S_OK;
2210 }
2211 
2212 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
2213 {
2214     IWICComponentInfo *comp_info;
2215     HRESULT hr;
2216 
2217     TRACE("%p,%p\n", iface, info);
2218 
2219     if (!info) return E_INVALIDARG;
2220 
2221     hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
2222     if (hr == S_OK)
2223     {
2224         hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2225         IWICComponentInfo_Release(comp_info);
2226     }
2227     return hr;
2228 }
2229 
2230 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
2231 {
2232     FIXME("%p,%u,%p: stub\n", iface, count, context);
2233     return E_NOTIMPL;
2234 }
2235 
2236 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2237 {
2238     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2239     HRESULT hr;
2240 
2241     TRACE("%p,%p\n", iface, palette);
2242 
2243     if (!palette) return E_INVALIDARG;
2244 
2245     EnterCriticalSection(&This->lock);
2246 
2247     if (This->initialized)
2248         hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
2249     else
2250         hr = WINCODEC_ERR_NOTINITIALIZED;
2251 
2252     LeaveCriticalSection(&This->lock);
2253     return hr;
2254 }
2255 
2256 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
2257 {
2258     TRACE("%p,%p\n", iface, thumbnail);
2259     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2260 }
2261 
2262 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
2263 {
2264     TRACE("%p,%p\n", iface, preview);
2265     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2266 }
2267 
2268 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
2269 {
2270     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2271     HRESULT hr;
2272 
2273     TRACE("%p,%p,%p\n", iface, frame, options);
2274 
2275     if (!frame) return E_INVALIDARG;
2276 
2277     EnterCriticalSection(&This->lock);
2278 
2279     if (This->initialized && !This->committed)
2280     {
2281         GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
2282         if (ret)
2283         {
2284             This->n_frames++;
2285 
2286             ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
2287             ret->ref = 1;
2288             ret->encoder = This;
2289             ret->initialized = FALSE;
2290             ret->interlace = FALSE; /* FIXME: read from the properties */
2291             ret->committed = FALSE;
2292             ret->width = 0;
2293             ret->height = 0;
2294             ret->lines = 0;
2295             ret->xres = 0.0;
2296             ret->yres = 0.0;
2297             ret->colors = 0;
2298             ret->image_data = NULL;
2299             IWICBitmapEncoder_AddRef(iface);
2300             *frame = &ret->IWICBitmapFrameEncode_iface;
2301 
2302             hr = S_OK;
2303 
2304             if (options)
2305             {
2306                 hr = CreatePropertyBag2(NULL, 0, options);
2307                 if (hr != S_OK)
2308                 {
2309                     IWICBitmapFrameEncode_Release(*frame);
2310                     *frame = NULL;
2311                 }
2312             }
2313         }
2314         else
2315             hr = E_OUTOFMEMORY;
2316     }
2317     else
2318         hr = WINCODEC_ERR_WRONGSTATE;
2319 
2320     LeaveCriticalSection(&This->lock);
2321 
2322     return hr;
2323 
2324 }
2325 
2326 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
2327 {
2328     GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2329     HRESULT hr;
2330 
2331     TRACE("%p\n", iface);
2332 
2333     EnterCriticalSection(&This->lock);
2334 
2335     if (This->initialized && !This->committed)
2336     {
2337         char gif_trailer = 0x3b;
2338 
2339         /* FIXME: write text, comment GIF extensions */
2340 
2341         hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
2342         if (hr == S_OK)
2343             This->committed = TRUE;
2344     }
2345     else
2346         hr = WINCODEC_ERR_WRONGSTATE;
2347 
2348     LeaveCriticalSection(&This->lock);
2349     return hr;
2350 }
2351 
2352 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
2353 {
2354     FIXME("%p,%p: stub\n", iface, writer);
2355     return E_NOTIMPL;
2356 }
2357 
2358 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
2359 {
2360     GifEncoder_QueryInterface,
2361     GifEncoder_AddRef,
2362     GifEncoder_Release,
2363     GifEncoder_Initialize,
2364     GifEncoder_GetContainerFormat,
2365     GifEncoder_GetEncoderInfo,
2366     GifEncoder_SetColorContexts,
2367     GifEncoder_SetPalette,
2368     GifEncoder_SetThumbnail,
2369     GifEncoder_SetPreview,
2370     GifEncoder_CreateNewFrame,
2371     GifEncoder_Commit,
2372     GifEncoder_GetMetadataQueryWriter
2373 };
2374 
2375 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
2376 {
2377     GifEncoder *This;
2378     HRESULT ret;
2379 
2380     TRACE("%s,%p\n", debugstr_guid(iid), ppv);
2381 
2382     *ppv = NULL;
2383 
2384     This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2385     if (!This) return E_OUTOFMEMORY;
2386 
2387     This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
2388     This->ref = 1;
2389     This->stream = NULL;
2390     InitializeCriticalSection(&This->lock);
2391     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
2392     This->initialized = FALSE;
2393     This->info_written = FALSE;
2394     This->committed = FALSE;
2395     This->n_frames = 0;
2396     This->colors = 0;
2397 
2398     ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2399     IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2400 
2401     return ret;
2402 }
2403