[WINDOWSCODECS] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / reactos / dll / win32 / windowscodecs / gifformat.c
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012 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 static LPWSTR strdupAtoW(const char *src)
27 {
28 int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
29 LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
30 if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
31 return dst;
32 }
33
34 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
35 MetadataItem **items, DWORD *count)
36 {
37 #include "pshpack1.h"
38 struct logical_screen_descriptor
39 {
40 char signature[6];
41 USHORT width;
42 USHORT height;
43 BYTE packed;
44 /* global_color_table_flag : 1;
45 * color_resolution : 3;
46 * sort_flag : 1;
47 * global_color_table_size : 3;
48 */
49 BYTE background_color_index;
50 BYTE pixel_aspect_ratio;
51 } lsd_data;
52 #include "poppack.h"
53 HRESULT hr;
54 ULONG bytesread, i;
55 MetadataItem *result;
56
57 *items = NULL;
58 *count = 0;
59
60 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
61 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
62
63 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9);
64 if (!result) return E_OUTOFMEMORY;
65
66 for (i = 0; i < 9; i++)
67 {
68 PropVariantInit(&result[i].schema);
69 PropVariantInit(&result[i].id);
70 PropVariantInit(&result[i].value);
71 }
72
73 result[0].id.vt = VT_LPWSTR;
74 result[0].id.u.pwszVal = strdupAtoW("Signature");
75 result[0].value.vt = VT_UI1|VT_VECTOR;
76 result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
77 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
78 memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
79
80 result[1].id.vt = VT_LPWSTR;
81 result[1].id.u.pwszVal = strdupAtoW("Width");
82 result[1].value.vt = VT_UI2;
83 result[1].value.u.uiVal = lsd_data.width;
84
85 result[2].id.vt = VT_LPWSTR;
86 result[2].id.u.pwszVal = strdupAtoW("Height");
87 result[2].value.vt = VT_UI2;
88 result[2].value.u.uiVal = lsd_data.height;
89
90 result[3].id.vt = VT_LPWSTR;
91 result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
92 result[3].value.vt = VT_BOOL;
93 result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;
94
95 result[4].id.vt = VT_LPWSTR;
96 result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
97 result[4].value.vt = VT_UI1;
98 result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;
99
100 result[5].id.vt = VT_LPWSTR;
101 result[5].id.u.pwszVal = strdupAtoW("SortFlag");
102 result[5].value.vt = VT_BOOL;
103 result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;
104
105 result[6].id.vt = VT_LPWSTR;
106 result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
107 result[6].value.vt = VT_UI1;
108 result[6].value.u.bVal = lsd_data.packed & 7;
109
110 result[7].id.vt = VT_LPWSTR;
111 result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
112 result[7].value.vt = VT_UI1;
113 result[7].value.u.bVal = lsd_data.background_color_index;
114
115 result[8].id.vt = VT_LPWSTR;
116 result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
117 result[8].value.vt = VT_UI1;
118 result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;
119
120 *items = result;
121 *count = 9;
122
123 return S_OK;
124 }
125
126 static const MetadataHandlerVtbl LSDReader_Vtbl = {
127 0,
128 &CLSID_WICLSDMetadataReader,
129 load_LSD_metadata
130 };
131
132 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
133 {
134 return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
135 }
136
137 #include "pshpack1.h"
138 struct image_descriptor
139 {
140 USHORT left;
141 USHORT top;
142 USHORT width;
143 USHORT height;
144 BYTE packed;
145 /* local_color_table_flag : 1;
146 * interlace_flag : 1;
147 * sort_flag : 1;
148 * reserved : 2;
149 * local_color_table_size : 3;
150 */
151 };
152 #include "poppack.h"
153
154 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
155 MetadataItem **items, DWORD *count)
156 {
157 struct image_descriptor imd_data;
158 HRESULT hr;
159 ULONG bytesread, i;
160 MetadataItem *result;
161
162 *items = NULL;
163 *count = 0;
164
165 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
166 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
167
168 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8);
169 if (!result) return E_OUTOFMEMORY;
170
171 for (i = 0; i < 8; i++)
172 {
173 PropVariantInit(&result[i].schema);
174 PropVariantInit(&result[i].id);
175 PropVariantInit(&result[i].value);
176 }
177
178 result[0].id.vt = VT_LPWSTR;
179 result[0].id.u.pwszVal = strdupAtoW("Left");
180 result[0].value.vt = VT_UI2;
181 result[0].value.u.uiVal = imd_data.left;
182
183 result[1].id.vt = VT_LPWSTR;
184 result[1].id.u.pwszVal = strdupAtoW("Top");
185 result[1].value.vt = VT_UI2;
186 result[1].value.u.uiVal = imd_data.top;
187
188 result[2].id.vt = VT_LPWSTR;
189 result[2].id.u.pwszVal = strdupAtoW("Width");
190 result[2].value.vt = VT_UI2;
191 result[2].value.u.uiVal = imd_data.width;
192
193 result[3].id.vt = VT_LPWSTR;
194 result[3].id.u.pwszVal = strdupAtoW("Height");
195 result[3].value.vt = VT_UI2;
196 result[3].value.u.uiVal = imd_data.height;
197
198 result[4].id.vt = VT_LPWSTR;
199 result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag");
200 result[4].value.vt = VT_BOOL;
201 result[4].value.u.boolVal = (imd_data.packed >> 7) & 1;
202
203 result[5].id.vt = VT_LPWSTR;
204 result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag");
205 result[5].value.vt = VT_BOOL;
206 result[5].value.u.boolVal = (imd_data.packed >> 6) & 1;
207
208 result[6].id.vt = VT_LPWSTR;
209 result[6].id.u.pwszVal = strdupAtoW("SortFlag");
210 result[6].value.vt = VT_BOOL;
211 result[6].value.u.boolVal = (imd_data.packed >> 5) & 1;
212
213 result[7].id.vt = VT_LPWSTR;
214 result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize");
215 result[7].value.vt = VT_UI1;
216 result[7].value.u.bVal = imd_data.packed & 7;
217
218 *items = result;
219 *count = 8;
220
221 return S_OK;
222 }
223
224 static const MetadataHandlerVtbl IMDReader_Vtbl = {
225 0,
226 &CLSID_WICIMDMetadataReader,
227 load_IMD_metadata
228 };
229
230 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv)
231 {
232 return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv);
233 }
234
235 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
236 MetadataItem **items, DWORD *count)
237 {
238 #include "pshpack1.h"
239 struct graphic_control_extenstion
240 {
241 BYTE packed;
242 /* reservred: 3;
243 * disposal : 3;
244 * user_input_flag : 1;
245 * transparency_flag : 1;
246 */
247 USHORT delay;
248 BYTE transparent_color_index;
249 } gce_data;
250 #include "poppack.h"
251 HRESULT hr;
252 ULONG bytesread, i;
253 MetadataItem *result;
254
255 *items = NULL;
256 *count = 0;
257
258 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
259 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
260
261 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5);
262 if (!result) return E_OUTOFMEMORY;
263
264 for (i = 0; i < 5; i++)
265 {
266 PropVariantInit(&result[i].schema);
267 PropVariantInit(&result[i].id);
268 PropVariantInit(&result[i].value);
269 }
270
271 result[0].id.vt = VT_LPWSTR;
272 result[0].id.u.pwszVal = strdupAtoW("Disposal");
273 result[0].value.vt = VT_UI1;
274 result[0].value.u.bVal = (gce_data.packed >> 2) & 7;
275
276 result[1].id.vt = VT_LPWSTR;
277 result[1].id.u.pwszVal = strdupAtoW("UserInputFlag");
278 result[1].value.vt = VT_BOOL;
279 result[1].value.u.boolVal = (gce_data.packed >> 1) & 1;
280
281 result[2].id.vt = VT_LPWSTR;
282 result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag");
283 result[2].value.vt = VT_BOOL;
284 result[2].value.u.boolVal = gce_data.packed & 1;
285
286 result[3].id.vt = VT_LPWSTR;
287 result[3].id.u.pwszVal = strdupAtoW("Delay");
288 result[3].value.vt = VT_UI2;
289 result[3].value.u.uiVal = gce_data.delay;
290
291 result[4].id.vt = VT_LPWSTR;
292 result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex");
293 result[4].value.vt = VT_UI1;
294 result[4].value.u.bVal = gce_data.transparent_color_index;
295
296 *items = result;
297 *count = 5;
298
299 return S_OK;
300 }
301
302 static const MetadataHandlerVtbl GCEReader_Vtbl = {
303 0,
304 &CLSID_WICGCEMetadataReader,
305 load_GCE_metadata
306 };
307
308 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv)
309 {
310 return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv);
311 }
312
313 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
314 MetadataItem **items, DWORD *count)
315 {
316 #include "pshpack1.h"
317 struct application_extenstion
318 {
319 BYTE extension_introducer;
320 BYTE extension_label;
321 BYTE block_size;
322 BYTE application[11];
323 } ape_data;
324 #include "poppack.h"
325 HRESULT hr;
326 ULONG bytesread, data_size, i;
327 MetadataItem *result;
328 BYTE subblock_size;
329 BYTE *data;
330
331 *items = NULL;
332 *count = 0;
333
334 hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
335 if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
336 if (ape_data.extension_introducer != 0x21 ||
337 ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
338 ape_data.block_size != 11)
339 return S_OK;
340
341 data = NULL;
342 data_size = 0;
343
344 for (;;)
345 {
346 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
347 if (FAILED(hr) || bytesread != sizeof(subblock_size))
348 {
349 HeapFree(GetProcessHeap(), 0, data);
350 return S_OK;
351 }
352 if (!subblock_size) break;
353
354 if (!data)
355 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
356 else
357 {
358 BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
359 if (!new_data)
360 {
361 HeapFree(GetProcessHeap(), 0, data);
362 return S_OK;
363 }
364 data = new_data;
365 }
366 data[data_size] = subblock_size;
367 hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
368 if (FAILED(hr) || bytesread != subblock_size)
369 {
370 HeapFree(GetProcessHeap(), 0, data);
371 return S_OK;
372 }
373 data_size += subblock_size + 1;
374 }
375
376 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2);
377 if (!result)
378 {
379 HeapFree(GetProcessHeap(), 0, data);
380 return E_OUTOFMEMORY;
381 }
382
383 for (i = 0; i < 2; i++)
384 {
385 PropVariantInit(&result[i].schema);
386 PropVariantInit(&result[i].id);
387 PropVariantInit(&result[i].value);
388 }
389
390 result[0].id.vt = VT_LPWSTR;
391 result[0].id.u.pwszVal = strdupAtoW("Application");
392 result[0].value.vt = VT_UI1|VT_VECTOR;
393 result[0].value.u.caub.cElems = sizeof(ape_data.application);
394 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application));
395 memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application));
396
397 result[1].id.vt = VT_LPWSTR;
398 result[1].id.u.pwszVal = strdupAtoW("Data");
399 result[1].value.vt = VT_UI1|VT_VECTOR;
400 result[1].value.u.caub.cElems = data_size;
401 result[1].value.u.caub.pElems = data;
402
403 *items = result;
404 *count = 2;
405
406 return S_OK;
407 }
408
409 static const MetadataHandlerVtbl APEReader_Vtbl = {
410 0,
411 &CLSID_WICAPEMetadataReader,
412 load_APE_metadata
413 };
414
415 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv)
416 {
417 return MetadataReader_Create(&APEReader_Vtbl, iid, ppv);
418 }
419
420 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
421 MetadataItem **items, DWORD *count)
422 {
423 #include "pshpack1.h"
424 struct gif_extenstion
425 {
426 BYTE extension_introducer;
427 BYTE extension_label;
428 } ext_data;
429 #include "poppack.h"
430 HRESULT hr;
431 ULONG bytesread, data_size;
432 MetadataItem *result;
433 BYTE subblock_size;
434 char *data;
435
436 *items = NULL;
437 *count = 0;
438
439 hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
440 if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
441 if (ext_data.extension_introducer != 0x21 ||
442 ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
443 return S_OK;
444
445 data = NULL;
446 data_size = 0;
447
448 for (;;)
449 {
450 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
451 if (FAILED(hr) || bytesread != sizeof(subblock_size))
452 {
453 HeapFree(GetProcessHeap(), 0, data);
454 return S_OK;
455 }
456 if (!subblock_size) break;
457
458 if (!data)
459 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
460 else
461 {
462 char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
463 if (!new_data)
464 {
465 HeapFree(GetProcessHeap(), 0, data);
466 return S_OK;
467 }
468 data = new_data;
469 }
470 hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
471 if (FAILED(hr) || bytesread != subblock_size)
472 {
473 HeapFree(GetProcessHeap(), 0, data);
474 return S_OK;
475 }
476 data_size += subblock_size;
477 }
478
479 data[data_size] = 0;
480
481 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem));
482 if (!result)
483 {
484 HeapFree(GetProcessHeap(), 0, data);
485 return E_OUTOFMEMORY;
486 }
487
488 PropVariantInit(&result->schema);
489 PropVariantInit(&result->id);
490 PropVariantInit(&result->value);
491
492 result->id.vt = VT_LPWSTR;
493 result->id.u.pwszVal = strdupAtoW("TextEntry");
494 result->value.vt = VT_LPSTR;
495 result->value.u.pszVal = data;
496
497 *items = result;
498 *count = 1;
499
500 return S_OK;
501 }
502
503 static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
504 0,
505 &CLSID_WICGifCommentMetadataReader,
506 load_GifComment_metadata
507 };
508
509 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv)
510 {
511 return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv);
512 }
513
514 static IStream *create_stream(const void *data, int data_size)
515 {
516 HRESULT hr;
517 IStream *stream;
518 HGLOBAL hdata;
519 void *locked_data;
520
521 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
522 if (!hdata) return NULL;
523
524 locked_data = GlobalLock(hdata);
525 memcpy(locked_data, data, data_size);
526 GlobalUnlock(hdata);
527
528 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
529 return FAILED(hr) ? NULL : stream;
530 }
531
532 static HRESULT create_metadata_reader(const void *data, int data_size,
533 class_constructor constructor,
534 IWICMetadataReader **reader)
535 {
536 HRESULT hr;
537 IWICMetadataReader *metadata_reader;
538 IWICPersistStream *persist;
539 IStream *stream;
540
541 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
542
543 hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader);
544 if (FAILED(hr)) return hr;
545
546 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
547 if (FAILED(hr))
548 {
549 IWICMetadataReader_Release(metadata_reader);
550 return hr;
551 }
552
553 stream = create_stream(data, data_size);
554 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
555 IStream_Release(stream);
556
557 IWICPersistStream_Release(persist);
558
559 *reader = metadata_reader;
560 return S_OK;
561 }
562
563 typedef struct {
564 IWICBitmapDecoder IWICBitmapDecoder_iface;
565 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
566 IStream *stream;
567 BYTE LSD_data[13]; /* Logical Screen Descriptor */
568 LONG ref;
569 BOOL initialized;
570 GifFileType *gif;
571 UINT current_frame;
572 CRITICAL_SECTION lock;
573 } GifDecoder;
574
575 typedef struct {
576 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
577 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
578 LONG ref;
579 SavedImage *frame;
580 GifDecoder *parent;
581 } GifFrameDecode;
582
583 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
584 {
585 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
586 }
587
588 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
589 {
590 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
591 }
592
593 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
594 {
595 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
596 }
597
598 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
599 {
600 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
601 }
602
603 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
604 void **ppv)
605 {
606 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
607 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
608
609 if (!ppv) return E_INVALIDARG;
610
611 if (IsEqualIID(&IID_IUnknown, iid) ||
612 IsEqualIID(&IID_IWICBitmapSource, iid) ||
613 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
614 {
615 *ppv = &This->IWICBitmapFrameDecode_iface;
616 }
617 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
618 {
619 *ppv = &This->IWICMetadataBlockReader_iface;
620 }
621 else
622 {
623 *ppv = NULL;
624 return E_NOINTERFACE;
625 }
626
627 IUnknown_AddRef((IUnknown*)*ppv);
628 return S_OK;
629 }
630
631 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
632 {
633 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
634 ULONG ref = InterlockedIncrement(&This->ref);
635
636 TRACE("(%p) refcount=%u\n", iface, ref);
637
638 return ref;
639 }
640
641 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
642 {
643 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
644 ULONG ref = InterlockedDecrement(&This->ref);
645
646 TRACE("(%p) refcount=%u\n", iface, ref);
647
648 if (ref == 0)
649 {
650 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
651 HeapFree(GetProcessHeap(), 0, This);
652 }
653
654 return ref;
655 }
656
657 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
658 UINT *puiWidth, UINT *puiHeight)
659 {
660 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
661 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
662
663 *puiWidth = This->frame->ImageDesc.Width;
664 *puiHeight = This->frame->ImageDesc.Height;
665
666 return S_OK;
667 }
668
669 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
670 WICPixelFormatGUID *pPixelFormat)
671 {
672 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
673
674 return S_OK;
675 }
676
677 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
678 double *pDpiX, double *pDpiY)
679 {
680 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
681 const GifWord aspect_word = This->parent->gif->SAspectRatio;
682 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
683 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
684
685 *pDpiX = 96.0 / aspect;
686 *pDpiY = 96.0;
687
688 return S_OK;
689 }
690
691 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
692 IWICPalette *pIPalette)
693 {
694 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
695 WICColor colors[256];
696 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
697 int i, trans;
698 ExtensionBlock *eb;
699 TRACE("(%p,%p)\n", iface, pIPalette);
700
701 if (!cm) cm = This->parent->gif->SColorMap;
702
703 if (cm->ColorCount > 256)
704 {
705 ERR("GIF contains %i colors???\n", cm->ColorCount);
706 return E_FAIL;
707 }
708
709 for (i = 0; i < cm->ColorCount; i++) {
710 colors[i] = 0xff000000| /* alpha */
711 cm->Colors[i].Red << 16|
712 cm->Colors[i].Green << 8|
713 cm->Colors[i].Blue;
714 }
715
716 /* look for the transparent color extension */
717 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) {
718 eb = This->frame->Extensions.ExtensionBlocks + i;
719 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) {
720 if (eb->Bytes[3] & 1) {
721 trans = (unsigned char)eb->Bytes[6];
722 colors[trans] &= 0xffffff; /* set alpha to 0 */
723 break;
724 }
725 }
726 }
727
728 return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
729 }
730
731 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
732 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
733 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
734 {
735 UINT row_offset; /* number of bytes into the source rows where the data starts */
736 const BYTE *src;
737 BYTE *dst;
738 UINT y;
739 WICRect rect;
740
741 if (!rc)
742 {
743 rect.X = 0;
744 rect.Y = 0;
745 rect.Width = srcwidth;
746 rect.Height = srcheight;
747 rc = &rect;
748 }
749 else
750 {
751 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
752 return E_INVALIDARG;
753 }
754
755 if (dststride < rc->Width)
756 return E_INVALIDARG;
757
758 if ((dststride * rc->Height) > dstbuffersize)
759 return E_INVALIDARG;
760
761 row_offset = rc->X;
762
763 dst = dstbuffer;
764 for (y=rc->Y; y-rc->Y < rc->Height; y++)
765 {
766 if (y%8 == 0)
767 src = srcbuffer + srcstride * (y/8);
768 else if (y%4 == 0)
769 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
770 else if (y%2 == 0)
771 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
772 else /* y%2 == 1 */
773 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
774 src += row_offset;
775 memcpy(dst, src, rc->Width);
776 dst += dststride;
777 }
778 return S_OK;
779 }
780
781 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
782 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
783 {
784 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
785 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
786
787 if (This->frame->ImageDesc.Interlace)
788 {
789 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
790 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
791 prc, cbStride, cbBufferSize, pbBuffer);
792 }
793 else
794 {
795 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
796 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
797 prc, cbStride, cbBufferSize, pbBuffer);
798 }
799 }
800
801 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
802 IWICMetadataQueryReader **ppIMetadataQueryReader)
803 {
804 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
805 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
806 }
807
808 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
809 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
810 {
811 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
812 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
813 }
814
815 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
816 IWICBitmapSource **ppIThumbnail)
817 {
818 TRACE("(%p,%p)\n", iface, ppIThumbnail);
819 return WINCODEC_ERR_CODECNOTHUMBNAIL;
820 }
821
822 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
823 GifFrameDecode_QueryInterface,
824 GifFrameDecode_AddRef,
825 GifFrameDecode_Release,
826 GifFrameDecode_GetSize,
827 GifFrameDecode_GetPixelFormat,
828 GifFrameDecode_GetResolution,
829 GifFrameDecode_CopyPalette,
830 GifFrameDecode_CopyPixels,
831 GifFrameDecode_GetMetadataQueryReader,
832 GifFrameDecode_GetColorContexts,
833 GifFrameDecode_GetThumbnail
834 };
835
836 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
837 REFIID iid, void **ppv)
838 {
839 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
840 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
841 }
842
843 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
844 {
845 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
846 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
847 }
848
849 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
850 {
851 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
852 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
853 }
854
855 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
856 GUID *guid)
857 {
858 TRACE("(%p,%p)\n", iface, guid);
859
860 if (!guid) return E_INVALIDARG;
861
862 *guid = GUID_ContainerFormatGif;
863 return S_OK;
864 }
865
866 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
867 UINT *count)
868 {
869 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
870
871 TRACE("%p,%p\n", iface, count);
872
873 if (!count) return E_INVALIDARG;
874
875 *count = This->frame->Extensions.ExtensionBlockCount + 1;
876 return S_OK;
877 }
878
879 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
880 {
881 HRESULT hr;
882 IWICMetadataReader *metadata_reader;
883 IWICPersistStream *persist;
884 IStream *stream;
885 struct image_descriptor IMD_data;
886
887 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
888
889 hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader);
890 if (FAILED(hr)) return hr;
891
892 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
893 if (FAILED(hr))
894 {
895 IWICMetadataReader_Release(metadata_reader);
896 return hr;
897 }
898
899 /* recreate IMD structure from GIF decoder data */
900 IMD_data.left = This->frame->ImageDesc.Left;
901 IMD_data.top = This->frame->ImageDesc.Top;
902 IMD_data.width = This->frame->ImageDesc.Width;
903 IMD_data.height = This->frame->ImageDesc.Height;
904 IMD_data.packed = 0;
905 /* interlace_flag */
906 IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0;
907 if (This->frame->ImageDesc.ColorMap)
908 {
909 /* local_color_table_flag */
910 IMD_data.packed |= 1 << 7;
911 /* local_color_table_size */
912 IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1;
913 /* sort_flag */
914 IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
915 }
916
917 stream = create_stream(&IMD_data, sizeof(IMD_data));
918 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
919 IStream_Release(stream);
920
921 IWICPersistStream_Release(persist);
922
923 *reader = metadata_reader;
924 return S_OK;
925 }
926
927 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
928 UINT index, IWICMetadataReader **reader)
929 {
930 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
931 int i, gce_index = -1, gce_skipped = 0;
932
933 TRACE("(%p,%u,%p)\n", iface, index, reader);
934
935 if (!reader) return E_INVALIDARG;
936
937 if (index == 0)
938 return create_IMD_metadata_reader(This, reader);
939
940 if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
941 return E_INVALIDARG;
942
943 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++)
944 {
945 class_constructor constructor;
946 const void *data;
947 int data_size;
948
949 if (index != i + 1 - gce_skipped) continue;
950
951 if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE)
952 {
953 gce_index = i;
954 gce_skipped = 1;
955 continue;
956 }
957 else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
958 {
959 constructor = GifCommentReader_CreateInstance;
960 data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
961 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
962 }
963 else
964 {
965 constructor = UnknownMetadataReader_CreateInstance;
966 data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
967 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
968 }
969 return create_metadata_reader(data, data_size, constructor, reader);
970 }
971
972 if (gce_index == -1) return E_INVALIDARG;
973
974 return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3,
975 This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4,
976 GCEReader_CreateInstance, reader);
977 }
978
979 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
980 IEnumUnknown **enumerator)
981 {
982 FIXME("(%p,%p): stub\n", iface, enumerator);
983 return E_NOTIMPL;
984 }
985
986 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl =
987 {
988 GifFrameDecode_Block_QueryInterface,
989 GifFrameDecode_Block_AddRef,
990 GifFrameDecode_Block_Release,
991 GifFrameDecode_Block_GetContainerFormat,
992 GifFrameDecode_Block_GetCount,
993 GifFrameDecode_Block_GetReaderByIndex,
994 GifFrameDecode_Block_GetEnumerator
995 };
996
997 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
998 void **ppv)
999 {
1000 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1001 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1002
1003 if (!ppv) return E_INVALIDARG;
1004
1005 if (IsEqualIID(&IID_IUnknown, iid) ||
1006 IsEqualIID(&IID_IWICBitmapDecoder, iid))
1007 {
1008 *ppv = &This->IWICBitmapDecoder_iface;
1009 }
1010 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
1011 {
1012 *ppv = &This->IWICMetadataBlockReader_iface;
1013 }
1014 else
1015 {
1016 *ppv = NULL;
1017 return E_NOINTERFACE;
1018 }
1019
1020 IUnknown_AddRef((IUnknown*)*ppv);
1021 return S_OK;
1022 }
1023
1024 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
1025 {
1026 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1027 ULONG ref = InterlockedIncrement(&This->ref);
1028
1029 TRACE("(%p) refcount=%u\n", iface, ref);
1030
1031 return ref;
1032 }
1033
1034 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
1035 {
1036 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1037 ULONG ref = InterlockedDecrement(&This->ref);
1038
1039 TRACE("(%p) refcount=%u\n", iface, ref);
1040
1041 if (ref == 0)
1042 {
1043 if (This->stream)
1044 {
1045 IStream_Release(This->stream);
1046 DGifCloseFile(This->gif);
1047 }
1048 This->lock.DebugInfo->Spare[0] = 0;
1049 DeleteCriticalSection(&This->lock);
1050 HeapFree(GetProcessHeap(), 0, This);
1051 }
1052
1053 return ref;
1054 }
1055
1056 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1057 DWORD *capability)
1058 {
1059 HRESULT hr;
1060
1061 TRACE("(%p,%p,%p)\n", iface, stream, capability);
1062
1063 if (!stream || !capability) return E_INVALIDARG;
1064
1065 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1066 if (hr != S_OK) return hr;
1067
1068 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
1069 WICBitmapDecoderCapabilityCanDecodeSomeImages |
1070 WICBitmapDecoderCapabilityCanEnumerateMetadata;
1071 return S_OK;
1072 }
1073
1074 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1075 IStream *stream = gif->UserData;
1076 ULONG bytesread;
1077 HRESULT hr;
1078
1079 if (!stream)
1080 {
1081 ERR("attempting to read file after initialization\n");
1082 return 0;
1083 }
1084
1085 hr = IStream_Read(stream, data, len, &bytesread);
1086 if (FAILED(hr)) bytesread = 0;
1087 return bytesread;
1088 }
1089
1090 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1091 WICDecodeOptions cacheOptions)
1092 {
1093 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1094 LARGE_INTEGER seek;
1095 int ret;
1096
1097 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1098
1099 EnterCriticalSection(&This->lock);
1100
1101 if (This->initialized || This->gif)
1102 {
1103 WARN("already initialized\n");
1104 LeaveCriticalSection(&This->lock);
1105 return WINCODEC_ERR_WRONGSTATE;
1106 }
1107
1108 /* seek to start of stream */
1109 seek.QuadPart = 0;
1110 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1111
1112 /* read all data from the stream */
1113 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1114 if (!This->gif)
1115 {
1116 LeaveCriticalSection(&This->lock);
1117 return E_FAIL;
1118 }
1119
1120 ret = DGifSlurp(This->gif);
1121 if (ret == GIF_ERROR)
1122 {
1123 LeaveCriticalSection(&This->lock);
1124 return E_FAIL;
1125 }
1126
1127 /* make sure we don't use the stream after this method returns */
1128 This->gif->UserData = NULL;
1129
1130 seek.QuadPart = 0;
1131 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1132 IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL);
1133
1134 This->stream = pIStream;
1135 IStream_AddRef(This->stream);
1136
1137 This->initialized = TRUE;
1138
1139 LeaveCriticalSection(&This->lock);
1140
1141 return S_OK;
1142 }
1143
1144 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1145 GUID *pguidContainerFormat)
1146 {
1147 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1148 return S_OK;
1149 }
1150
1151 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1152 IWICBitmapDecoderInfo **ppIDecoderInfo)
1153 {
1154 HRESULT hr;
1155 IWICComponentInfo *compinfo;
1156
1157 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1158
1159 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
1160 if (FAILED(hr)) return hr;
1161
1162 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
1163 (void**)ppIDecoderInfo);
1164
1165 IWICComponentInfo_Release(compinfo);
1166
1167 return hr;
1168 }
1169
1170 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1171 {
1172 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1173 WICColor colors[256];
1174 ColorMapObject *cm;
1175 int i, trans, count;
1176 ExtensionBlock *eb;
1177
1178 TRACE("(%p,%p)\n", iface, palette);
1179
1180 cm = This->gif->SColorMap;
1181 if (cm)
1182 {
1183 if (cm->ColorCount > 256)
1184 {
1185 ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
1186 return E_FAIL;
1187 }
1188
1189 for (i = 0; i < cm->ColorCount; i++)
1190 {
1191 colors[i] = 0xff000000 | /* alpha */
1192 cm->Colors[i].Red << 16 |
1193 cm->Colors[i].Green << 8 |
1194 cm->Colors[i].Blue;
1195 }
1196
1197 count = cm->ColorCount;
1198 }
1199 else
1200 {
1201 colors[0] = 0xff000000;
1202 colors[1] = 0xffffffff;
1203
1204 for (i = 2; i < 256; i++)
1205 colors[i] = 0xff000000;
1206
1207 count = 256;
1208 }
1209
1210 /* look for the transparent color extension */
1211 for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
1212 {
1213 eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
1214 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
1215 {
1216 if (eb->Bytes[3] & 1)
1217 {
1218 trans = (unsigned char)eb->Bytes[6];
1219 colors[trans] &= 0xffffff; /* set alpha to 0 */
1220 break;
1221 }
1222 }
1223 }
1224
1225 return IWICPalette_InitializeCustom(palette, colors, count);
1226 }
1227
1228 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1229 IWICMetadataQueryReader **ppIMetadataQueryReader)
1230 {
1231 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1232 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1233 }
1234
1235 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1236 IWICBitmapSource **ppIBitmapSource)
1237 {
1238 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1239 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1240 }
1241
1242 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1243 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1244 {
1245 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1246 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1247 }
1248
1249 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1250 IWICBitmapSource **ppIThumbnail)
1251 {
1252 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1253 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1254 }
1255
1256 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1257 UINT *pCount)
1258 {
1259 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1260
1261 if (!pCount) return E_INVALIDARG;
1262
1263 EnterCriticalSection(&This->lock);
1264 *pCount = This->gif ? This->gif->ImageCount : 0;
1265 LeaveCriticalSection(&This->lock);
1266
1267 TRACE("(%p) <-- %d\n", iface, *pCount);
1268
1269 return S_OK;
1270 }
1271
1272 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1273 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1274 {
1275 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1276 GifFrameDecode *result;
1277 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1278
1279 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1280
1281 if (index >= This->gif->ImageCount) return E_INVALIDARG;
1282
1283 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1284 if (!result) return E_OUTOFMEMORY;
1285
1286 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1287 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1288 result->ref = 1;
1289 result->frame = &This->gif->SavedImages[index];
1290 IWICBitmapDecoder_AddRef(iface);
1291 result->parent = This;
1292 This->current_frame = index;
1293
1294 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1295
1296 return S_OK;
1297 }
1298
1299 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1300 GifDecoder_QueryInterface,
1301 GifDecoder_AddRef,
1302 GifDecoder_Release,
1303 GifDecoder_QueryCapability,
1304 GifDecoder_Initialize,
1305 GifDecoder_GetContainerFormat,
1306 GifDecoder_GetDecoderInfo,
1307 GifDecoder_CopyPalette,
1308 GifDecoder_GetMetadataQueryReader,
1309 GifDecoder_GetPreview,
1310 GifDecoder_GetColorContexts,
1311 GifDecoder_GetThumbnail,
1312 GifDecoder_GetFrameCount,
1313 GifDecoder_GetFrame
1314 };
1315
1316 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1317 REFIID iid, void **ppv)
1318 {
1319 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1320 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1321 }
1322
1323 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1324 {
1325 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1326 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1327 }
1328
1329 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1330 {
1331 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1332 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1333 }
1334
1335 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1336 GUID *guid)
1337 {
1338 TRACE("(%p,%p)\n", iface, guid);
1339
1340 if (!guid) return E_INVALIDARG;
1341
1342 *guid = GUID_ContainerFormatGif;
1343 return S_OK;
1344 }
1345
1346 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1347 UINT *count)
1348 {
1349 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1350
1351 TRACE("%p,%p\n", iface, count);
1352
1353 if (!count) return E_INVALIDARG;
1354
1355 *count = This->gif->Extensions.ExtensionBlockCount + 1;
1356 return S_OK;
1357 }
1358
1359 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1360 UINT index, IWICMetadataReader **reader)
1361 {
1362 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1363 int i;
1364
1365 TRACE("(%p,%u,%p)\n", iface, index, reader);
1366
1367 if (!reader) return E_INVALIDARG;
1368
1369 if (index == 0)
1370 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1371 LSDReader_CreateInstance, reader);
1372
1373 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1374 {
1375 class_constructor constructor;
1376
1377 if (index != i + 1) continue;
1378
1379 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1380 constructor = APEReader_CreateInstance;
1381 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1382 constructor = GifCommentReader_CreateInstance;
1383 else
1384 constructor = UnknownMetadataReader_CreateInstance;
1385
1386 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1387 This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1388 constructor, reader);
1389 }
1390
1391 return E_INVALIDARG;
1392 }
1393
1394 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1395 IEnumUnknown **enumerator)
1396 {
1397 FIXME("(%p,%p): stub\n", iface, enumerator);
1398 return E_NOTIMPL;
1399 }
1400
1401 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1402 {
1403 GifDecoder_Block_QueryInterface,
1404 GifDecoder_Block_AddRef,
1405 GifDecoder_Block_Release,
1406 GifDecoder_Block_GetContainerFormat,
1407 GifDecoder_Block_GetCount,
1408 GifDecoder_Block_GetReaderByIndex,
1409 GifDecoder_Block_GetEnumerator
1410 };
1411
1412 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
1413 {
1414 GifDecoder *This;
1415 HRESULT ret;
1416
1417 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1418
1419 *ppv = NULL;
1420
1421 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1422 if (!This) return E_OUTOFMEMORY;
1423
1424 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1425 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1426 This->stream = NULL;
1427 This->ref = 1;
1428 This->initialized = FALSE;
1429 This->gif = NULL;
1430 This->current_frame = 0;
1431 InitializeCriticalSection(&This->lock);
1432 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1433
1434 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1435 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1436
1437 return ret;
1438 }