[SHELL32] CDrivesFolder: Implement the eject and disconnect menu items. CORE-13841
[reactos.git] / dll / win32 / windowscodecs / gifformat.c
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 }