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