* Sync up to trunk HEAD (r62286).
[reactos.git] / 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(), 0, 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(IUnknown *pUnkOuter, REFIID iid, void **ppv)
133 {
134 return MetadataReader_Create(&LSDReader_Vtbl, pUnkOuter, 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(), 0, 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(IUnknown *pUnkOuter, REFIID iid, void **ppv)
231 {
232 return MetadataReader_Create(&IMDReader_Vtbl, pUnkOuter, 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(), 0, 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(IUnknown *pUnkOuter, REFIID iid, void **ppv)
309 {
310 return MetadataReader_Create(&GCEReader_Vtbl, pUnkOuter, 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(), 0, 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(IUnknown *pUnkOuter, REFIID iid, void **ppv)
416 {
417 return MetadataReader_Create(&APEReader_Vtbl, pUnkOuter, 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(), 0, 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(IUnknown *pUnkOuter, REFIID iid, void **ppv)
510 {
511 return MetadataReader_Create(&GifCommentReader_Vtbl, pUnkOuter, 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 const CLSID *clsid, IWICMetadataReader **reader)
534 {
535 HRESULT hr;
536 IWICMetadataReader *metadata_reader;
537 IWICPersistStream *persist;
538 IStream *stream;
539
540 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
541
542 hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER,
543 &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 BYTE LSD_data[13]; /* Logical Screen Descriptor */
567 LONG ref;
568 BOOL initialized;
569 GifFileType *gif;
570 UINT current_frame;
571 CRITICAL_SECTION lock;
572 } GifDecoder;
573
574 typedef struct {
575 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
576 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
577 LONG ref;
578 SavedImage *frame;
579 GifDecoder *parent;
580 } GifFrameDecode;
581
582 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
583 {
584 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
585 }
586
587 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
588 {
589 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
590 }
591
592 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
593 {
594 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
595 }
596
597 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
598 {
599 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
600 }
601
602 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
603 void **ppv)
604 {
605 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
606 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
607
608 if (!ppv) return E_INVALIDARG;
609
610 if (IsEqualIID(&IID_IUnknown, iid) ||
611 IsEqualIID(&IID_IWICBitmapSource, iid) ||
612 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
613 {
614 *ppv = &This->IWICBitmapFrameDecode_iface;
615 }
616 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
617 {
618 *ppv = &This->IWICMetadataBlockReader_iface;
619 }
620 else
621 {
622 *ppv = NULL;
623 return E_NOINTERFACE;
624 }
625
626 IUnknown_AddRef((IUnknown*)*ppv);
627 return S_OK;
628 }
629
630 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
631 {
632 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
633 ULONG ref = InterlockedIncrement(&This->ref);
634
635 TRACE("(%p) refcount=%u\n", iface, ref);
636
637 return ref;
638 }
639
640 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
641 {
642 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
643 ULONG ref = InterlockedDecrement(&This->ref);
644
645 TRACE("(%p) refcount=%u\n", iface, ref);
646
647 if (ref == 0)
648 {
649 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
650 HeapFree(GetProcessHeap(), 0, This);
651 }
652
653 return ref;
654 }
655
656 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
657 UINT *puiWidth, UINT *puiHeight)
658 {
659 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
660 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
661
662 *puiWidth = This->frame->ImageDesc.Width;
663 *puiHeight = This->frame->ImageDesc.Height;
664
665 return S_OK;
666 }
667
668 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
669 WICPixelFormatGUID *pPixelFormat)
670 {
671 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
672
673 return S_OK;
674 }
675
676 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
677 double *pDpiX, double *pDpiY)
678 {
679 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
680 const GifWord aspect_word = This->parent->gif->SAspectRatio;
681 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
682 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
683
684 *pDpiX = 96.0 / aspect;
685 *pDpiY = 96.0;
686
687 return S_OK;
688 }
689
690 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
691 IWICPalette *pIPalette)
692 {
693 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
694 WICColor colors[256];
695 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
696 int i, trans;
697 ExtensionBlock *eb;
698 TRACE("(%p,%p)\n", iface, pIPalette);
699
700 if (!cm) cm = This->parent->gif->SColorMap;
701
702 if (cm->ColorCount > 256)
703 {
704 ERR("GIF contains %i colors???\n", cm->ColorCount);
705 return E_FAIL;
706 }
707
708 for (i = 0; i < cm->ColorCount; i++) {
709 colors[i] = 0xff000000| /* alpha */
710 cm->Colors[i].Red << 16|
711 cm->Colors[i].Green << 8|
712 cm->Colors[i].Blue;
713 }
714
715 /* look for the transparent color extension */
716 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) {
717 eb = This->frame->Extensions.ExtensionBlocks + i;
718 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) {
719 if (eb->Bytes[3] & 1) {
720 trans = (unsigned char)eb->Bytes[6];
721 colors[trans] &= 0xffffff; /* set alpha to 0 */
722 break;
723 }
724 }
725 }
726
727 return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
728 }
729
730 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
731 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
732 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
733 {
734 UINT row_offset; /* number of bytes into the source rows where the data starts */
735 const BYTE *src;
736 BYTE *dst;
737 UINT y;
738 WICRect rect;
739
740 if (!rc)
741 {
742 rect.X = 0;
743 rect.Y = 0;
744 rect.Width = srcwidth;
745 rect.Height = srcheight;
746 rc = &rect;
747 }
748 else
749 {
750 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
751 return E_INVALIDARG;
752 }
753
754 if (dststride < rc->Width)
755 return E_INVALIDARG;
756
757 if ((dststride * rc->Height) > dstbuffersize)
758 return E_INVALIDARG;
759
760 row_offset = rc->X;
761
762 dst = dstbuffer;
763 for (y=rc->Y; y-rc->Y < rc->Height; y++)
764 {
765 if (y%8 == 0)
766 src = srcbuffer + srcstride * (y/8);
767 else if (y%4 == 0)
768 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
769 else if (y%2 == 0)
770 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
771 else /* y%2 == 1 */
772 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
773 src += row_offset;
774 memcpy(dst, src, rc->Width);
775 dst += dststride;
776 }
777 return S_OK;
778 }
779
780 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
781 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
782 {
783 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
784 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
785
786 if (This->frame->ImageDesc.Interlace)
787 {
788 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
789 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
790 prc, cbStride, cbBufferSize, pbBuffer);
791 }
792 else
793 {
794 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
795 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
796 prc, cbStride, cbBufferSize, pbBuffer);
797 }
798 }
799
800 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
801 IWICMetadataQueryReader **ppIMetadataQueryReader)
802 {
803 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
804 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
805 }
806
807 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
808 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
809 {
810 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
811 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
812 }
813
814 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
815 IWICBitmapSource **ppIThumbnail)
816 {
817 TRACE("(%p,%p)\n", iface, ppIThumbnail);
818 return WINCODEC_ERR_CODECNOTHUMBNAIL;
819 }
820
821 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
822 GifFrameDecode_QueryInterface,
823 GifFrameDecode_AddRef,
824 GifFrameDecode_Release,
825 GifFrameDecode_GetSize,
826 GifFrameDecode_GetPixelFormat,
827 GifFrameDecode_GetResolution,
828 GifFrameDecode_CopyPalette,
829 GifFrameDecode_CopyPixels,
830 GifFrameDecode_GetMetadataQueryReader,
831 GifFrameDecode_GetColorContexts,
832 GifFrameDecode_GetThumbnail
833 };
834
835 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
836 REFIID iid, void **ppv)
837 {
838 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
839 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
840 }
841
842 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
843 {
844 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
845 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
846 }
847
848 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
849 {
850 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
851 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
852 }
853
854 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
855 GUID *guid)
856 {
857 TRACE("(%p,%p)\n", iface, guid);
858
859 if (!guid) return E_INVALIDARG;
860
861 *guid = GUID_ContainerFormatGif;
862 return S_OK;
863 }
864
865 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
866 UINT *count)
867 {
868 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
869
870 TRACE("%p,%p\n", iface, count);
871
872 if (!count) return E_INVALIDARG;
873
874 *count = This->frame->Extensions.ExtensionBlockCount + 1;
875 return S_OK;
876 }
877
878 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
879 {
880 HRESULT hr;
881 IWICMetadataReader *metadata_reader;
882 IWICPersistStream *persist;
883 IStream *stream;
884 struct image_descriptor IMD_data;
885
886 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
887
888 hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
889 &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 const CLSID *clsid;
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 clsid = &CLSID_WICGifCommentMetadataReader;
960 data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
961 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
962 }
963 else
964 {
965 clsid = &CLSID_WICUnknownMetadataReader;
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, clsid, 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 &CLSID_WICGCEMetadataReader, 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 This->lock.DebugInfo->Spare[0] = 0;
1044 DeleteCriticalSection(&This->lock);
1045 DGifCloseFile(This->gif);
1046 HeapFree(GetProcessHeap(), 0, This);
1047 }
1048
1049 return ref;
1050 }
1051
1052 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1053 DWORD *capability)
1054 {
1055 HRESULT hr;
1056
1057 TRACE("(%p,%p,%p)\n", iface, stream, capability);
1058
1059 if (!stream || !capability) return E_INVALIDARG;
1060
1061 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1062 if (hr != S_OK) return hr;
1063
1064 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
1065 WICBitmapDecoderCapabilityCanDecodeSomeImages |
1066 WICBitmapDecoderCapabilityCanEnumerateMetadata;
1067 return S_OK;
1068 }
1069
1070 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1071 IStream *stream = gif->UserData;
1072 ULONG bytesread;
1073 HRESULT hr;
1074
1075 if (!stream)
1076 {
1077 ERR("attempting to read file after initialization\n");
1078 return 0;
1079 }
1080
1081 hr = IStream_Read(stream, data, len, &bytesread);
1082 if (hr != S_OK) bytesread = 0;
1083 return bytesread;
1084 }
1085
1086 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1087 WICDecodeOptions cacheOptions)
1088 {
1089 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1090 LARGE_INTEGER seek;
1091 int ret;
1092
1093 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1094
1095 EnterCriticalSection(&This->lock);
1096
1097 if (This->initialized || This->gif)
1098 {
1099 WARN("already initialized\n");
1100 LeaveCriticalSection(&This->lock);
1101 return WINCODEC_ERR_WRONGSTATE;
1102 }
1103
1104 /* seek to start of stream */
1105 seek.QuadPart = 0;
1106 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1107
1108 /* read all data from the stream */
1109 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1110 if (!This->gif)
1111 {
1112 LeaveCriticalSection(&This->lock);
1113 return E_FAIL;
1114 }
1115
1116 ret = DGifSlurp(This->gif);
1117 if (ret == GIF_ERROR)
1118 {
1119 LeaveCriticalSection(&This->lock);
1120 return E_FAIL;
1121 }
1122
1123 /* make sure we don't use the stream after this method returns */
1124 This->gif->UserData = NULL;
1125
1126 seek.QuadPart = 0;
1127 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1128 IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL);
1129
1130 This->initialized = TRUE;
1131
1132 LeaveCriticalSection(&This->lock);
1133
1134 return S_OK;
1135 }
1136
1137 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1138 GUID *pguidContainerFormat)
1139 {
1140 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1141 return S_OK;
1142 }
1143
1144 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1145 IWICBitmapDecoderInfo **ppIDecoderInfo)
1146 {
1147 HRESULT hr;
1148 IWICComponentInfo *compinfo;
1149
1150 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1151
1152 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
1153 if (FAILED(hr)) return hr;
1154
1155 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
1156 (void**)ppIDecoderInfo);
1157
1158 IWICComponentInfo_Release(compinfo);
1159
1160 return hr;
1161 }
1162
1163 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1164 {
1165 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1166 WICColor colors[256];
1167 ColorMapObject *cm;
1168 int i, trans, count;
1169 ExtensionBlock *eb;
1170
1171 TRACE("(%p,%p)\n", iface, palette);
1172
1173 cm = This->gif->SColorMap;
1174 if (cm)
1175 {
1176 if (cm->ColorCount > 256)
1177 {
1178 ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
1179 return E_FAIL;
1180 }
1181
1182 for (i = 0; i < cm->ColorCount; i++)
1183 {
1184 colors[i] = 0xff000000 | /* alpha */
1185 cm->Colors[i].Red << 16 |
1186 cm->Colors[i].Green << 8 |
1187 cm->Colors[i].Blue;
1188 }
1189
1190 count = cm->ColorCount;
1191 }
1192 else
1193 {
1194 colors[0] = 0xff000000;
1195 colors[1] = 0xffffffff;
1196
1197 for (i = 2; i < 256; i++)
1198 colors[i] = 0xff000000;
1199
1200 count = 256;
1201 }
1202
1203 /* look for the transparent color extension */
1204 for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
1205 {
1206 eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
1207 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
1208 {
1209 if (eb->Bytes[3] & 1)
1210 {
1211 trans = (unsigned char)eb->Bytes[6];
1212 colors[trans] &= 0xffffff; /* set alpha to 0 */
1213 break;
1214 }
1215 }
1216 }
1217
1218 return IWICPalette_InitializeCustom(palette, colors, count);
1219 }
1220
1221 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1222 IWICMetadataQueryReader **ppIMetadataQueryReader)
1223 {
1224 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1225 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1226 }
1227
1228 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1229 IWICBitmapSource **ppIBitmapSource)
1230 {
1231 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1232 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1233 }
1234
1235 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1236 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1237 {
1238 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1239 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1240 }
1241
1242 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1243 IWICBitmapSource **ppIThumbnail)
1244 {
1245 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1246 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1247 }
1248
1249 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1250 UINT *pCount)
1251 {
1252 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1253
1254 if (!pCount) return E_INVALIDARG;
1255
1256 EnterCriticalSection(&This->lock);
1257 *pCount = This->gif ? This->gif->ImageCount : 0;
1258 LeaveCriticalSection(&This->lock);
1259
1260 TRACE("(%p) <-- %d\n", iface, *pCount);
1261
1262 return S_OK;
1263 }
1264
1265 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1266 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1267 {
1268 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1269 GifFrameDecode *result;
1270 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1271
1272 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1273
1274 if (index >= This->gif->ImageCount) return E_INVALIDARG;
1275
1276 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1277 if (!result) return E_OUTOFMEMORY;
1278
1279 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1280 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1281 result->ref = 1;
1282 result->frame = &This->gif->SavedImages[index];
1283 IWICBitmapDecoder_AddRef(iface);
1284 result->parent = This;
1285 This->current_frame = index;
1286
1287 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1288
1289 return S_OK;
1290 }
1291
1292 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1293 GifDecoder_QueryInterface,
1294 GifDecoder_AddRef,
1295 GifDecoder_Release,
1296 GifDecoder_QueryCapability,
1297 GifDecoder_Initialize,
1298 GifDecoder_GetContainerFormat,
1299 GifDecoder_GetDecoderInfo,
1300 GifDecoder_CopyPalette,
1301 GifDecoder_GetMetadataQueryReader,
1302 GifDecoder_GetPreview,
1303 GifDecoder_GetColorContexts,
1304 GifDecoder_GetThumbnail,
1305 GifDecoder_GetFrameCount,
1306 GifDecoder_GetFrame
1307 };
1308
1309 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1310 REFIID iid, void **ppv)
1311 {
1312 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1313 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1314 }
1315
1316 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1317 {
1318 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1319 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1320 }
1321
1322 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1323 {
1324 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1325 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1326 }
1327
1328 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1329 GUID *guid)
1330 {
1331 TRACE("(%p,%p)\n", iface, guid);
1332
1333 if (!guid) return E_INVALIDARG;
1334
1335 *guid = GUID_ContainerFormatGif;
1336 return S_OK;
1337 }
1338
1339 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1340 UINT *count)
1341 {
1342 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1343
1344 TRACE("%p,%p\n", iface, count);
1345
1346 if (!count) return E_INVALIDARG;
1347
1348 *count = This->gif->Extensions.ExtensionBlockCount + 1;
1349 return S_OK;
1350 }
1351
1352 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1353 UINT index, IWICMetadataReader **reader)
1354 {
1355 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1356 int i;
1357
1358 TRACE("(%p,%u,%p)\n", iface, index, reader);
1359
1360 if (!reader) return E_INVALIDARG;
1361
1362 if (index == 0)
1363 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1364 &CLSID_WICLSDMetadataReader, reader);
1365
1366 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1367 {
1368 const CLSID *clsid;
1369
1370 if (index != i + 1) continue;
1371
1372 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1373 clsid = &CLSID_WICAPEMetadataReader;
1374 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1375 clsid = &CLSID_WICGifCommentMetadataReader;
1376 else
1377 clsid = &CLSID_WICUnknownMetadataReader;
1378
1379 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1380 This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1381 clsid, reader);
1382 }
1383
1384 return E_INVALIDARG;
1385 }
1386
1387 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1388 IEnumUnknown **enumerator)
1389 {
1390 FIXME("(%p,%p): stub\n", iface, enumerator);
1391 return E_NOTIMPL;
1392 }
1393
1394 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1395 {
1396 GifDecoder_Block_QueryInterface,
1397 GifDecoder_Block_AddRef,
1398 GifDecoder_Block_Release,
1399 GifDecoder_Block_GetContainerFormat,
1400 GifDecoder_Block_GetCount,
1401 GifDecoder_Block_GetReaderByIndex,
1402 GifDecoder_Block_GetEnumerator
1403 };
1404
1405 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1406 {
1407 GifDecoder *This;
1408 HRESULT ret;
1409
1410 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1411
1412 *ppv = NULL;
1413
1414 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1415
1416 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1417 if (!This) return E_OUTOFMEMORY;
1418
1419 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1420 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1421 This->ref = 1;
1422 This->initialized = FALSE;
1423 This->gif = NULL;
1424 This->current_frame = 0;
1425 InitializeCriticalSection(&This->lock);
1426 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1427
1428 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1429 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1430
1431 return ret;
1432 }