urlmon: Implemented canonicalization of query strings.
[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     FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
127     return E_NOTIMPL;
128 }
129
130 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
131     IWICPalette *pIPalette)
132 {
133     GifFrameDecode *This = (GifFrameDecode*)iface;
134     WICColor colors[256];
135     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
136     int i, trans;
137     ExtensionBlock *eb;
138     TRACE("(%p,%p)\n", iface, pIPalette);
139
140     if (!cm) cm = This->parent->gif->SColorMap;
141
142     if (cm->ColorCount > 256)
143     {
144         ERR("GIF contains %i colors???\n", cm->ColorCount);
145         return E_FAIL;
146     }
147
148     for (i = 0; i < cm->ColorCount; i++) {
149         colors[i] = 0xff000000| /* alpha */
150                     cm->Colors[i].Red << 16|
151                     cm->Colors[i].Green << 8|
152                     cm->Colors[i].Blue;
153     }
154
155     /* look for the transparent color extension */
156     for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
157         eb = This->frame->ExtensionBlocks + i;
158         if (eb->Function == 0xF9 && eb->ByteCount == 4) {
159             if ((eb->Bytes[0] & 1) == 1) {
160                 trans = (unsigned char)eb->Bytes[3];
161                 colors[trans] &= 0xffffff; /* set alpha to 0 */
162                 break;
163             }
164         }
165     }
166
167     IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
168
169     return S_OK;
170 }
171
172 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
173     UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
174     UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
175 {
176     UINT row_offset; /* number of bytes into the source rows where the data starts */
177     const BYTE *src;
178     BYTE *dst;
179     UINT y;
180
181     if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
182         return E_INVALIDARG;
183
184     if (dststride < rc->Width)
185         return E_INVALIDARG;
186
187     if ((dststride * rc->Height) > dstbuffersize)
188         return E_INVALIDARG;
189
190     row_offset = rc->X;
191
192     dst = dstbuffer;
193     for (y=rc->Y; y-rc->Y < rc->Height; y++)
194     {
195         if (y%8 == 0)
196             src = srcbuffer + srcstride * (y/8);
197         else if (y%4 == 0)
198             src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
199         else if (y%2 == 0)
200             src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
201         else /* y%2 == 1 */
202             src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
203         src += row_offset;
204         memcpy(dst, src, rc->Width);
205         dst += dststride;
206     }
207     return S_OK;
208 }
209
210 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
211     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
212 {
213     GifFrameDecode *This = (GifFrameDecode*)iface;
214     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
215
216     if (This->frame->ImageDesc.Interlace)
217     {
218         return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
219             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
220             prc, cbStride, cbBufferSize, pbBuffer);
221     }
222     else
223     {
224         return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
225             This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
226             prc, cbStride, cbBufferSize, pbBuffer);
227     }
228 }
229
230 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
231     IWICMetadataQueryReader **ppIMetadataQueryReader)
232 {
233     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
234     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
235 }
236
237 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
238     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
239 {
240     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
241     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
242 }
243
244 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
245     IWICBitmapSource **ppIThumbnail)
246 {
247     TRACE("(%p,%p)\n", iface, ppIThumbnail);
248     return WINCODEC_ERR_CODECNOTHUMBNAIL;
249 }
250
251 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
252     GifFrameDecode_QueryInterface,
253     GifFrameDecode_AddRef,
254     GifFrameDecode_Release,
255     GifFrameDecode_GetSize,
256     GifFrameDecode_GetPixelFormat,
257     GifFrameDecode_GetResolution,
258     GifFrameDecode_CopyPalette,
259     GifFrameDecode_CopyPixels,
260     GifFrameDecode_GetMetadataQueryReader,
261     GifFrameDecode_GetColorContexts,
262     GifFrameDecode_GetThumbnail
263 };
264
265 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
266     void **ppv)
267 {
268     GifDecoder *This = (GifDecoder*)iface;
269     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
270
271     if (!ppv) return E_INVALIDARG;
272
273     if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
274     {
275         *ppv = This;
276     }
277     else
278     {
279         *ppv = NULL;
280         return E_NOINTERFACE;
281     }
282
283     IUnknown_AddRef((IUnknown*)*ppv);
284     return S_OK;
285 }
286
287 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
288 {
289     GifDecoder *This = (GifDecoder*)iface;
290     ULONG ref = InterlockedIncrement(&This->ref);
291
292     TRACE("(%p) refcount=%u\n", iface, ref);
293
294     return ref;
295 }
296
297 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
298 {
299     GifDecoder *This = (GifDecoder*)iface;
300     ULONG ref = InterlockedDecrement(&This->ref);
301
302     TRACE("(%p) refcount=%u\n", iface, ref);
303
304     if (ref == 0)
305     {
306         This->lock.DebugInfo->Spare[0] = 0;
307         DeleteCriticalSection(&This->lock);
308         DGifCloseFile(This->gif);
309         HeapFree(GetProcessHeap(), 0, This);
310     }
311
312     return ref;
313 }
314
315 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
316     DWORD *pdwCapability)
317 {
318     FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
319     return E_NOTIMPL;
320 }
321
322 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
323     IStream *stream = gif->UserData;
324     ULONG bytesread;
325     HRESULT hr;
326
327     if (!stream)
328     {
329         ERR("attempting to read file after initialization\n");
330         return 0;
331     }
332
333     hr = IStream_Read(stream, data, len, &bytesread);
334     if (hr != S_OK) bytesread = 0;
335     return bytesread;
336 }
337
338 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
339     WICDecodeOptions cacheOptions)
340 {
341     GifDecoder *This = (GifDecoder*)iface;
342     LARGE_INTEGER seek;
343     int ret;
344
345     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
346
347     EnterCriticalSection(&This->lock);
348
349     if (This->initialized || This->gif)
350     {
351         WARN("already initialized\n");
352         LeaveCriticalSection(&This->lock);
353         return WINCODEC_ERR_WRONGSTATE;
354     }
355
356     /* seek to start of stream */
357     seek.QuadPart = 0;
358     IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
359
360     /* read all data from the stream */
361     This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
362     if (!This->gif)
363     {
364         LeaveCriticalSection(&This->lock);
365         return E_FAIL;
366     }
367
368     ret = DGifSlurp(This->gif);
369     if (ret == GIF_ERROR)
370     {
371         LeaveCriticalSection(&This->lock);
372         return E_FAIL;
373     }
374
375     /* make sure we don't use the stream after this method returns */
376     This->gif->UserData = NULL;
377
378     This->initialized = TRUE;
379
380     LeaveCriticalSection(&This->lock);
381
382     return S_OK;
383 }
384
385 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
386     GUID *pguidContainerFormat)
387 {
388     memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
389     return S_OK;
390 }
391
392 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
393     IWICBitmapDecoderInfo **ppIDecoderInfo)
394 {
395     HRESULT hr;
396     IWICComponentInfo *compinfo;
397
398     TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
399
400     hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
401     if (FAILED(hr)) return hr;
402
403     hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
404         (void**)ppIDecoderInfo);
405
406     IWICComponentInfo_Release(compinfo);
407
408     return hr;
409 }
410
411 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
412     IWICPalette *pIPalette)
413 {
414     TRACE("(%p,%p)\n", iface, pIPalette);
415     return WINCODEC_ERR_PALETTEUNAVAILABLE;
416 }
417
418 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
419     IWICMetadataQueryReader **ppIMetadataQueryReader)
420 {
421     TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
422     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
423 }
424
425 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
426     IWICBitmapSource **ppIBitmapSource)
427 {
428     TRACE("(%p,%p)\n", iface, ppIBitmapSource);
429     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
430 }
431
432 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
433     UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
434 {
435     TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
436     return WINCODEC_ERR_UNSUPPORTEDOPERATION;
437 }
438
439 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
440     IWICBitmapSource **ppIThumbnail)
441 {
442     TRACE("(%p,%p)\n", iface, ppIThumbnail);
443     return WINCODEC_ERR_CODECNOTHUMBNAIL;
444 }
445
446 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
447     UINT *pCount)
448 {
449     GifDecoder *This = (GifDecoder*)iface;
450     TRACE("(%p,%p)\n", iface, pCount);
451
452     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
453
454     *pCount = This->gif->ImageCount;
455
456     TRACE("<- %u\n", *pCount);
457
458     return S_OK;
459 }
460
461 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
462     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
463 {
464     GifDecoder *This = (GifDecoder*)iface;
465     GifFrameDecode *result;
466     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
467
468     if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
469
470     if (index >= This->gif->ImageCount) return E_INVALIDARG;
471
472     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
473     if (!result) return E_OUTOFMEMORY;
474
475     result->lpVtbl = &GifFrameDecode_Vtbl;
476     result->ref = 1;
477     result->frame = &This->gif->SavedImages[index];
478     IWICBitmapDecoder_AddRef(iface);
479     result->parent = This;
480
481     *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
482
483     return S_OK;
484 }
485
486 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
487     GifDecoder_QueryInterface,
488     GifDecoder_AddRef,
489     GifDecoder_Release,
490     GifDecoder_QueryCapability,
491     GifDecoder_Initialize,
492     GifDecoder_GetContainerFormat,
493     GifDecoder_GetDecoderInfo,
494     GifDecoder_CopyPalette,
495     GifDecoder_GetMetadataQueryReader,
496     GifDecoder_GetPreview,
497     GifDecoder_GetColorContexts,
498     GifDecoder_GetThumbnail,
499     GifDecoder_GetFrameCount,
500     GifDecoder_GetFrame
501 };
502
503 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
504 {
505     GifDecoder *This;
506     HRESULT ret;
507
508     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
509
510     *ppv = NULL;
511
512     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
513
514     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
515     if (!This) return E_OUTOFMEMORY;
516
517     This->lpVtbl = &GifDecoder_Vtbl;
518     This->ref = 1;
519     This->initialized = FALSE;
520     This->gif = NULL;
521     InitializeCriticalSection(&This->lock);
522     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
523
524     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
525     IUnknown_Release((IUnknown*)This);
526
527     return ret;
528 }