jscript: Add index, input and lastIndex properties to regexp functions results.
[wine] / dlls / windowscodecs / gifformat.c
1 /*
2  * Copyright 2009 Vincent Povirk for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29
30 #include "ungif.h"
31
32 #include "wincodecs_private.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37
38 typedef struct {
39     const IWICBitmapDecoderVtbl *lpVtbl;
40     LONG ref;
41     BOOL initialized;
42     GifFileType *gif;
43     CRITICAL_SECTION lock;
44 } GifDecoder;
45
46 typedef struct {
47     const IWICBitmapFrameDecodeVtbl *lpVtbl;
48     LONG ref;
49     SavedImage *frame;
50     GifDecoder *parent;
51 } GifFrameDecode;
52
53 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
54     void **ppv)
55 {
56     GifFrameDecode *This = (GifFrameDecode*)iface;
57     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
58
59     if (!ppv) return E_INVALIDARG;
60
61     if (IsEqualIID(&IID_IUnknown, iid) ||
62         IsEqualIID(&IID_IWICBitmapSource, iid) ||
63         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
64     {
65         *ppv = This;
66     }
67     else
68     {
69         *ppv = NULL;
70         return E_NOINTERFACE;
71     }
72
73     IUnknown_AddRef((IUnknown*)*ppv);
74     return S_OK;
75 }
76
77 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
78 {
79     GifFrameDecode *This = (GifFrameDecode*)iface;
80     ULONG ref = InterlockedIncrement(&This->ref);
81
82     TRACE("(%p) refcount=%u\n", iface, ref);
83
84     return ref;
85 }
86
87 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
88 {
89     GifFrameDecode *This = (GifFrameDecode*)iface;
90     ULONG ref = InterlockedDecrement(&This->ref);
91
92     TRACE("(%p) refcount=%u\n", iface, ref);
93
94     if (ref == 0)
95     {
96         IUnknown_Release((IUnknown*)This->parent);
97         HeapFree(GetProcessHeap(), 0, This);
98     }
99
100     return ref;
101 }
102
103 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
104     UINT *puiWidth, UINT *puiHeight)
105 {
106     GifFrameDecode *This = (GifFrameDecode*)iface;
107     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
108
109     *puiWidth = This->frame->ImageDesc.Width;
110     *puiHeight = This->frame->ImageDesc.Height;
111
112     return S_OK;
113 }
114
115 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
116     WICPixelFormatGUID *pPixelFormat)
117 {
118     memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
119
120     return S_OK;
121 }
122
123 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
124     double *pDpiX, double *pDpiY)
125 {
126     GifFrameDecode *This = (GifFrameDecode*)iface;
127     const GifWord aspect_word = This->parent->gif->SAspectRatio;
128     const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
129     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
130
131     *pDpiX = 96.0 / aspect;
132     *pDpiY = 96.0;
133
134     return S_OK;
135 }
136
137 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
138     IWICPalette *pIPalette)
139 {
140     GifFrameDecode *This = (GifFrameDecode*)iface;
141     WICColor colors[256];
142     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
143     int i, trans;
144     ExtensionBlock *eb;
145     TRACE("(%p,%p)\n", iface, pIPalette);
146
147     if (!cm) cm = This->parent->gif->SColorMap;
148
149     if (cm->ColorCount > 256)
150     {
151         ERR("GIF contains %i colors???\n", cm->ColorCount);
152         return E_FAIL;
153     }
154
155     for (i = 0; i < cm->ColorCount; i++) {
156         colors[i] = 0xff000000| /* alpha */
157                     cm->Colors[i].Red << 16|
158                     cm->Colors[i].Green << 8|
159                     cm->Colors[i].Blue;
160     }
161
162     /* look for the transparent color extension */
163     for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
164         eb = This->frame->ExtensionBlocks + i;
165         if (eb->Function == 0xF9 && eb->ByteCount == 4) {
166             if ((eb->Bytes[0] & 1) == 1) {
167                 trans = (unsigned char)eb->Bytes[3];
168                 colors[trans] &= 0xffffff; /* set alpha to 0 */
169                 break;
170             }
171         }
172     }
173
174     IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
175
176     return S_OK;
177 }
178
179 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
180     UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
181     UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
182 {
183     UINT row_offset; /* number of bytes into the source rows where the data starts */
184     const BYTE *src;
185     BYTE *dst;
186     UINT y;
187
188     if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
189         return E_INVALIDARG;
190
191     if (dststride < rc->Width)
192         return E_INVALIDARG;
193
194     if ((dststride * rc->Height) > dstbuffersize)
195         return E_INVALIDARG;
196
197     row_offset = rc->X;
198
199     dst = dstbuffer;
200     for (y=rc->Y; y-rc->Y < rc->Height; y++)
201     {
202         if (y%8 == 0)
203             src = srcbuffer + srcstride * (y/8);
204         else if (y%4 == 0)
205             src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
206         else if (y%2 == 0)
207             src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
208         else /* y%2 == 1 */
209             src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
210         src += row_offset;
211         memcpy(dst, src, rc->Width);
212         dst += dststride;
213     }
214     return S_OK;
215 }
216
217 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
218     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
219 {
220     GifFrameDecode *This = (GifFrameDecode*)iface;
221     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
222
223     if (This->frame->ImageDesc.Interlace)
224     {
225         return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
226             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
227             prc, cbStride, cbBufferSize, pbBuffer);
228     }
229     else
230     {
231         return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
232             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
233             prc, cbStride, cbBufferSize, pbBuffer);
234     }
235 }
236
237 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
238     IWICMetadataQueryReader **ppIMetadataQueryReader)
239 {
240     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
241     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
242 }
243
244 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
245     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
246 {
247     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
248     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
249 }
250
251 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
252     IWICBitmapSource **ppIThumbnail)
253 {
254     TRACE("(%p,%p)\n", iface, ppIThumbnail);
255     return WINCODEC_ERR_CODECNOTHUMBNAIL;
256 }
257
258 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
259     GifFrameDecode_QueryInterface,
260     GifFrameDecode_AddRef,
261     GifFrameDecode_Release,
262     GifFrameDecode_GetSize,
263     GifFrameDecode_GetPixelFormat,
264     GifFrameDecode_GetResolution,
265     GifFrameDecode_CopyPalette,
266     GifFrameDecode_CopyPixels,
267     GifFrameDecode_GetMetadataQueryReader,
268     GifFrameDecode_GetColorContexts,
269     GifFrameDecode_GetThumbnail
270 };
271
272 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
273     void **ppv)
274 {
275     GifDecoder *This = (GifDecoder*)iface;
276     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
277
278     if (!ppv) return E_INVALIDARG;
279
280     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
281     {
282         *ppv = This;
283     }
284     else
285     {
286         *ppv = NULL;
287         return E_NOINTERFACE;
288     }
289
290     IUnknown_AddRef((IUnknown*)*ppv);
291     return S_OK;
292 }
293
294 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
295 {
296     GifDecoder *This = (GifDecoder*)iface;
297     ULONG ref = InterlockedIncrement(&This->ref);
298
299     TRACE("(%p) refcount=%u\n", iface, ref);
300
301     return ref;
302 }
303
304 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
305 {
306     GifDecoder *This = (GifDecoder*)iface;
307     ULONG ref = InterlockedDecrement(&This->ref);
308
309     TRACE("(%p) refcount=%u\n", iface, ref);
310
311     if (ref == 0)
312     {
313         This->lock.DebugInfo->Spare[0] = 0;
314         DeleteCriticalSection(&This->lock);
315         DGifCloseFile(This->gif);
316         HeapFree(GetProcessHeap(), 0, This);
317     }
318
319     return ref;
320 }
321
322 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
323     DWORD *pdwCapability)
324 {
325     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
326     return E_NOTIMPL;
327 }
328
329 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
330     IStream *stream = gif->UserData;
331     ULONG bytesread;
332     HRESULT hr;
333
334     if (!stream)
335     {
336         ERR("attempting to read file after initialization\n");
337         return 0;
338     }
339
340     hr = IStream_Read(stream, data, len, &bytesread);
341     if (hr != S_OK) bytesread = 0;
342     return bytesread;
343 }
344
345 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
346     WICDecodeOptions cacheOptions)
347 {
348     GifDecoder *This = (GifDecoder*)iface;
349     LARGE_INTEGER seek;
350     int ret;
351
352     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
353
354     EnterCriticalSection(&This->lock);
355
356     if (This->initialized || This->gif)
357     {
358         WARN("already initialized\n");
359         LeaveCriticalSection(&This->lock);
360         return WINCODEC_ERR_WRONGSTATE;
361     }
362
363     /* seek to start of stream */
364     seek.QuadPart = 0;
365     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
366
367     /* read all data from the stream */
368     This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
369     if (!This->gif)
370     {
371         LeaveCriticalSection(&This->lock);
372         return E_FAIL;
373     }
374
375     ret = DGifSlurp(This->gif);
376     if (ret == GIF_ERROR)
377     {
378         LeaveCriticalSection(&This->lock);
379         return E_FAIL;
380     }
381
382     /* make sure we don't use the stream after this method returns */
383     This->gif->UserData = NULL;
384
385     This->initialized = TRUE;
386
387     LeaveCriticalSection(&This->lock);
388
389     return S_OK;
390 }
391
392 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
393     GUID *pguidContainerFormat)
394 {
395     memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
396     return S_OK;
397 }
398
399 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
400     IWICBitmapDecoderInfo **ppIDecoderInfo)
401 {
402     HRESULT hr;
403     IWICComponentInfo *compinfo;
404
405     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
406
407     hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
408     if (FAILED(hr)) return hr;
409
410     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
411         (void**)ppIDecoderInfo);
412
413     IWICComponentInfo_Release(compinfo);
414
415     return hr;
416 }
417
418 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
419     IWICPalette *pIPalette)
420 {
421     TRACE("(%p,%p)\n", iface, pIPalette);
422     return WINCODEC_ERR_PALETTEUNAVAILABLE;
423 }
424
425 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
426     IWICMetadataQueryReader **ppIMetadataQueryReader)
427 {
428     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
429     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
430 }
431
432 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
433     IWICBitmapSource **ppIBitmapSource)
434 {
435     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
436     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
437 }
438
439 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
440     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
441 {
442     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
443     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
444 }
445
446 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
447     IWICBitmapSource **ppIThumbnail)
448 {
449     TRACE("(%p,%p)\n", iface, ppIThumbnail);
450     return WINCODEC_ERR_CODECNOTHUMBNAIL;
451 }
452
453 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
454     UINT *pCount)
455 {
456     GifDecoder *This = (GifDecoder*)iface;
457     TRACE("(%p,%p)\n", iface, pCount);
458
459     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
460
461     *pCount = This->gif->ImageCount;
462
463     TRACE("<- %u\n", *pCount);
464
465     return S_OK;
466 }
467
468 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
469     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
470 {
471     GifDecoder *This = (GifDecoder*)iface;
472     GifFrameDecode *result;
473     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
474
475     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
476
477     if (index >= This->gif->ImageCount) return E_INVALIDARG;
478
479     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
480     if (!result) return E_OUTOFMEMORY;
481
482     result->lpVtbl = &GifFrameDecode_Vtbl;
483     result->ref = 1;
484     result->frame = &This->gif->SavedImages[index];
485     IWICBitmapDecoder_AddRef(iface);
486     result->parent = This;
487
488     *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
489
490     return S_OK;
491 }
492
493 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
494     GifDecoder_QueryInterface,
495     GifDecoder_AddRef,
496     GifDecoder_Release,
497     GifDecoder_QueryCapability,
498     GifDecoder_Initialize,
499     GifDecoder_GetContainerFormat,
500     GifDecoder_GetDecoderInfo,
501     GifDecoder_CopyPalette,
502     GifDecoder_GetMetadataQueryReader,
503     GifDecoder_GetPreview,
504     GifDecoder_GetColorContexts,
505     GifDecoder_GetThumbnail,
506     GifDecoder_GetFrameCount,
507     GifDecoder_GetFrame
508 };
509
510 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
511 {
512     GifDecoder *This;
513     HRESULT ret;
514
515     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
516
517     *ppv = NULL;
518
519     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
520
521     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
522     if (!This) return E_OUTOFMEMORY;
523
524     This->lpVtbl = &GifDecoder_Vtbl;
525     This->ref = 1;
526     This->initialized = FALSE;
527     This->gif = NULL;
528     InitializeCriticalSection(&This->lock);
529     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
530
531     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
532     IUnknown_Release((IUnknown*)This);
533
534     return ret;
535 }