- Add windowscodecs.dll from Wine 1.1.28
authorDmitry Chapyshev <dmitry@reactos.org>
Sat, 22 Aug 2009 19:03:09 +0000 (19:03 +0000)
committerDmitry Chapyshev <dmitry@reactos.org>
Sat, 22 Aug 2009 19:03:09 +0000 (19:03 +0000)
svn path=/trunk/; revision=42867

25 files changed:
reactos/baseaddress.rbuild
reactos/boot/bootdata/packages/reactos.dff
reactos/dll/win32/win32.rbuild
reactos/dll/win32/windowscodecs/bmpdecode.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/bmpencode.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/clsfactory.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/converter.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/gifformat.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/icoformat.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/imgfactory.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/info.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/main.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/palette.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/propertybag.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/regsvr.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/stream.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/ungif.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/ungif.h [new file with mode: 0644]
reactos/dll/win32/windowscodecs/version.rc [new file with mode: 0644]
reactos/dll/win32/windowscodecs/wincodecs_private.h [new file with mode: 0644]
reactos/dll/win32/windowscodecs/windowscodecs.rbuild [new file with mode: 0644]
reactos/dll/win32/windowscodecs/windowscodecs.spec [new file with mode: 0644]
reactos/include/psdk/psdk.rbuild
reactos/include/psdk/wincodec.idl [new file with mode: 0644]
reactos/media/doc/README.WINE

index f36856c..5ec3e97 100644 (file)
@@ -6,6 +6,7 @@
   <property name="BASEADDRESS_QMGRPRXY" value="0x1F710000" />
   <property name="BASEADDRESS_CRYPTDLG" value="0x209C0000" />
   <property name="BASEADDRESS_COMCAT" value="0x20A50000" />
+  <property name="BASEADDRESS_WINDOWSCODECS" value="0x26c40000" />
   <property name="BASEADDRESS_DEVENUM" value="0x35680000" />
   <property name="BASEADDRESS_RSABASE" value="0x35700000" />
   <property name="BASEADDRESS_RSAENH" value="0x35780000" />
index 36326cf..aa7382a 100644 (file)
@@ -439,6 +439,7 @@ dll\win32\usp10\usp10.dll                           1
 dll\win32\uxtheme\uxtheme.dll                       1
 dll\win32\vdmdbg\vdmdbg.dll                         1
 dll\win32\version\version.dll                       1
+dll\win32\windowscodecs\windowscodecs.dll           1
 dll\win32\winemp3.acm\winemp3.acm                   1
 dll\win32\winfax\winfax.dll                         1
 dll\win32\winhttp\winhttp.dll                       1
index c3261d5..a1fbe61 100644 (file)
 <directory name="wdmaud.drv">
        <xi:include href="wdmaud.drv/wdmaud.rbuild" />
 </directory>
+<directory name="windowscodecs">
+       <xi:include href="windowscodecs/windowscodecs.rbuild" />
+</directory>
 <directory name="winemp3.acm">
        <xi:include href="winemp3.acm/winemp3.acm.rbuild" />
 </directory>
diff --git a/reactos/dll/win32/windowscodecs/bmpdecode.c b/reactos/dll/win32/windowscodecs/bmpdecode.c
new file mode 100644 (file)
index 0000000..5c805c8
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wingdi.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct {
+    DWORD bc2Size;
+    DWORD bc2Width;
+    DWORD bc2Height;
+    WORD  bc2Planes;
+    WORD  bc2BitCount;
+    DWORD bc2Compression;
+    DWORD bc2SizeImage;
+    DWORD bc2XRes;
+    DWORD bc2YRes;
+    DWORD bc2ClrUsed;
+    DWORD bc2ClrImportant;
+    /* same as BITMAPINFOHEADER until this point */
+    WORD  bc2ResUnit;
+    WORD  bc2Reserved;
+    WORD  bc2Orientation;
+    WORD  bc2Halftoning;
+    DWORD bc2HalftoneSize1;
+    DWORD bc2HalftoneSize2;
+    DWORD bc2ColorSpace;
+    DWORD bc2AppData;
+} BITMAPCOREHEADER2;
+
+struct BmpFrameDecode;
+typedef HRESULT (*ReadDataFunc)(struct BmpFrameDecode* This);
+
+typedef struct BmpFrameDecode {
+    const IWICBitmapFrameDecodeVtbl *lpVtbl;
+    LONG ref;
+    IStream *stream;
+    BITMAPFILEHEADER bfh;
+    BITMAPV5HEADER bih;
+    const WICPixelFormatGUID *pixelformat;
+    int bitsperpixel;
+    ReadDataFunc read_data_func;
+    INT stride;
+    BYTE *imagedata;
+    BYTE *imagedatastart;
+} BmpFrameDecode;
+
+static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
+    void **ppv)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapSource, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        IStream_Release(This->stream);
+        HeapFree(GetProcessHeap(), 0, This->imagedata);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
+
+    if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+    {
+        BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
+        *puiWidth = bch->bcWidth;
+        *puiHeight = bch->bcHeight;
+    }
+    else
+    {
+        *puiWidth = This->bih.bV5Width;
+        *puiHeight = abs(This->bih.bV5Height);
+    }
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    TRACE("(%p,%p)\n", iface, pPixelFormat);
+
+    memcpy(pPixelFormat, This->pixelformat, sizeof(GUID));
+
+    return S_OK;
+}
+
+static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY)
+{
+    switch (bih->bV5Size)
+    {
+    case sizeof(BITMAPCOREHEADER):
+        *pDpiX = 96.0;
+        *pDpiY = 96.0;
+        return S_OK;
+    case sizeof(BITMAPCOREHEADER2):
+    case sizeof(BITMAPINFOHEADER):
+    case sizeof(BITMAPV4HEADER):
+    case sizeof(BITMAPV5HEADER):
+        *pDpiX = bih->bV5XPelsPerMeter * 0.0254;
+        *pDpiY = bih->bV5YPelsPerMeter * 0.0254;
+        return S_OK;
+    default:
+        return E_FAIL;
+    }
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
+    double *pDpiX, double *pDpiY)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
+
+    return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY);
+}
+
+static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
+    IWICPalette *pIPalette)
+{
+    HRESULT hr;
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    int count;
+    WICColor *wiccolors=NULL;
+    RGBTRIPLE *bgrcolors=NULL;
+
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+    {
+        BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
+        if (bch->bcBitCount <= 8)
+        {
+            /* 2**n colors in BGR format after the header */
+            ULONG tablesize, bytesread;
+            LARGE_INTEGER offset;
+            int i;
+
+            count = 1 << bch->bcBitCount;
+            wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
+            tablesize = sizeof(RGBTRIPLE) * count;
+            bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
+            if (!wiccolors || !bgrcolors)
+            {
+                hr = E_OUTOFMEMORY;
+                goto end;
+            }
+
+            offset.QuadPart = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER);
+            hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
+            if (FAILED(hr)) goto end;
+
+            hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread);
+            if (FAILED(hr)) goto end;
+            if (bytesread != tablesize) {
+                hr = E_FAIL;
+                goto end;
+            }
+
+            for (i=0; i<count; i++)
+            {
+                wiccolors[i] = 0xff000000|
+                               (bgrcolors[i].rgbtRed<<16)|
+                               (bgrcolors[i].rgbtGreen<<8)|
+                               bgrcolors[i].rgbtBlue;
+            }
+        }
+        else
+        {
+            return WINCODEC_ERR_PALETTEUNAVAILABLE;
+        }
+    }
+    else
+    {
+        if (This->bih.bV5BitCount <= 8)
+        {
+            ULONG tablesize, bytesread;
+            LARGE_INTEGER offset;
+            int i;
+
+            if (This->bih.bV5ClrUsed == 0)
+                count = 1 << This->bih.bV5BitCount;
+            else
+                count = This->bih.bV5ClrUsed;
+
+            tablesize = sizeof(WICColor) * count;
+            wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize);
+            if (!wiccolors) return E_OUTOFMEMORY;
+
+            offset.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+            hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
+            if (FAILED(hr)) goto end;
+
+            hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread);
+            if (FAILED(hr)) goto end;
+            if (bytesread != tablesize) {
+                hr = E_FAIL;
+                goto end;
+            }
+
+            /* convert from BGR to BGRA by setting alpha to 100% */
+            for (i=0; i<count; i++)
+                wiccolors[i] |= 0xff000000;
+        }
+        else
+        {
+            return WINCODEC_ERR_PALETTEUNAVAILABLE;
+        }
+    }
+
+    hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
+
+end:
+    HeapFree(GetProcessHeap(), 0, wiccolors);
+    HeapFree(GetProcessHeap(), 0, bgrcolors);
+    return hr;
+}
+
+static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+{
+    BmpFrameDecode *This = (BmpFrameDecode*)iface;
+    HRESULT hr;
+    UINT width, height;
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    if (!This->imagedata)
+    {
+        hr = This->read_data_func(This);
+        if (FAILED(hr)) return hr;
+    }
+
+    hr = BmpFrameDecode_GetSize(iface, &width, &height);
+    if (FAILED(hr)) return hr;
+
+    return copy_pixels(This->bitsperpixel, This->imagedatastart,
+        width, height, This->stride,
+        prc, cbStride, cbBufferSize, pbBuffer);
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static HRESULT BmpFrameDecode_ReadUncompressed(BmpFrameDecode* This)
+{
+    UINT bytesperrow;
+    UINT width, height;
+    UINT datasize;
+    int bottomup;
+    HRESULT hr;
+    LARGE_INTEGER offbits;
+    ULONG bytesread;
+
+    if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+    {
+        BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
+        width = bch->bcWidth;
+        height = bch->bcHeight;
+        bottomup = 1;
+    }
+    else
+    {
+        width = This->bih.bV5Width;
+        height = abs(This->bih.bV5Height);
+        bottomup = (This->bih.bV5Height > 0);
+    }
+
+    /* row sizes in BMP files must be divisible by 4 bytes */
+    bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
+    datasize = bytesperrow * height;
+
+    This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
+    if (!This->imagedata) return E_OUTOFMEMORY;
+
+    offbits.QuadPart = This->bfh.bfOffBits;
+    hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread);
+    if (FAILED(hr) || bytesread != datasize) goto fail;
+
+    if (bottomup)
+    {
+        This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
+        This->stride = -bytesperrow;
+    }
+    else
+    {
+        This->imagedatastart = This->imagedata;
+        This->stride = bytesperrow;
+    }
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, This->imagedata);
+    This->imagedata = NULL;
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    return hr;
+}
+
+static HRESULT BmpFrameDecode_ReadRLE8(BmpFrameDecode* This)
+{
+    UINT bytesperrow;
+    UINT width, height;
+    BYTE *rledata, *cursor, *rledataend;
+    UINT rlesize, datasize, palettesize;
+    DWORD palette[256];
+    UINT x, y;
+    DWORD *bgrdata;
+    HRESULT hr;
+    LARGE_INTEGER offbits;
+    ULONG bytesread;
+
+    width = This->bih.bV5Width;
+    height = abs(This->bih.bV5Height);
+    bytesperrow = width * 4;
+    datasize = bytesperrow * height;
+    rlesize = This->bih.bV5SizeImage;
+    if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256)
+        palettesize = 4 * This->bih.bV5ClrUsed;
+    else
+        palettesize = 4 * 256;
+
+    rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
+    This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
+    if (!This->imagedata || !rledata)
+    {
+        hr = E_OUTOFMEMORY;
+        goto fail;
+    }
+
+    /* read palette */
+    offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+    hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
+    if (FAILED(hr) || bytesread != palettesize) goto fail;
+
+    /* read RLE data */
+    offbits.QuadPart = This->bfh.bfOffBits;
+    hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
+    if (FAILED(hr) || bytesread != rlesize) goto fail;
+
+    /* decode RLE */
+    bgrdata = (DWORD*)This->imagedata;
+    x = 0;
+    y = 0;
+    rledataend = rledata + rlesize;
+    cursor = rledata;
+    while (cursor < rledataend && y < height)
+    {
+        BYTE length = *cursor++;
+        if (length == 0)
+        {
+            /* escape code */
+            BYTE escape = *cursor++;
+            switch(escape)
+            {
+            case 0: /* end of line */
+                x = 0;
+                y++;
+                break;
+            case 1: /* end of bitmap */
+                goto end;
+            case 2: /* delta */
+                if (cursor < rledataend)
+                {
+                    x += *cursor++;
+                    y += *cursor++;
+                }
+                break;
+            default: /* absolute mode */
+                length = escape;
+                while (cursor < rledataend && length-- && x < width)
+                    bgrdata[y*width + x++] = palette[*cursor++];
+                if (escape & 1) cursor++; /* skip pad byte */
+            }
+        }
+        else
+        {
+            DWORD color = palette[*cursor++];
+            while (length-- && x < width)
+                bgrdata[y*width + x++] = color;
+        }
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, rledata);
+
+    This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
+    This->stride = -bytesperrow;
+
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, rledata);
+    HeapFree(GetProcessHeap(), 0, This->imagedata);
+    This->imagedata = NULL;
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    return hr;
+}
+
+static HRESULT BmpFrameDecode_ReadRLE4(BmpFrameDecode* This)
+{
+    UINT bytesperrow;
+    UINT width, height;
+    BYTE *rledata, *cursor, *rledataend;
+    UINT rlesize, datasize, palettesize;
+    DWORD palette[16];
+    UINT x, y;
+    DWORD *bgrdata;
+    HRESULT hr;
+    LARGE_INTEGER offbits;
+    ULONG bytesread;
+
+    width = This->bih.bV5Width;
+    height = abs(This->bih.bV5Height);
+    bytesperrow = width * 4;
+    datasize = bytesperrow * height;
+    rlesize = This->bih.bV5SizeImage;
+    if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16)
+        palettesize = 4 * This->bih.bV5ClrUsed;
+    else
+        palettesize = 4 * 16;
+
+    rledata = HeapAlloc(GetProcessHeap(), 0, rlesize);
+    This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
+    if (!This->imagedata || !rledata)
+    {
+        hr = E_OUTOFMEMORY;
+        goto fail;
+    }
+
+    /* read palette */
+    offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+    hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, palette, palettesize, &bytesread);
+    if (FAILED(hr) || bytesread != palettesize) goto fail;
+
+    /* read RLE data */
+    offbits.QuadPart = This->bfh.bfOffBits;
+    hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, rledata, rlesize, &bytesread);
+    if (FAILED(hr) || bytesread != rlesize) goto fail;
+
+    /* decode RLE */
+    bgrdata = (DWORD*)This->imagedata;
+    x = 0;
+    y = 0;
+    rledataend = rledata + rlesize;
+    cursor = rledata;
+    while (cursor < rledataend && y < height)
+    {
+        BYTE length = *cursor++;
+        if (length == 0)
+        {
+            /* escape code */
+            BYTE escape = *cursor++;
+            switch(escape)
+            {
+            case 0: /* end of line */
+                x = 0;
+                y++;
+                break;
+            case 1: /* end of bitmap */
+                goto end;
+            case 2: /* delta */
+                if (cursor < rledataend)
+                {
+                    x += *cursor++;
+                    y += *cursor++;
+                }
+                break;
+            default: /* absolute mode */
+                length = escape;
+                while (cursor < rledataend && length-- && x < width)
+                {
+                    BYTE colors = *cursor++;
+                    bgrdata[y*width + x++] = palette[colors>>4];
+                    if (length-- && x < width)
+                        bgrdata[y*width + x++] = palette[colors&0xf];
+                    else
+                        break;
+                }
+                if ((cursor - rledata) & 1) cursor++; /* skip pad byte */
+            }
+        }
+        else
+        {
+            BYTE colors = *cursor++;
+            DWORD color1 = palette[colors>>4];
+            DWORD color2 = palette[colors&0xf];
+            while (length-- && x < width)
+            {
+                bgrdata[y*width + x++] = color1;
+                if (length-- && x < width)
+                    bgrdata[y*width + x++] = color2;
+                else
+                    break;
+            }
+        }
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, rledata);
+
+    This->imagedatastart = This->imagedata + (height-1) * bytesperrow;
+    This->stride = -bytesperrow;
+
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, rledata);
+    HeapFree(GetProcessHeap(), 0, This->imagedata);
+    This->imagedata = NULL;
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    return hr;
+}
+
+static HRESULT BmpFrameDecode_ReadUnsupported(BmpFrameDecode* This)
+{
+    return E_FAIL;
+}
+
+struct bitfields_format {
+    WORD bitcount; /* 0 for end of list */
+    DWORD redmask;
+    DWORD greenmask;
+    DWORD bluemask;
+    DWORD alphamask;
+    const WICPixelFormatGUID *pixelformat;
+    ReadDataFunc read_data_func;
+};
+
+static const struct bitfields_format bitfields_formats[] = {
+    {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555,BmpFrameDecode_ReadUncompressed},
+    {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed},
+    {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed},
+    {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed},
+    {0}
+};
+
+static const IWICBitmapFrameDecodeVtbl BmpFrameDecode_Vtbl = {
+    BmpFrameDecode_QueryInterface,
+    BmpFrameDecode_AddRef,
+    BmpFrameDecode_Release,
+    BmpFrameDecode_GetSize,
+    BmpFrameDecode_GetPixelFormat,
+    BmpFrameDecode_GetResolution,
+    BmpFrameDecode_CopyPalette,
+    BmpFrameDecode_CopyPixels,
+    BmpFrameDecode_GetMetadataQueryReader,
+    BmpFrameDecode_GetColorContexts,
+    BmpFrameDecode_GetThumbnail
+};
+
+typedef struct {
+    const IWICBitmapDecoderVtbl *lpVtbl;
+    LONG ref;
+    BOOL initialized;
+    IStream *stream;
+    BITMAPFILEHEADER bfh;
+    BITMAPV5HEADER bih;
+    BmpFrameDecode *framedecode;
+    const WICPixelFormatGUID *pixelformat;
+    int bitsperpixel;
+    ReadDataFunc read_data_func;
+} BmpDecoder;
+
+static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
+{
+    HRESULT hr;
+    ULONG bytestoread, bytesread;
+    LARGE_INTEGER seek;
+
+    if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
+
+    seek.QuadPart = 0;
+    hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) return hr;
+
+    hr = IStream_Read(stream, &This->bfh, sizeof(BITMAPFILEHEADER), &bytesread);
+    if (FAILED(hr)) return hr;
+    if (bytesread != sizeof(BITMAPFILEHEADER) ||
+        This->bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
+
+    hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
+    if (FAILED(hr)) return hr;
+    if (bytesread != sizeof(DWORD) ||
+        (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) &&
+         This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) &&
+         This->bih.bV5Size != sizeof(BITMAPINFOHEADER) &&
+         This->bih.bV5Size != sizeof(BITMAPV4HEADER) &&
+         This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL;
+
+    bytestoread = This->bih.bV5Size-sizeof(DWORD);
+    hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread);
+    if (FAILED(hr)) return hr;
+    if (bytestoread != bytesread) return E_FAIL;
+
+    /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
+        read the extra fields */
+    if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) &&
+        This->bih.bV5Compression == BI_BITFIELDS)
+    {
+        hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread);
+        if (FAILED(hr)) return hr;
+        if (bytesread != 12) return E_FAIL;
+        This->bih.bV5AlphaMask = 0;
+    }
+
+    /* decide what kind of bitmap this is and how/if we can read it */
+    if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+    {
+        BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
+        TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount);
+        This->bitsperpixel = bch->bcBitCount;
+        This->read_data_func = BmpFrameDecode_ReadUncompressed;
+        switch(bch->bcBitCount)
+        {
+        case 1:
+            This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
+            break;
+        case 2:
+            This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
+            break;
+        case 4:
+            This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
+            break;
+        case 8:
+            This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
+            break;
+        case 24:
+            This->pixelformat = &GUID_WICPixelFormat24bppBGR;
+            break;
+        default:
+            This->pixelformat = &GUID_WICPixelFormatUndefined;
+            WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount);
+            break;
+        }
+    }
+    else /* struct is compatible with BITMAPINFOHEADER */
+    {
+        TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
+        switch(This->bih.bV5Compression)
+        {
+        case BI_RGB:
+            This->bitsperpixel = This->bih.bV5BitCount;
+            This->read_data_func = BmpFrameDecode_ReadUncompressed;
+            switch(This->bih.bV5BitCount)
+            {
+            case 1:
+                This->pixelformat = &GUID_WICPixelFormat1bppIndexed;
+                break;
+            case 2:
+                This->pixelformat = &GUID_WICPixelFormat2bppIndexed;
+                break;
+            case 4:
+                This->pixelformat = &GUID_WICPixelFormat4bppIndexed;
+                break;
+            case 8:
+                This->pixelformat = &GUID_WICPixelFormat8bppIndexed;
+                break;
+            case 16:
+                This->pixelformat = &GUID_WICPixelFormat16bppBGR555;
+                break;
+            case 24:
+                This->pixelformat = &GUID_WICPixelFormat24bppBGR;
+                break;
+            case 32:
+                This->pixelformat = &GUID_WICPixelFormat32bppBGR;
+                break;
+            default:
+                This->pixelformat = &GUID_WICPixelFormatUndefined;
+                FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount);
+            }
+            break;
+        case BI_RLE8:
+            This->bitsperpixel = 32;
+            This->read_data_func = BmpFrameDecode_ReadRLE8;
+            This->pixelformat = &GUID_WICPixelFormat32bppBGR;
+            break;
+        case BI_RLE4:
+            This->bitsperpixel = 32;
+            This->read_data_func = BmpFrameDecode_ReadRLE4;
+            This->pixelformat = &GUID_WICPixelFormat32bppBGR;
+            break;
+        case BI_BITFIELDS:
+        {
+            const struct bitfields_format *format;
+            if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2))
+            {
+                /* BCH2 doesn't support bitfields; this is Huffman 1D compression */
+                This->bitsperpixel = 0;
+                This->read_data_func = BmpFrameDecode_ReadUnsupported;
+                This->pixelformat = &GUID_WICPixelFormatUndefined;
+                FIXME("Huffman 1D compression is unsupported\n");
+                break;
+            }
+            This->bitsperpixel = This->bih.bV5BitCount;
+            for (format = bitfields_formats; format->bitcount; format++)
+            {
+                if ((format->bitcount == This->bih.bV5BitCount) &&
+                    (format->redmask == This->bih.bV5RedMask) &&
+                    (format->greenmask == This->bih.bV5GreenMask) &&
+                    (format->bluemask == This->bih.bV5BlueMask) &&
+                    (format->alphamask == This->bih.bV5AlphaMask))
+                {
+                    This->read_data_func = format->read_data_func;
+                    This->pixelformat = format->pixelformat;
+                    break;
+                }
+            }
+            if (!format->bitcount)
+            {
+                This->read_data_func = BmpFrameDecode_ReadUncompressed;
+                This->pixelformat = &GUID_WICPixelFormatUndefined;
+                FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n",
+                    This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask);
+            }
+            break;
+        }
+        default:
+            This->bitsperpixel = 0;
+            This->read_data_func = BmpFrameDecode_ReadUnsupported;
+            This->pixelformat = &GUID_WICPixelFormatUndefined;
+            FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount);
+            break;
+        }
+    }
+
+    This->initialized = TRUE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
+    void **ppv)
+{
+    BmpDecoder *This = (BmpDecoder*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
+{
+    BmpDecoder *This = (BmpDecoder*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
+{
+    BmpDecoder *This = (BmpDecoder*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->stream) IStream_Release(This->stream);
+        if (This->framedecode) IUnknown_Release((IUnknown*)This->framedecode);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
+    DWORD *pdwCapability)
+{
+    HRESULT hr;
+    BmpDecoder *This = (BmpDecoder*)iface;
+
+    hr = BmpDecoder_ReadHeaders(This, pIStream);
+    if (FAILED(hr)) return hr;
+
+    if (This->read_data_func == BmpFrameDecode_ReadUnsupported)
+        *pdwCapability = 0;
+    else
+        *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
+    WICDecodeOptions cacheOptions)
+{
+    HRESULT hr;
+    BmpDecoder *This = (BmpDecoder*)iface;
+
+    hr = BmpDecoder_ReadHeaders(This, pIStream);
+
+    if (SUCCEEDED(hr))
+    {
+        This->stream = pIStream;
+        IStream_AddRef(pIStream);
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
+    GUID *pguidContainerFormat)
+{
+    memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
+    IWICBitmapDecoderInfo **ppIDecoderInfo)
+{
+    HRESULT hr;
+    IWICComponentInfo *compinfo;
+
+    TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
+
+    hr = CreateComponentInfo(&CLSID_WICBmpDecoder, &compinfo);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void**)ppIDecoderInfo);
+
+    IWICComponentInfo_Release(compinfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface,
+    IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    return WINCODEC_ERR_PALETTEUNAVAILABLE;
+}
+
+static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIBitmapSource)
+{
+    TRACE("(%p,%p)\n", iface, ppIBitmapSource);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
+    UINT *pCount)
+{
+    *pCount = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
+    UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
+{
+    BmpDecoder *This = (BmpDecoder*)iface;
+
+    if (index != 0) return E_INVALIDARG;
+
+    if (!This->stream) return WINCODEC_ERR_WRONGSTATE;
+
+    if (!This->framedecode)
+    {
+        This->framedecode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameDecode));
+        if (!This->framedecode) return E_OUTOFMEMORY;
+
+        This->framedecode->lpVtbl = &BmpFrameDecode_Vtbl;
+        This->framedecode->ref = 1;
+        This->framedecode->stream = This->stream;
+        IStream_AddRef(This->stream);
+        This->framedecode->bfh = This->bfh;
+        This->framedecode->bih = This->bih;
+        This->framedecode->pixelformat = This->pixelformat;
+        This->framedecode->bitsperpixel = This->bitsperpixel;
+        This->framedecode->read_data_func = This->read_data_func;
+        This->framedecode->imagedata = NULL;
+    }
+
+    *ppIBitmapFrame = (IWICBitmapFrameDecode*)This->framedecode;
+    IWICBitmapFrameDecode_AddRef((IWICBitmapFrameDecode*)This->framedecode);
+
+    return S_OK;
+}
+
+static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
+    BmpDecoder_QueryInterface,
+    BmpDecoder_AddRef,
+    BmpDecoder_Release,
+    BmpDecoder_QueryCapability,
+    BmpDecoder_Initialize,
+    BmpDecoder_GetContainerFormat,
+    BmpDecoder_GetDecoderInfo,
+    BmpDecoder_CopyPalette,
+    BmpDecoder_GetMetadataQueryReader,
+    BmpDecoder_GetPreview,
+    BmpDecoder_GetColorContexts,
+    BmpDecoder_GetThumbnail,
+    BmpDecoder_GetFrameCount,
+    BmpDecoder_GetFrame
+};
+
+HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    BmpDecoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &BmpDecoder_Vtbl;
+    This->ref = 1;
+    This->initialized = FALSE;
+    This->stream = NULL;
+    This->framedecode = NULL;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/bmpencode.c b/reactos/dll/win32/windowscodecs/bmpencode.c
new file mode 100644 (file)
index 0000000..a545103
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "wingdi.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+struct bmp_pixelformat {
+    const WICPixelFormatGUID *guid;
+    UINT bpp;
+    DWORD compression;
+    DWORD redmask;
+    DWORD greenmask;
+    DWORD bluemask;
+    DWORD alphamask;
+};
+
+static const struct bmp_pixelformat formats[] = {
+    {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
+    {NULL}
+};
+
+typedef struct BmpFrameEncode {
+    const IWICBitmapFrameEncodeVtbl *lpVtbl;
+    LONG ref;
+    IStream *stream;
+    BOOL initialized;
+    UINT width, height;
+    BYTE *bits;
+    const struct bmp_pixelformat *format;
+    double xres, yres;
+    UINT lineswritten;
+    UINT stride;
+    BOOL committed;
+} BmpFrameEncode;
+
+static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
+    void **ppv)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->stream) IStream_Release(This->stream);
+        HeapFree(GetProcessHeap(), 0, This->bits);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
+    IPropertyBag2 *pIEncoderOptions)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    TRACE("(%p,%p)\n", iface, pIEncoderOptions);
+
+    if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
+
+    This->initialized = TRUE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
+    UINT uiWidth, UINT uiHeight)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
+
+    if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
+
+    This->width = uiWidth;
+    This->height = uiHeight;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
+    double dpiX, double dpiY)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
+
+    if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
+
+    This->xres = dpiX;
+    This->yres = dpiY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    int i;
+    TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
+
+    if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
+
+    for (i=0; formats[i].guid; i++)
+    {
+        if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
+            break;
+    }
+
+    if (!formats[i].guid) i = 0;
+
+    This->format = &formats[i];
+    memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
+    IWICPalette *pIPalette)
+{
+    FIXME("(%p,%p): stub\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIThumbnail)
+{
+    FIXME("(%p,%p): stub\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
+{
+    if (!This->bits)
+    {
+        if (!This->initialized || !This->width || !This->height || !This->format)
+            return WINCODEC_ERR_WRONGSTATE;
+
+        This->stride = (((This->width * This->format->bpp)+31)/32)*4;
+        This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
+        if (!This->bits) return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
+    UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    HRESULT hr;
+    WICRect rc;
+    TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
+
+    if (!This->initialized || !This->width || !This->height || !This->format)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    hr = BmpFrameEncode_AllocateBits(This);
+    if (FAILED(hr)) return hr;
+
+    rc.X = 0;
+    rc.Y = 0;
+    rc.Width = This->width;
+    rc.Height = lineCount;
+
+    hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
+        &rc, This->stride, This->stride*(This->height-This->lineswritten),
+        This->bits + This->stride*This->lineswritten);
+
+    if (SUCCEEDED(hr))
+        This->lineswritten += lineCount;
+
+    return hr;
+}
+
+static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIBitmapSource, WICRect *prc)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    HRESULT hr;
+    WICRect rc;
+    WICPixelFormatGUID guid;
+    TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
+
+    if (!This->initialized || !This->width || !This->height)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    if (!This->format)
+    {
+        hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
+        if (FAILED(hr)) return hr;
+        hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
+        if (FAILED(hr)) return hr;
+    }
+
+    hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
+    if (FAILED(hr)) return hr;
+    if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
+    {
+        /* should use WICConvertBitmapSource to convert, but that's unimplemented */
+        ERR("format %s unsupported\n", debugstr_guid(&guid));
+        return E_FAIL;
+    }
+
+    if (This->xres == 0.0 || This->yres == 0.0)
+    {
+        double xres, yres;
+        hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
+        if (FAILED(hr)) return hr;
+        hr = BmpFrameEncode_SetResolution(iface, xres, yres);
+        if (FAILED(hr)) return hr;
+    }
+
+    if (!prc)
+    {
+        UINT width, height;
+        hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
+        if (FAILED(hr)) return hr;
+        rc.X = 0;
+        rc.Y = 0;
+        rc.Width = width;
+        rc.Height = height;
+        prc = &rc;
+    }
+
+    if (prc->Width != This->width) return E_INVALIDARG;
+
+    hr = BmpFrameEncode_AllocateBits(This);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
+        This->stride*(This->height-This->lineswritten),
+        This->bits + This->stride*This->lineswritten);
+
+    This->lineswritten += rc.Height;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
+{
+    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BITMAPFILEHEADER bfh;
+    BITMAPV5HEADER bih;
+    UINT info_size;
+    LARGE_INTEGER pos;
+    ULONG byteswritten;
+    HRESULT hr;
+
+    TRACE("(%p)\n", iface);
+
+    if (!This->bits || This->committed || This->height != This->lineswritten)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    bfh.bfType = 0x4d42; /* "BM" */
+    bfh.bfReserved1 = 0;
+    bfh.bfReserved2 = 0;
+
+    bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
+    bih.bV5Width = This->width;
+    bih.bV5Height = -This->height; /* top-down bitmap */
+    bih.bV5Planes = 1;
+    bih.bV5BitCount = This->format->bpp;
+    bih.bV5Compression = This->format->compression;
+    bih.bV5SizeImage = This->stride*This->height;
+    bih.bV5XPelsPerMeter = (This->xres-0.0127) / 0.0254;
+    bih.bV5YPelsPerMeter = (This->yres-0.0127) / 0.0254;
+    bih.bV5ClrUsed = 0;
+    bih.bV5ClrImportant = 0;
+
+    bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
+    bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
+
+    pos.QuadPart = 0;
+    hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);\
+    if (FAILED(hr)) return hr;
+
+    hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
+    if (FAILED(hr)) return hr;
+    if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
+
+    hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
+    if (FAILED(hr)) return hr;
+    if (byteswritten != info_size) return E_FAIL;
+
+    hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
+    if (FAILED(hr)) return hr;
+    if (byteswritten != bih.bV5SizeImage) return E_FAIL;
+
+    This->committed = TRUE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
+    BmpFrameEncode_QueryInterface,
+    BmpFrameEncode_AddRef,
+    BmpFrameEncode_Release,
+    BmpFrameEncode_Initialize,
+    BmpFrameEncode_SetSize,
+    BmpFrameEncode_SetResolution,
+    BmpFrameEncode_SetPixelFormat,
+    BmpFrameEncode_SetColorContexts,
+    BmpFrameEncode_SetPalette,
+    BmpFrameEncode_SetThumbnail,
+    BmpFrameEncode_WritePixels,
+    BmpFrameEncode_WriteSource,
+    BmpFrameEncode_Commit,
+    BmpFrameEncode_GetMetadataQueryWriter
+};
+
+typedef struct BmpEncoder {
+    const IWICBitmapEncoderVtbl *lpVtbl;
+    LONG ref;
+    IStream *stream;
+    IWICBitmapFrameEncode *frame;
+} BmpEncoder;
+
+static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
+    void **ppv)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapEncoder, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->stream) IStream_Release(This->stream);
+        if (This->frame) IWICBitmapFrameEncode_Release(This->frame);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
+    IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+
+    TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
+
+    IStream_AddRef(pIStream);
+    This->stream = pIStream;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
+    GUID *pguidContainerFormat)
+{
+    FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
+    IWICBitmapEncoderInfo **ppIEncoderInfo)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
+{
+    TRACE("(%p,%p)\n", iface, pIPreview);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
+    IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpFrameEncode *encode;
+    HRESULT hr;
+
+    TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
+
+    if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+
+    if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
+
+    hr = CreatePropertyBag2(ppIEncoderOptions);
+    if (FAILED(hr)) return hr;
+
+    encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
+    if (!encode)
+    {
+        IPropertyBag2_Release(*ppIEncoderOptions);
+        *ppIEncoderOptions = NULL;
+        return E_OUTOFMEMORY;
+    }
+    encode->lpVtbl = &BmpFrameEncode_Vtbl;
+    encode->ref = 2;
+    IStream_AddRef(This->stream);
+    encode->stream = This->stream;
+    encode->initialized = FALSE;
+    encode->width = 0;
+    encode->height = 0;
+    encode->bits = NULL;
+    encode->format = NULL;
+    encode->xres = 0.0;
+    encode->yres = 0.0;
+    encode->lineswritten = 0;
+    encode->committed = FALSE;
+
+    *ppIFrameEncode = (IWICBitmapFrameEncode*)encode;
+    This->frame = (IWICBitmapFrameEncode*)encode;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
+{
+    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpFrameEncode *frame = (BmpFrameEncode*)This->frame;
+    TRACE("(%p)\n", iface);
+
+    if (!frame || !frame->committed) return WINCODEC_ERR_WRONGSTATE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
+    BmpEncoder_QueryInterface,
+    BmpEncoder_AddRef,
+    BmpEncoder_Release,
+    BmpEncoder_Initialize,
+    BmpEncoder_GetContainerFormat,
+    BmpEncoder_GetEncoderInfo,
+    BmpEncoder_SetColorContexts,
+    BmpEncoder_SetPalette,
+    BmpEncoder_SetThumbnail,
+    BmpEncoder_SetPreview,
+    BmpEncoder_CreateNewFrame,
+    BmpEncoder_Commit,
+    BmpEncoder_GetMetadataQueryWriter
+};
+
+HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    BmpEncoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &BmpEncoder_Vtbl;
+    This->ref = 1;
+    This->stream = NULL;
+    This->frame = NULL;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/clsfactory.c b/reactos/dll/win32/windowscodecs/clsfactory.c
new file mode 100644 (file)
index 0000000..0ce08b3
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "ocidl.h"
+#include "initguid.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct {
+    REFCLSID classid;
+    HRESULT (*constructor)(IUnknown*,REFIID,void**);
+} classinfo;
+
+static classinfo wic_classes[] = {
+    {&CLSID_WICImagingFactory, ImagingFactory_CreateInstance},
+    {&CLSID_WICBmpDecoder, BmpDecoder_CreateInstance},
+    {&CLSID_WICBmpEncoder, BmpEncoder_CreateInstance},
+    {&CLSID_WICGifDecoder, GifDecoder_CreateInstance},
+    {&CLSID_WICIcoDecoder, IcoDecoder_CreateInstance},
+    {&CLSID_WICDefaultFormatConverter, FormatConverter_CreateInstance},
+    {0}};
+
+typedef struct {
+    const IClassFactoryVtbl *lpIClassFactoryVtbl;
+    LONG                    ref;
+    classinfo               *info;
+} ClassFactoryImpl;
+
+static HRESULT WINAPI ClassFactoryImpl_QueryInterface(IClassFactory *iface,
+    REFIID iid, void **ppv)
+{
+    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IClassFactory, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface)
+{
+    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface)
+{
+    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI ClassFactoryImpl_CreateInstance(IClassFactory *iface,
+    IUnknown *pUnkOuter, REFIID riid, void **ppv)
+{
+    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+
+    return This->info->constructor(pUnkOuter, riid, ppv);
+}
+
+static HRESULT WINAPI ClassFactoryImpl_LockServer(IClassFactory *iface, BOOL lock)
+{
+    TRACE("(%p, %i): stub\n", iface, lock);
+    return E_NOTIMPL;
+}
+
+static const IClassFactoryVtbl ClassFactoryImpl_Vtbl = {
+    ClassFactoryImpl_QueryInterface,
+    ClassFactoryImpl_AddRef,
+    ClassFactoryImpl_Release,
+    ClassFactoryImpl_CreateInstance,
+    ClassFactoryImpl_LockServer
+};
+
+static HRESULT ClassFactoryImpl_Constructor(classinfo *info, REFIID riid, LPVOID *ppv)
+{
+    ClassFactoryImpl *This;
+    HRESULT ret;
+
+    *ppv = NULL;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ClassFactoryImpl));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpIClassFactoryVtbl = &ClassFactoryImpl_Vtbl;
+    This->ref = 1;
+    This->info = info;
+
+    ret = IClassFactory_QueryInterface((IClassFactory*)This, riid, ppv);
+    IClassFactory_Release((IClassFactory*)This);
+
+    return ret;
+}
+
+HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
+{
+    HRESULT ret;
+    classinfo *info=NULL;
+    int i;
+
+    TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
+
+    if (!rclsid || !iid || !ppv)
+        return E_INVALIDARG;
+
+    *ppv = NULL;
+
+    for (i=0; wic_classes[i].classid; i++)
+    {
+        if (IsEqualCLSID(wic_classes[i].classid, rclsid))
+        {
+            info = &wic_classes[i];
+            break;
+        }
+    }
+
+    if (info)
+        ret = ClassFactoryImpl_Constructor(info, iid, ppv);
+    else
+        ret = CLASS_E_CLASSNOTAVAILABLE;
+
+    TRACE("<-- %08X\n", ret);
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/converter.c b/reactos/dll/win32/windowscodecs/converter.c
new file mode 100644 (file)
index 0000000..7db56ea
--- /dev/null
@@ -0,0 +1,659 @@
+/*
+ * Copyright 2009 Vincent Povirk
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+struct FormatConverter;
+
+enum pixelformat {
+    format_1bppIndexed,
+    format_4bppIndexed,
+    format_8bppIndexed,
+    format_16bppBGR555,
+    format_16bppBGR565,
+    format_24bppBGR,
+    format_32bppBGR,
+    format_32bppBGRA
+};
+
+typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
+    UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
+
+struct pixelformatinfo {
+    enum pixelformat format;
+    const WICPixelFormatGUID *guid;
+    copyfunc copy_function;
+};
+
+typedef struct FormatConverter {
+    const IWICFormatConverterVtbl *lpVtbl;
+    LONG ref;
+    IWICBitmapSource *source;
+    const struct pixelformatinfo *dst_format, *src_format;
+    WICBitmapDitherType dither;
+    double alpha_threshold;
+    WICBitmapPaletteType palette_type;
+} FormatConverter;
+
+static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
+    UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
+{
+    switch (source_format)
+    {
+    case format_1bppIndexed:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const BYTE *srcbyte;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+            WICColor colors[2];
+            IWICPalette *palette;
+            UINT actualcolors;
+
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
+
+            res = IWICBitmapSource_CopyPalette(This->source, palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
+
+            IWICPalette_Release(palette);
+
+            if (FAILED(res)) return res;
+
+            srcstride = (prc->Width+7)/8;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcbyte=(const BYTE*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x+=8) {
+                        BYTE srcval;
+                        srcval=*srcbyte++;
+                        *dstpixel++ = colors[srcval>>7&1];
+                        if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
+                        if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
+                        if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
+                        if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
+                        if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
+                        if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
+                        if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_4bppIndexed:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const BYTE *srcbyte;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+            WICColor colors[16];
+            IWICPalette *palette;
+            UINT actualcolors;
+
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
+
+            res = IWICBitmapSource_CopyPalette(This->source, palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
+
+            IWICPalette_Release(palette);
+
+            if (FAILED(res)) return res;
+
+            srcstride = (prc->Width+1)/2;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcbyte=(const BYTE*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x+=2) {
+                        BYTE srcval;
+                        srcval=*srcbyte++;
+                        *dstpixel++ = colors[srcval>>4];
+                        if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_8bppIndexed:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const BYTE *srcbyte;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+            WICColor colors[256];
+            IWICPalette *palette;
+            UINT actualcolors;
+
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
+
+            res = IWICBitmapSource_CopyPalette(This->source, palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
+
+            IWICPalette_Release(palette);
+
+            if (FAILED(res)) return res;
+
+            srcstride = prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcbyte=(const BYTE*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x++)
+                        *dstpixel++ = colors[*srcbyte++];
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_16bppBGR555:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const WORD *srcpixel;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+
+            srcstride = 2 * prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcpixel=(const WORD*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x++) {
+                        WORD srcval;
+                        srcval=*srcpixel++;
+                        *dstpixel++=0xff000000 | /* constant 255 alpha */
+                                    ((srcval << 9) & 0xf80000) | /* r */
+                                    ((srcval << 4) & 0x070000) | /* r - 3 bits */
+                                    ((srcval << 6) & 0x00f800) | /* g */
+                                    ((srcval << 1) & 0x000700) | /* g - 3 bits */
+                                    ((srcval << 3) & 0x0000f8) | /* b */
+                                    ((srcval >> 2) & 0x000007);  /* b - 3 bits */
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_16bppBGR565:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const WORD *srcpixel;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+
+            srcstride = 2 * prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcpixel=(const WORD*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x++) {
+                        WORD srcval;
+                        srcval=*srcpixel++;
+                        *dstpixel++=0xff000000 | /* constant 255 alpha */
+                                    ((srcval << 8) & 0xf80000) | /* r */
+                                    ((srcval << 3) & 0x070000) | /* r - 3 bits */
+                                    ((srcval << 5) & 0x00fc00) | /* g */
+                                    ((srcval >> 1) & 0x000300) | /* g - 2 bits */
+                                    ((srcval << 3) & 0x0000f8) | /* b */
+                                    ((srcval >> 2) & 0x000007);  /* b - 3 bits */
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_24bppBGR:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const BYTE *srcpixel;
+            BYTE *dstrow;
+            BYTE *dstpixel;
+
+            srcstride = 3 * prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcpixel=srcrow;
+                    dstpixel=dstrow;
+                    for (x=0; x<prc->Width; x++) {
+                        *dstpixel++=*srcpixel++; /* blue */
+                        *dstpixel++=*srcpixel++; /* green */
+                        *dstpixel++=*srcpixel++; /* red */
+                        *dstpixel++=255; /* alpha */
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
+    case format_32bppBGR:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+            if (FAILED(res)) return res;
+
+            /* set all alpha values to 255 */
+            for (y=0; y<prc->Height; y++)
+                for (x=0; x<prc->Width; x++)
+                    pbBuffer[cbStride*y+4*x+3] = 0xff;
+        }
+        return S_OK;
+    case format_32bppBGRA:
+        if (prc)
+            return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+        return S_OK;
+    default:
+        return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+    }
+}
+
+static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
+    UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
+{
+    switch (source_format)
+    {
+    case format_32bppBGR:
+    case format_32bppBGRA:
+        if (prc)
+            return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+        return S_OK;
+    default:
+        return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
+    }
+}
+
+static const struct pixelformatinfo supported_formats[] = {
+    {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
+    {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
+    {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
+    {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
+    {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
+    {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
+    {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
+    {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
+    {0}
+};
+
+static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
+{
+    UINT i;
+
+    for (i=0; supported_formats[i].guid; i++)
+        if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
+
+    return NULL;
+}
+
+static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
+    void **ppv)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapSource, iid) ||
+        IsEqualIID(&IID_IWICFormatConverter, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->source) IWICBitmapSource_Release(This->source);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+
+    TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
+
+    if (This->source)
+        return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
+    else
+        return WINCODEC_ERR_NOTINITIALIZED;
+}
+
+static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+
+    TRACE("(%p,%p): stub\n", iface, pPixelFormat);
+
+    if (This->source)
+        memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
+    else
+        return WINCODEC_ERR_NOTINITIALIZED;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
+    double *pDpiX, double *pDpiY)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+
+    TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
+
+    if (This->source)
+        return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
+    else
+        return WINCODEC_ERR_NOTINITIALIZED;
+}
+
+static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
+    IWICPalette *pIPalette)
+{
+    FIXME("(%p,%p): stub\n", iface, pIPalette);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    if (This->source)
+        return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
+            pbBuffer, This->src_format->format);
+    else
+        return WINCODEC_ERR_NOTINITIALIZED;
+}
+
+static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
+    IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
+    IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    const struct pixelformatinfo *srcinfo, *dstinfo;
+    static INT fixme=0;
+    GUID srcFormat;
+    HRESULT res;
+
+    TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
+        dither, pIPalette, alphaThresholdPercent, paletteTranslate);
+
+    if (pIPalette && !fixme++) FIXME("ignoring palette\n");
+
+    if (This->source) return WINCODEC_ERR_WRONGSTATE;
+
+    res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
+    if (FAILED(res)) return res;
+
+    srcinfo = get_formatinfo(&srcFormat);
+    if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+
+    dstinfo = get_formatinfo(dstFormat);
+    if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+
+    if (dstinfo->copy_function)
+    {
+        IWICBitmapSource_AddRef(pISource);
+        This->source = pISource;
+        This->src_format = srcinfo;
+        This->dst_format = dstinfo;
+        This->dither = dither;
+        This->alpha_threshold = alphaThresholdPercent;
+        This->palette_type = paletteTranslate;
+    }
+    else
+        return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
+    REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
+    BOOL *pfCanConvert)
+{
+    FormatConverter *This = (FormatConverter*)iface;
+    const struct pixelformatinfo *srcinfo, *dstinfo;
+
+    TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
+        debugstr_guid(dstPixelFormat), pfCanConvert);
+
+    srcinfo = get_formatinfo(srcPixelFormat);
+    if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+
+    dstinfo = get_formatinfo(dstPixelFormat);
+    if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+
+    if (dstinfo->copy_function &&
+        SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
+        *pfCanConvert = TRUE;
+    else
+        *pfCanConvert = FALSE;
+
+    return S_OK;
+}
+
+static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
+    FormatConverter_QueryInterface,
+    FormatConverter_AddRef,
+    FormatConverter_Release,
+    FormatConverter_GetSize,
+    FormatConverter_GetPixelFormat,
+    FormatConverter_GetResolution,
+    FormatConverter_CopyPalette,
+    FormatConverter_CopyPixels,
+    FormatConverter_Initialize,
+    FormatConverter_CanConvert
+};
+
+HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    FormatConverter *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &FormatConverter_Vtbl;
+    This->ref = 1;
+    This->source = NULL;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/gifformat.c b/reactos/dll/win32/windowscodecs/gifformat.c
new file mode 100644 (file)
index 0000000..0597b1a
--- /dev/null
@@ -0,0 +1,510 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "ungif.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct {
+    const IWICBitmapDecoderVtbl *lpVtbl;
+    LONG ref;
+    BOOL initialized;
+    GifFileType *gif;
+} GifDecoder;
+
+typedef struct {
+    const IWICBitmapFrameDecodeVtbl *lpVtbl;
+    LONG ref;
+    SavedImage *frame;
+    GifDecoder *parent;
+} GifFrameDecode;
+
+static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
+    void **ppv)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapSource, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        IUnknown_Release((IUnknown*)This->parent);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
+
+    *puiWidth = This->frame->ImageDesc.Width;
+    *puiHeight = This->frame->ImageDesc.Height;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
+    double *pDpiX, double *pDpiY)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
+    IWICPalette *pIPalette)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    WICColor colors[256];
+    ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
+    int i, trans;
+    ExtensionBlock *eb;
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    if (!cm) cm = This->parent->gif->SColorMap;
+
+    if (cm->ColorCount > 256)
+    {
+        ERR("GIF contains %i colors???\n", cm->ColorCount);
+        return E_FAIL;
+    }
+
+    for (i = 0; i < cm->ColorCount; i++) {
+        colors[i] = 0xff000000| /* alpha */
+                    cm->Colors[i].Red << 16|
+                    cm->Colors[i].Green << 8|
+                    cm->Colors[i].Blue;
+    }
+
+    /* look for the transparent color extension */
+    for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
+       eb = This->frame->ExtensionBlocks + i;
+       if (eb->Function == 0xF9 && eb->ByteCount == 4) {
+           if ((eb->Bytes[0] & 1) == 1) {
+               trans = (unsigned char)eb->Bytes[3];
+               colors[trans] &= 0xffffff; /* set alpha to 0 */
+               break;
+           }
+       }
+    }
+
+    IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
+
+    return S_OK;
+}
+
+static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
+    UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
+    UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
+{
+    UINT row_offset; /* number of bytes into the source rows where the data starts */
+    const BYTE *src;
+    BYTE *dst;
+    UINT y;
+
+    if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
+        return E_INVALIDARG;
+
+    if (dststride < rc->Width)
+        return E_INVALIDARG;
+
+    if ((dststride * rc->Height) > dstbuffersize)
+        return E_INVALIDARG;
+
+    row_offset = rc->X;
+
+    dst = dstbuffer;
+    for (y=rc->Y; y-rc->Y < rc->Height; y++)
+    {
+        if (y%8 == 0)
+            src = srcbuffer + srcstride * (y/8);
+        else if (y%4 == 0)
+            src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
+        else if (y%2 == 0)
+            src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
+        else /* y%2 == 1 */
+            src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
+        src += row_offset;
+        memcpy(dst, src, rc->Width);
+        dst += dststride;
+    }
+    return S_OK;
+}
+
+static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+{
+    GifFrameDecode *This = (GifFrameDecode*)iface;
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    if (This->frame->ImageDesc.Interlace)
+    {
+        return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
+            This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
+            prc, cbStride, cbBufferSize, pbBuffer);
+    }
+    else
+    {
+        return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
+            This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
+            prc, cbStride, cbBufferSize, pbBuffer);
+    }
+}
+
+static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
+    GifFrameDecode_QueryInterface,
+    GifFrameDecode_AddRef,
+    GifFrameDecode_Release,
+    GifFrameDecode_GetSize,
+    GifFrameDecode_GetPixelFormat,
+    GifFrameDecode_GetResolution,
+    GifFrameDecode_CopyPalette,
+    GifFrameDecode_CopyPixels,
+    GifFrameDecode_GetMetadataQueryReader,
+    GifFrameDecode_GetColorContexts,
+    GifFrameDecode_GetThumbnail
+};
+
+static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
+    void **ppv)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        DGifCloseFile(This->gif);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
+    DWORD *pdwCapability)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
+    return E_NOTIMPL;
+}
+
+static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
+    IStream *stream = gif->UserData;
+    ULONG bytesread;
+    HRESULT hr;
+
+    if (!stream)
+    {
+        ERR("attempting to read file after initialization\n");
+        return 0;
+    }
+
+    hr = IStream_Read(stream, data, len, &bytesread);
+    if (hr != S_OK) bytesread = 0;
+    return bytesread;
+}
+
+static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
+    WICDecodeOptions cacheOptions)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    LARGE_INTEGER seek;
+    int ret;
+
+    TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
+
+    if (This->initialized || This->gif)
+    {
+        WARN("already initialized\n");
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    /* seek to start of stream */
+    seek.QuadPart = 0;
+    IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
+
+    /* read all data from the stream */
+    This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
+    if (!This->gif) return E_FAIL;
+
+    ret = DGifSlurp(This->gif);
+    if (ret == GIF_ERROR) return E_FAIL;
+
+    /* make sure we don't use the stream after this method returns */
+    This->gif->UserData = NULL;
+
+    This->initialized = TRUE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
+    GUID *pguidContainerFormat)
+{
+    memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
+    return S_OK;
+}
+
+static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
+    IWICBitmapDecoderInfo **ppIDecoderInfo)
+{
+    HRESULT hr;
+    IWICComponentInfo *compinfo;
+
+    TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
+
+    hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void**)ppIDecoderInfo);
+
+    IWICComponentInfo_Release(compinfo);
+
+    return hr;
+}
+
+static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
+    IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_PALETTEUNAVAILABLE;
+}
+
+static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIBitmapSource)
+{
+    TRACE("(%p,%p)\n", iface, ppIBitmapSource);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
+    UINT *pCount)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    TRACE("(%p,%p)\n", iface, pCount);
+
+    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+
+    *pCount = This->gif->ImageCount;
+
+    TRACE("<- %u\n", *pCount);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
+    UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
+{
+    GifDecoder *This = (GifDecoder*)iface;
+    GifFrameDecode *result;
+    TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
+
+    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+
+    if (index >= This->gif->ImageCount) return E_INVALIDARG;
+
+    result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
+    if (!result) return E_OUTOFMEMORY;
+
+    result->lpVtbl = &GifFrameDecode_Vtbl;
+    result->ref = 1;
+    result->frame = &This->gif->SavedImages[index];
+    IWICBitmapDecoder_AddRef(iface);
+    result->parent = This;
+
+    *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
+
+    return S_OK;
+}
+
+static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
+    GifDecoder_QueryInterface,
+    GifDecoder_AddRef,
+    GifDecoder_Release,
+    GifDecoder_QueryCapability,
+    GifDecoder_Initialize,
+    GifDecoder_GetContainerFormat,
+    GifDecoder_GetDecoderInfo,
+    GifDecoder_CopyPalette,
+    GifDecoder_GetMetadataQueryReader,
+    GifDecoder_GetPreview,
+    GifDecoder_GetColorContexts,
+    GifDecoder_GetThumbnail,
+    GifDecoder_GetFrameCount,
+    GifDecoder_GetFrame
+};
+
+HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    GifDecoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &GifDecoder_Vtbl;
+    This->ref = 1;
+    This->initialized = FALSE;
+    This->gif = NULL;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/icoformat.c b/reactos/dll/win32/windowscodecs/icoformat.c
new file mode 100644 (file)
index 0000000..ab30ab0
--- /dev/null
@@ -0,0 +1,797 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+#include "pshpack1.h"
+
+typedef struct {
+    BYTE bWidth;
+    BYTE bHeight;
+    BYTE bColorCount;
+    BYTE bReserved;
+    WORD wPlanes;
+    WORD wBitCount;
+    DWORD dwDIBSize;
+    DWORD dwDIBOffset;
+} ICONDIRENTRY;
+
+typedef struct
+{
+    WORD idReserved;
+    WORD idType;
+    WORD idCount;
+} ICONHEADER;
+
+#include "poppack.h"
+
+typedef struct {
+    const IWICBitmapDecoderVtbl *lpVtbl;
+    LONG ref;
+    BOOL initialized;
+    IStream *stream;
+    ICONHEADER header;
+} IcoDecoder;
+
+typedef struct {
+    const IWICBitmapFrameDecodeVtbl *lpVtbl;
+    LONG ref;
+    ICONDIRENTRY entry;
+    IcoDecoder *parent;
+    BYTE *bits;
+} IcoFrameDecode;
+
+static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
+    void **ppv)
+{
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapSource, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
+{
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
+{
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        IUnknown_Release((IUnknown*)This->parent);
+        HeapFree(GetProcessHeap(), 0, This->bits);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+
+    *puiWidth = This->entry.bWidth ? This->entry.bWidth : 256;
+    *puiHeight = This->entry.bHeight ? This->entry.bHeight : 256;
+
+    TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+    return S_OK;
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
+    double *pDpiX, double *pDpiY)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
+    IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_PALETTEUNAVAILABLE;
+}
+
+static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+{
+    if (transparent) *pixel = 0;
+    else *pixel |= 0xff000000;
+}
+
+static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
+{
+    BITMAPINFOHEADER bih;
+    DWORD colors[256];
+    UINT colorcount=0;
+    LARGE_INTEGER seek;
+    ULONG bytesread;
+    HRESULT hr;
+    BYTE *tempdata = NULL;
+    BYTE *bits = NULL;
+    UINT bitsStride;
+    UINT bitsSize;
+    UINT width, height;
+
+    width = This->entry.bWidth ? This->entry.bWidth : 256;
+    height = This->entry.bHeight ? This->entry.bHeight : 256;
+
+    /* read the BITMAPINFOHEADER */
+    seek.QuadPart = This->entry.dwDIBOffset;
+    hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
+
+    if (This->entry.wBitCount <= 8)
+    {
+        /* read the palette */
+        colorcount = This->entry.bColorCount ? This->entry.bColorCount : 256;
+
+        hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
+        if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
+    }
+
+    bitsStride = width * 4;
+    bitsSize = bitsStride * height;
+
+    /* read the XOR data */
+    switch (This->entry.wBitCount)
+    {
+    case 1:
+    {
+        UINT xorBytesPerRow = (width+31)/32*4;
+        UINT xorBytes = xorBytesPerRow * height;
+        INT xorStride;
+        BYTE *xorRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
+        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            xorStride = -xorBytesPerRow;
+            xorRow = tempdata + (height-1)*xorBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            xorStride = xorBytesPerRow;
+            xorRow = tempdata;
+        }
+
+        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
+
+        /* palette-map the 1-bit data */
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *xorByte=xorRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x+=8) {
+                BYTE xorVal;
+                xorVal=*xorByte++;
+                *bitsPixel++ = colors[xorVal>>7];
+                if (x+1 < width) *bitsPixel++ = colors[xorVal>>6&1];
+                if (x+2 < width) *bitsPixel++ = colors[xorVal>>5&1];
+                if (x+3 < width) *bitsPixel++ = colors[xorVal>>4&1];
+                if (x+4 < width) *bitsPixel++ = colors[xorVal>>3&1];
+                if (x+5 < width) *bitsPixel++ = colors[xorVal>>2&1];
+                if (x+6 < width) *bitsPixel++ = colors[xorVal>>1&1];
+                if (x+7 < width) *bitsPixel++ = colors[xorVal&1];
+            }
+            xorRow += xorStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+        break;
+    }
+    case 4:
+    {
+        UINT xorBytesPerRow = (width+7)/8*4;
+        UINT xorBytes = xorBytesPerRow * height;
+        INT xorStride;
+        BYTE *xorRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
+        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            xorStride = -xorBytesPerRow;
+            xorRow = tempdata + (height-1)*xorBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            xorStride = xorBytesPerRow;
+            xorRow = tempdata;
+        }
+
+        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
+
+        /* palette-map the 4-bit data */
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *xorByte=xorRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x+=2) {
+                BYTE xorVal;
+                xorVal=*xorByte++;
+                *bitsPixel++ = colors[xorVal>>4];
+                if (x+1 < width) *bitsPixel++ = colors[xorVal&0xf];
+            }
+            xorRow += xorStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+        break;
+    }
+    case 8:
+    {
+        UINT xorBytesPerRow = (width+3)/4*4;
+        UINT xorBytes = xorBytesPerRow * height;
+        INT xorStride;
+        BYTE *xorRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
+        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            xorStride = -xorBytesPerRow;
+            xorRow = tempdata + (height-1)*xorBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            xorStride = xorBytesPerRow;
+            xorRow = tempdata;
+        }
+
+        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
+
+        /* palette-map the 8-bit data */
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *xorByte=xorRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x++)
+                *bitsPixel++ = colors[*xorByte++];
+            xorRow += xorStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+        break;
+    }
+    case 24:
+    {
+        UINT xorBytesPerRow = (width*3+3)/4*4;
+        UINT xorBytes = xorBytesPerRow * height;
+        INT xorStride;
+        BYTE *xorRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
+        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            xorStride = -xorBytesPerRow;
+            xorRow = tempdata + (height-1)*xorBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            xorStride = xorBytesPerRow;
+            xorRow = tempdata;
+        }
+
+        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
+
+        /* copy BGR->BGRA */
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *xorByte=xorRow;
+            BYTE *bitsByte=bitsRow;
+            for (x=0; x<width; x++)
+            {
+                *bitsByte++ = *xorByte++; /* blue */
+                *bitsByte++ = *xorByte++; /* green */
+                *bitsByte++ = *xorByte++; /* red */
+                bitsByte++; /* alpha */
+            }
+            xorRow += xorStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+        break;
+    }
+    case 32:
+    {
+        UINT xorBytesPerRow = width*4;
+        UINT xorBytes = xorBytesPerRow * height;
+
+        bits = HeapAlloc(GetProcessHeap(), 0, xorBytes);
+        if (!bits)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            /* read the rows backwards so we get a top-down DIB */
+            UINT i;
+            BYTE *xorRow = bits + xorBytesPerRow * (height-1);
+
+            for (i=0; i<height; i++)
+            {
+                hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread);
+                if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail;
+                xorRow -= xorBytesPerRow;
+            }
+        }
+        else /* top-down DIB */
+        {
+            hr = IStream_Read(This->parent->stream, bits, xorBytes, &bytesread);
+            if (FAILED(hr) || bytesread != xorBytes) goto fail;
+        }
+        break;
+    }
+    default:
+        FIXME("unsupported bitcount: %u\n", This->entry.wBitCount);
+        goto fail;
+    }
+
+    if (This->entry.wBitCount < 32)
+    {
+        /* set alpha data based on the AND mask */
+        UINT andBytesPerRow = (width+31)/32*4;
+        UINT andBytes = andBytesPerRow * height;
+        INT andStride;
+        BYTE *andRow;
+        BYTE *bitsRow;
+        UINT x, y;
+
+        tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
+        if (!tempdata)
+        {
+            hr = E_OUTOFMEMORY;
+            goto fail;
+        }
+
+        hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread);
+        if (FAILED(hr) || bytesread != andBytes) goto fail;
+
+        if (bih.biHeight > 0) /* bottom-up DIB */
+        {
+            andStride = -andBytesPerRow;
+            andRow = tempdata + (height-1)*andBytesPerRow;
+        }
+        else /* top-down DIB */
+        {
+            andStride = andBytesPerRow;
+            andRow = tempdata;
+        }
+
+        bitsRow = bits;
+        for (y=0; y<height; y++) {
+            BYTE *andByte=andRow;
+            DWORD *bitsPixel=(DWORD*)bitsRow;
+            for (x=0; x<width; x+=8) {
+                BYTE andVal=*andByte++;
+                pixel_set_trans(bitsPixel++, andVal>>7&1);
+                if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1);
+                if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1);
+                if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1);
+                if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1);
+                if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1);
+                if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1);
+                if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1);
+            }
+            andRow += andStride;
+            bitsRow += bitsStride;
+        }
+
+        HeapFree(GetProcessHeap(), 0, tempdata);
+    }
+
+    This->bits = bits;
+
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, tempdata);
+    HeapFree(GetProcessHeap(), 0, bits);
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    TRACE("<-- %x\n", hr);
+    return hr;
+}
+
+static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+{
+    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    HRESULT hr;
+    UINT width, height, stride;
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    if (!This->bits)
+    {
+        hr = IcoFrameDecode_ReadPixels(This);
+        if (FAILED(hr)) return hr;
+    }
+
+    width = This->entry.bWidth ? This->entry.bWidth : 256;
+    height = This->entry.bHeight ? This->entry.bHeight : 256;
+    stride = width * 4;
+
+    return copy_pixels(32, This->bits, width, height, stride,
+        prc, cbStride, cbBufferSize, pbBuffer);
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
+    IcoFrameDecode_QueryInterface,
+    IcoFrameDecode_AddRef,
+    IcoFrameDecode_Release,
+    IcoFrameDecode_GetSize,
+    IcoFrameDecode_GetPixelFormat,
+    IcoFrameDecode_GetResolution,
+    IcoFrameDecode_CopyPalette,
+    IcoFrameDecode_CopyPixels,
+    IcoFrameDecode_GetMetadataQueryReader,
+    IcoFrameDecode_GetColorContexts,
+    IcoFrameDecode_GetThumbnail
+};
+
+static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
+    void **ppv)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->stream) IStream_Release(This->stream);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
+    DWORD *pdwCapability)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
+    WICDecodeOptions cacheOptions)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    LARGE_INTEGER seek;
+    HRESULT hr;
+    ULONG bytesread;
+    TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
+
+    if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
+
+    seek.QuadPart = 0;
+    hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
+    if (FAILED(hr)) return hr;
+
+    hr = IStream_Read(pIStream, &This->header, sizeof(ICONHEADER), &bytesread);
+    if (FAILED(hr)) return hr;
+    if (bytesread != sizeof(ICONHEADER) ||
+        This->header.idReserved != 0 ||
+        This->header.idType != 1) return E_FAIL;
+
+    This->initialized = TRUE;
+    This->stream = pIStream;
+    IStream_AddRef(pIStream);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
+    GUID *pguidContainerFormat)
+{
+    FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
+    IWICBitmapDecoderInfo **ppIDecoderInfo)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
+    IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_PALETTEUNAVAILABLE;
+}
+
+static HRESULT WINAPI IcoDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
+{
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcoDecoder_GetPreview(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIBitmapSource)
+{
+    TRACE("(%p,%p)\n", iface, ppIBitmapSource);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcoDecoder_GetColorContexts(IWICBitmapDecoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, ppIThumbnail);
+    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+}
+
+static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
+    UINT *pCount)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    TRACE("(%p,%p)\n", iface, pCount);
+
+    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+
+    *pCount = This->header.idCount;
+    TRACE("<-- %u\n", *pCount);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
+    UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
+{
+    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoFrameDecode *result;
+    LARGE_INTEGER seek;
+    HRESULT hr;
+    ULONG bytesread;
+    TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
+
+    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+
+    if (This->header.idCount < index) return E_INVALIDARG;
+
+    result = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoFrameDecode));
+    if (!result) return E_OUTOFMEMORY;
+
+    result->lpVtbl = &IcoFrameDecode_Vtbl;
+    result->ref = 1;
+    result->parent = This;
+    result->bits = NULL;
+
+    /* read the icon entry */
+    seek.QuadPart = sizeof(ICONHEADER) + sizeof(ICONDIRENTRY) * index;
+    hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
+    if (FAILED(hr)) goto fail;
+
+    hr = IStream_Read(This->stream, &result->entry, sizeof(ICONDIRENTRY), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail;
+
+    IWICBitmapDecoder_AddRef(iface);
+
+    *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
+
+    return S_OK;
+
+fail:
+    HeapFree(GetProcessHeap(), 0, result);
+    if (SUCCEEDED(hr)) hr = E_FAIL;
+    TRACE("<-- %x\n", hr);
+    return hr;
+}
+
+static const IWICBitmapDecoderVtbl IcoDecoder_Vtbl = {
+    IcoDecoder_QueryInterface,
+    IcoDecoder_AddRef,
+    IcoDecoder_Release,
+    IcoDecoder_QueryCapability,
+    IcoDecoder_Initialize,
+    IcoDecoder_GetContainerFormat,
+    IcoDecoder_GetDecoderInfo,
+    IcoDecoder_CopyPalette,
+    IcoDecoder_GetMetadataQueryReader,
+    IcoDecoder_GetPreview,
+    IcoDecoder_GetColorContexts,
+    IcoDecoder_GetThumbnail,
+    IcoDecoder_GetFrameCount,
+    IcoDecoder_GetFrame
+};
+
+HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    IcoDecoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &IcoDecoder_Vtbl;
+    This->ref = 1;
+    This->stream = NULL;
+    This->initialized = FALSE;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/imgfactory.c b/reactos/dll/win32/windowscodecs/imgfactory.c
new file mode 100644 (file)
index 0000000..a98aeb8
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct {
+    const IWICImagingFactoryVtbl    *lpIWICImagingFactoryVtbl;
+    LONG ref;
+} ImagingFactory;
+
+static HRESULT WINAPI ImagingFactory_QueryInterface(IWICImagingFactory *iface, REFIID iid,
+    void **ppv)
+{
+    ImagingFactory *This = (ImagingFactory*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICImagingFactory, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ImagingFactory_AddRef(IWICImagingFactory *iface)
+{
+    ImagingFactory *This = (ImagingFactory*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI ImagingFactory_Release(IWICImagingFactory *iface)
+{
+    ImagingFactory *This = (ImagingFactory*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateDecoderFromFilename(
+    IWICImagingFactory *iface, LPCWSTR wzFilename, const GUID *pguidVendor,
+    DWORD dwDesiredAccess, WICDecodeOptions metadataOptions,
+    IWICBitmapDecoder **ppIDecoder)
+{
+    FIXME("(%p,%s,%s,%u,%u,%p): stub\n", iface, debugstr_w(wzFilename),
+        debugstr_guid(pguidVendor), dwDesiredAccess, metadataOptions, ppIDecoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateDecoderFromStream(
+    IWICImagingFactory *iface, IStream *pIStream, const GUID *pguidVendor,
+    WICDecodeOptions metadataOptions, IWICBitmapDecoder **ppIDecoder)
+{
+    static int fixme=0;
+    IEnumUnknown *enumdecoders;
+    IUnknown *unkdecoderinfo;
+    IWICBitmapDecoderInfo *decoderinfo;
+    IWICBitmapDecoder *decoder=NULL;
+    HRESULT res=S_OK;
+    ULONG num_fetched;
+    BOOL matches;
+
+    TRACE("(%p,%p,%s,%u,%p)\n", iface, pIStream, debugstr_guid(pguidVendor),
+        metadataOptions, ppIDecoder);
+
+    if (pguidVendor && !fixme++)
+        FIXME("ignoring vendor GUID\n");
+
+    res = CreateComponentEnumerator(WICDecoder, WICComponentEnumerateDefault, &enumdecoders);
+    if (FAILED(res)) return res;
+
+    while (!decoder)
+    {
+        res = IEnumUnknown_Next(enumdecoders, 1, &unkdecoderinfo, &num_fetched);
+
+        if (res == S_OK)
+        {
+            res = IUnknown_QueryInterface(unkdecoderinfo, &IID_IWICBitmapDecoderInfo, (void**)&decoderinfo);
+
+            if (SUCCEEDED(res))
+            {
+                res = IWICBitmapDecoderInfo_MatchesPattern(decoderinfo, pIStream, &matches);
+
+                if (SUCCEEDED(res) && matches)
+                {
+                    res = IWICBitmapDecoderInfo_CreateInstance(decoderinfo, &decoder);
+
+                    /* FIXME: should use QueryCapability to choose a decoder */
+
+                    if (SUCCEEDED(res))
+                    {
+                        res = IWICBitmapDecoder_Initialize(decoder, pIStream, metadataOptions);
+
+                        if (FAILED(res))
+                        {
+                            IWICBitmapDecoder_Release(decoder);
+                            decoder = NULL;
+                        }
+                    }
+                }
+
+                IWICBitmapDecoderInfo_Release(decoderinfo);
+            }
+
+            IUnknown_Release(unkdecoderinfo);
+        }
+        else
+            break;
+    }
+
+    IEnumUnknown_Release(enumdecoders);
+
+    if (decoder)
+    {
+        *ppIDecoder = decoder;
+        return S_OK;
+    }
+    else
+    {
+        if (WARN_ON(wincodecs))
+        {
+            LARGE_INTEGER seek;
+            BYTE data[4];
+            ULONG bytesread;
+
+            WARN("failed to load from a stream\n");
+
+            seek.QuadPart = 0;
+            res = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
+            if (SUCCEEDED(res))
+                res = IStream_Read(pIStream, data, 4, &bytesread);
+            if (SUCCEEDED(res))
+                WARN("first %i bytes of stream=%x %x %x %x\n", bytesread, data[0], data[1], data[2], data[3]);
+        }
+        *ppIDecoder = NULL;
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
+    }
+}
+
+static HRESULT WINAPI ImagingFactory_CreateDecoderFromFileHandle(
+    IWICImagingFactory *iface, ULONG_PTR hFile, const GUID *pguidVendor,
+    WICDecodeOptions metadataOptions, IWICBitmapDecoder **ppIDecoder)
+{
+    FIXME("(%p,%lx,%s,%u,%p): stub\n", iface, hFile, debugstr_guid(pguidVendor),
+        metadataOptions, ppIDecoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateComponentInfo(IWICImagingFactory *iface,
+    REFCLSID clsidComponent, IWICComponentInfo **ppIInfo)
+{
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(clsidComponent), ppIInfo);
+    return CreateComponentInfo(clsidComponent, ppIInfo);
+}
+
+static HRESULT WINAPI ImagingFactory_CreateDecoder(IWICImagingFactory *iface,
+    REFGUID guidContainerFormat, const GUID *pguidVendor,
+    IWICBitmapDecoder **ppIDecoder)
+{
+    FIXME("(%p,%s,%s,%p): stub\n", iface, debugstr_guid(guidContainerFormat),
+        debugstr_guid(pguidVendor), ppIDecoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateEncoder(IWICImagingFactory *iface,
+    REFGUID guidContainerFormat, const GUID *pguidVendor,
+    IWICBitmapEncoder **ppIEncoder)
+{
+    FIXME("(%p,%s,%s,%p): stub\n", iface, debugstr_guid(guidContainerFormat),
+        debugstr_guid(pguidVendor), ppIEncoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreatePalette(IWICImagingFactory *iface,
+    IWICPalette **ppIPalette)
+{
+    TRACE("(%p,%p)\n", iface, ppIPalette);
+    return PaletteImpl_Create(ppIPalette);
+}
+
+static HRESULT WINAPI ImagingFactory_CreateFormatConverter(IWICImagingFactory *iface,
+    IWICFormatConverter **ppIFormatConverter)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIFormatConverter);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapScaler(IWICImagingFactory *iface,
+    IWICBitmapScaler **ppIBitmapScaler)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIBitmapScaler);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapClipper(IWICImagingFactory *iface,
+    IWICBitmapClipper **ppIBitmapClipper)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIBitmapClipper);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFlipRotator(IWICImagingFactory *iface,
+    IWICBitmapFlipRotator **ppIBitmapFlipRotator)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIBitmapFlipRotator);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateStream(IWICImagingFactory *iface,
+    IWICStream **ppIWICStream)
+{
+    TRACE("(%p,%p)\n", iface, ppIWICStream);
+    return StreamImpl_Create(ppIWICStream);
+}
+
+static HRESULT WINAPI ImagingFactory_CreateColorContext(IWICImagingFactory *iface,
+    IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateColorTransformer(IWICImagingFactory *iface,
+    IWICColorTransform **ppIColorTransform)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIColorTransform);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmap(IWICImagingFactory *iface,
+    UINT uiWidth, UINT uiHeight, REFWICPixelFormatGUID pixelFormat,
+    WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%u,%u,%s,%u,%p): stub\n", iface, uiWidth, uiHeight,
+        debugstr_guid(pixelFormat), option, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFromSource(IWICImagingFactory *iface,
+    IWICBitmapSource *piBitmapSource, WICBitmapCreateCacheOption option,
+    IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%p,%u,%p): stub\n", iface, piBitmapSource, option, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFromSourceRect(IWICImagingFactory *iface,
+    IWICBitmapSource *piBitmapSource, UINT x, UINT y, UINT width, UINT height,
+    IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%p,%u,%u,%u,%u,%p): stub\n", iface, piBitmapSource, x, y, width,
+        height, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFromMemory(IWICImagingFactory *iface,
+    UINT uiWidth, UINT uiHeight, REFWICPixelFormatGUID pixelFormat, UINT cbStride,
+    UINT cbBufferSize, BYTE *pbBuffer, IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%u,%u,%s,%u,%u,%p,%p): stub\n", iface, uiWidth, uiHeight,
+        debugstr_guid(pixelFormat), cbStride, cbBufferSize, pbBuffer, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFromHBITMAP(IWICImagingFactory *iface,
+    HBITMAP hBitmap, HPALETTE hPalette, WICBitmapAlphaChannelOption options,
+    IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%p,%p,%u,%p): stub\n", iface, hBitmap, hPalette, options, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateBitmapFromHICON(IWICImagingFactory *iface,
+    HICON hIcon, IWICBitmap **ppIBitmap)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, hIcon, ppIBitmap);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateComponentEnumerator(IWICImagingFactory *iface,
+    DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
+{
+    TRACE("(%p,%u,%u,%p)\n", iface, componentTypes, options, ppIEnumUnknown);
+    return CreateComponentEnumerator(componentTypes, options, ppIEnumUnknown);
+}
+
+static HRESULT WINAPI ImagingFactory_CreateFastMetadataEncoderFromDecoder(
+    IWICImagingFactory *iface, IWICBitmapDecoder *pIDecoder,
+    IWICFastMetadataEncoder **ppIFastEncoder)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pIDecoder, ppIFastEncoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateFastMetadataEncoderFromFrameDecode(
+    IWICImagingFactory *iface, IWICBitmapFrameDecode *pIFrameDecoder,
+    IWICFastMetadataEncoder **ppIFastEncoder)
+{
+    FIXME("(%p,%p,%p): stub\n", iface, pIFrameDecoder, ppIFastEncoder);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateQueryWriter(IWICImagingFactory *iface,
+    REFGUID guidMetadataFormat, const GUID *pguidVendor,
+    IWICMetadataQueryWriter **ppIQueryWriter)
+{
+    FIXME("(%p,%s,%s,%p): stub\n", iface, debugstr_guid(guidMetadataFormat),
+        debugstr_guid(pguidVendor), ppIQueryWriter);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ImagingFactory_CreateQueryWriterFromReader(IWICImagingFactory *iface,
+    IWICMetadataQueryReader *pIQueryReader, const GUID *pguidVendor,
+    IWICMetadataQueryWriter **ppIQueryWriter)
+{
+    FIXME("(%p,%p,%s,%p): stub\n", iface, pIQueryReader, debugstr_guid(pguidVendor),
+        ppIQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICImagingFactoryVtbl ImagingFactory_Vtbl = {
+    ImagingFactory_QueryInterface,
+    ImagingFactory_AddRef,
+    ImagingFactory_Release,
+    ImagingFactory_CreateDecoderFromFilename,
+    ImagingFactory_CreateDecoderFromStream,
+    ImagingFactory_CreateDecoderFromFileHandle,
+    ImagingFactory_CreateComponentInfo,
+    ImagingFactory_CreateDecoder,
+    ImagingFactory_CreateEncoder,
+    ImagingFactory_CreatePalette,
+    ImagingFactory_CreateFormatConverter,
+    ImagingFactory_CreateBitmapScaler,
+    ImagingFactory_CreateBitmapClipper,
+    ImagingFactory_CreateBitmapFlipRotator,
+    ImagingFactory_CreateStream,
+    ImagingFactory_CreateColorContext,
+    ImagingFactory_CreateColorTransformer,
+    ImagingFactory_CreateBitmap,
+    ImagingFactory_CreateBitmapFromSource,
+    ImagingFactory_CreateBitmapFromSourceRect,
+    ImagingFactory_CreateBitmapFromMemory,
+    ImagingFactory_CreateBitmapFromHBITMAP,
+    ImagingFactory_CreateBitmapFromHICON,
+    ImagingFactory_CreateComponentEnumerator,
+    ImagingFactory_CreateFastMetadataEncoderFromDecoder,
+    ImagingFactory_CreateFastMetadataEncoderFromFrameDecode,
+    ImagingFactory_CreateQueryWriter,
+    ImagingFactory_CreateQueryWriterFromReader
+};
+
+HRESULT ImagingFactory_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    ImagingFactory *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ImagingFactory));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpIWICImagingFactoryVtbl = &ImagingFactory_Vtbl;
+    This->ref = 1;
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
diff --git a/reactos/dll/win32/windowscodecs/info.c b/reactos/dll/win32/windowscodecs/info.c
new file mode 100644 (file)
index 0000000..a89759b
--- /dev/null
@@ -0,0 +1,1070 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+#include "wine/list.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
+
+typedef struct {
+    const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl;
+    LONG ref;
+    HKEY classkey;
+    CLSID clsid;
+} BitmapDecoderInfo;
+
+static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
+    void **ppv)
+{
+    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICComponentInfo, iid) ||
+        IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
+        IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
+{
+    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
+{
+    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        RegCloseKey(This->classkey);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *iface,
+    WICComponentType *pType)
+{
+    TRACE("(%p,%p)\n", iface, pType);
+    *pType = WICDecoder;
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
+{
+    FIXME("(%p,%p): stub\n", iface, pclsid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
+{
+    FIXME("(%p,%p): stub\n", iface, pStatus);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
+    WCHAR *wzAuthor, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
+{
+    FIXME("(%p,%p): stub\n", iface, pguidVendor);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
+    WCHAR *wzVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
+    WCHAR *wzSpecVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
+    WCHAR *wzFriendlyName, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
+    GUID *pguidContainerFormat)
+{
+    FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
+    UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
+    UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetDeviceManufacturer(IWICBitmapDecoderInfo *iface,
+    UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *iface,
+    UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
+    UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
+    UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
+    BOOL *pfSupportAnimation)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_DoesSupportChromaKey(IWICBitmapDecoderInfo *iface,
+    BOOL *pfSupportChromaKey)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_DoesSupportLossless(IWICBitmapDecoderInfo *iface,
+    BOOL *pfSupportLossless)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_DoesSupportMultiframe(IWICBitmapDecoderInfo *iface,
+    BOOL *pfSupportMultiframe)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *iface,
+    LPCWSTR wzMimeType, BOOL *pfMatches)
+{
+    FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
+    UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
+{
+    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    UINT pattern_count=0, patterns_size=0;
+    WCHAR subkeyname[11];
+    LONG res;
+    HKEY patternskey, patternkey;
+    static const WCHAR uintformatW[] = {'%','u',0};
+    static const WCHAR patternsW[] = {'P','a','t','t','e','r','n','s',0};
+    static const WCHAR positionW[] = {'P','o','s','i','t','i','o','n',0};
+    static const WCHAR lengthW[] = {'L','e','n','g','t','h',0};
+    static const WCHAR patternW[] = {'P','a','t','t','e','r','n',0};
+    static const WCHAR maskW[] = {'M','a','s','k',0};
+    static const WCHAR endofstreamW[] = {'E','n','d','O','f','S','t','r','e','a','m',0};
+    HRESULT hr=S_OK;
+    UINT i;
+    BYTE *bPatterns=(BYTE*)pPatterns;
+    DWORD length, valuesize;
+
+    TRACE("(%p,%i,%p,%p,%p)\n", iface, cbSizePatterns, pPatterns, pcPatterns, pcbPatternsActual);
+
+    res = RegOpenKeyExW(This->classkey, patternsW, 0, KEY_READ, &patternskey);
+    if (res != ERROR_SUCCESS) return HRESULT_FROM_WIN32(res);
+
+    res = RegQueryInfoKeyW(patternskey, NULL, NULL, NULL, &pattern_count, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    if (res == ERROR_SUCCESS)
+    {
+        patterns_size = pattern_count * sizeof(WICBitmapPattern);
+
+        for (i=0; i<pattern_count; i++)
+        {
+            snprintfW(subkeyname, 11, uintformatW, i);
+            res = RegOpenKeyExW(patternskey, subkeyname, 0, KEY_READ, &patternkey);
+            if (res == ERROR_SUCCESS)
+            {
+                valuesize = sizeof(ULONG);
+                res = RegGetValueW(patternkey, NULL, lengthW, RRF_RT_DWORD, NULL,
+                    &length, &valuesize);
+                patterns_size += length*2;
+
+                if ((cbSizePatterns >= patterns_size) && (res == ERROR_SUCCESS))
+                {
+                    pPatterns[i].Length = length;
+
+                    pPatterns[i].EndOfStream = 0;
+                    valuesize = sizeof(BOOL);
+                    RegGetValueW(patternkey, NULL, endofstreamW, RRF_RT_DWORD, NULL,
+                        &pPatterns[i].EndOfStream, &valuesize);
+
+                    pPatterns[i].Position.QuadPart = 0;
+                    valuesize = sizeof(ULARGE_INTEGER);
+                    res = RegGetValueW(patternkey, NULL, positionW, RRF_RT_DWORD|RRF_RT_QWORD, NULL,
+                        &pPatterns[i].Position, &valuesize);
+
+                    if (res == ERROR_SUCCESS)
+                    {
+                        pPatterns[i].Pattern = bPatterns+patterns_size-length*2;
+                        valuesize = length;
+                        res = RegGetValueW(patternkey, NULL, patternW, RRF_RT_REG_BINARY, NULL,
+                            pPatterns[i].Pattern, &valuesize);
+                    }
+
+                    if (res == ERROR_SUCCESS)
+                    {
+                        pPatterns[i].Mask = bPatterns+patterns_size-length;
+                        valuesize = length;
+                        res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
+                            pPatterns[i].Mask, &valuesize);
+                    }
+                }
+
+                RegCloseKey(patternkey);
+            }
+            if (res != ERROR_SUCCESS)
+            {
+                hr = HRESULT_FROM_WIN32(res);
+                break;
+            }
+        }
+    }
+    else hr = HRESULT_FROM_WIN32(res);
+
+    RegCloseKey(patternskey);
+
+    if (hr == S_OK)
+    {
+        *pcPatterns = pattern_count;
+        *pcbPatternsActual = patterns_size;
+        if (pPatterns && cbSizePatterns < patterns_size)
+            hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
+    IStream *pIStream, BOOL *pfMatches)
+{
+    WICBitmapPattern *patterns;
+    UINT pattern_count=0, patterns_size=0;
+    HRESULT hr;
+    int i, pos;
+    BYTE *data=NULL;
+    ULONG datasize=0;
+    ULONG bytesread;
+    LARGE_INTEGER seekpos;
+
+    TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
+
+    hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
+    if (FAILED(hr)) return hr;
+
+    patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
+    if (!patterns) return E_OUTOFMEMORY;
+
+    hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
+    if (FAILED(hr)) goto end;
+
+    for (i=0; i<pattern_count; i++)
+    {
+        if (datasize < patterns[i].Length)
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            datasize = patterns[i].Length;
+            data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
+            if (!data)
+            {
+                hr = E_OUTOFMEMORY;
+                break;
+            }
+        }
+
+        if (patterns[i].EndOfStream)
+            seekpos.QuadPart = -patterns[i].Position.QuadPart;
+        else
+            seekpos.QuadPart = patterns[i].Position.QuadPart;
+        hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
+        if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
+        if (FAILED(hr)) break;
+
+        hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
+        if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
+            continue;
+        if (FAILED(hr)) break;
+
+        for (pos=0; pos<patterns[i].Length; pos++)
+        {
+            if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
+                break;
+        }
+        if (pos == patterns[i].Length) /* matches pattern */
+        {
+            hr = S_OK;
+            *pfMatches = TRUE;
+            break;
+        }
+    }
+
+    if (i == pattern_count) /* does not match any pattern */
+    {
+        hr = S_OK;
+        *pfMatches = FALSE;
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, patterns);
+    HeapFree(GetProcessHeap(), 0, data);
+
+    return hr;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
+    IWICBitmapDecoder **ppIBitmapDecoder)
+{
+    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+
+    TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
+
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
+}
+
+static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
+    BitmapDecoderInfo_QueryInterface,
+    BitmapDecoderInfo_AddRef,
+    BitmapDecoderInfo_Release,
+    BitmapDecoderInfo_GetComponentType,
+    BitmapDecoderInfo_GetCLSID,
+    BitmapDecoderInfo_GetSigningStatus,
+    BitmapDecoderInfo_GetAuthor,
+    BitmapDecoderInfo_GetVendorGUID,
+    BitmapDecoderInfo_GetVersion,
+    BitmapDecoderInfo_GetSpecVersion,
+    BitmapDecoderInfo_GetFriendlyName,
+    BitmapDecoderInfo_GetContainerFormat,
+    BitmapDecoderInfo_GetPixelFormats,
+    BitmapDecoderInfo_GetColorManagementVersion,
+    BitmapDecoderInfo_GetDeviceManufacturer,
+    BitmapDecoderInfo_GetDeviceModels,
+    BitmapDecoderInfo_GetMimeTypes,
+    BitmapDecoderInfo_GetFileExtensions,
+    BitmapDecoderInfo_DoesSupportAnimation,
+    BitmapDecoderInfo_DoesSupportChromaKey,
+    BitmapDecoderInfo_DoesSupportLossless,
+    BitmapDecoderInfo_DoesSupportMultiframe,
+    BitmapDecoderInfo_MatchesMimeType,
+    BitmapDecoderInfo_GetPatterns,
+    BitmapDecoderInfo_MatchesPattern,
+    BitmapDecoderInfo_CreateInstance
+};
+
+static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    BitmapDecoderInfo *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
+    if (!This)
+    {
+        RegCloseKey(classkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl;
+    This->ref = 1;
+    This->classkey = classkey;
+    memcpy(&This->clsid, clsid, sizeof(CLSID));
+
+    *ppIInfo = (IWICComponentInfo*)This;
+    return S_OK;
+}
+
+typedef struct {
+    const IWICFormatConverterInfoVtbl *lpIWICFormatConverterInfoVtbl;
+    LONG ref;
+    HKEY classkey;
+    CLSID clsid;
+} FormatConverterInfo;
+
+static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
+    void **ppv)
+{
+    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICComponentInfo, iid) ||
+        IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
+{
+    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
+{
+    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        RegCloseKey(This->classkey);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
+    WICComponentType *pType)
+{
+    TRACE("(%p,%p)\n", iface, pType);
+    *pType = WICPixelFormatConverter;
+    return S_OK;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
+{
+    FIXME("(%p,%p): stub\n", iface, pclsid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
+{
+    FIXME("(%p,%p): stub\n", iface, pStatus);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
+    WCHAR *wzAuthor, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
+{
+    FIXME("(%p,%p): stub\n", iface, pguidVendor);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
+    WCHAR *wzVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
+    WCHAR *wzSpecVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
+    WCHAR *wzFriendlyName, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
+    UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
+    IWICFormatConverter **ppIFormatConverter)
+{
+    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+
+    TRACE("(%p,%p)\n", iface, ppIFormatConverter);
+
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICFormatConverter, (void**)ppIFormatConverter);
+}
+
+static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
+{
+    LONG res;
+    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    HKEY formats_key, guid_key;
+
+    /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
+        would be O(n). A registry test should do better. */
+
+    res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
+    if (res != ERROR_SUCCESS) return FALSE;
+
+    res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
+    if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
+
+    RegCloseKey(formats_key);
+
+    return (res == ERROR_SUCCESS);
+}
+
+static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
+    FormatConverterInfo_QueryInterface,
+    FormatConverterInfo_AddRef,
+    FormatConverterInfo_Release,
+    FormatConverterInfo_GetComponentType,
+    FormatConverterInfo_GetCLSID,
+    FormatConverterInfo_GetSigningStatus,
+    FormatConverterInfo_GetAuthor,
+    FormatConverterInfo_GetVendorGUID,
+    FormatConverterInfo_GetVersion,
+    FormatConverterInfo_GetSpecVersion,
+    FormatConverterInfo_GetFriendlyName,
+    FormatConverterInfo_GetPixelFormats,
+    FormatConverterInfo_CreateInstance
+};
+
+static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    FormatConverterInfo *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
+    if (!This)
+    {
+        RegCloseKey(classkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->lpIWICFormatConverterInfoVtbl = &FormatConverterInfo_Vtbl;
+    This->ref = 1;
+    This->classkey = classkey;
+    memcpy(&This->clsid, clsid, sizeof(CLSID));
+
+    *ppIInfo = (IWICComponentInfo*)This;
+    return S_OK;
+}
+
+static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0};
+static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
+
+struct category {
+    WICComponentType type;
+    const GUID *catid;
+    HRESULT (*constructor)(HKEY,REFCLSID,IWICComponentInfo**);
+};
+
+static const struct category categories[] = {
+    {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
+    {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
+    {0}
+};
+
+HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    HKEY clsidkey;
+    HKEY classkey;
+    HKEY catidkey;
+    HKEY instancekey;
+    WCHAR guidstring[39];
+    LONG res;
+    const struct category *category;
+    int found=0;
+    HRESULT hr;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
+    if (res != ERROR_SUCCESS)
+        return HRESULT_FROM_WIN32(res);
+
+    for (category=categories; category->type; category++)
+    {
+        StringFromGUID2(category->catid, guidstring, 39);
+        res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
+            if (res == ERROR_SUCCESS)
+            {
+                StringFromGUID2(clsid, guidstring, 39);
+                res = RegOpenKeyExW(instancekey, guidstring, 0, KEY_READ, &classkey);
+                if (res == ERROR_SUCCESS)
+                {
+                    RegCloseKey(classkey);
+                    found = 1;
+                }
+                RegCloseKey(instancekey);
+            }
+            RegCloseKey(catidkey);
+        }
+        if (found) break;
+    }
+
+    if (found)
+    {
+        res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &classkey);
+        if (res == ERROR_SUCCESS)
+            hr = category->constructor(classkey, clsid, ppIInfo);
+        else
+            hr = HRESULT_FROM_WIN32(res);
+    }
+    else
+        hr = E_FAIL;
+
+    RegCloseKey(clsidkey);
+
+    return hr;
+}
+
+typedef struct {
+    const IEnumUnknownVtbl *IEnumUnknown_Vtbl;
+    LONG ref;
+    struct list objects;
+    struct list *cursor;
+} ComponentEnum;
+
+typedef struct {
+    struct list entry;
+    IUnknown *unk;
+} ComponentEnumItem;
+
+static const IEnumUnknownVtbl ComponentEnumVtbl;
+
+static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
+    void **ppv)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+    ComponentEnumItem *cursor, *cursor2;
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &This->objects, ComponentEnumItem, entry)
+        {
+            IUnknown_Release(cursor->unk);
+            list_remove(&cursor->entry);
+            HeapFree(GetProcessHeap(), 0, cursor);
+        }
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
+    IUnknown **rgelt, ULONG *pceltFetched)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    int num_fetched=0;
+    ComponentEnumItem *item;
+
+    TRACE("(%p,%u,%p,%p)\n", iface, celt, rgelt, pceltFetched);
+
+    while (num_fetched<celt)
+    {
+        if (!This->cursor)
+        {
+            *pceltFetched = num_fetched;
+            return S_FALSE;
+        }
+        item = LIST_ENTRY(This->cursor, ComponentEnumItem, entry);
+        IUnknown_AddRef(item->unk);
+        rgelt[num_fetched] = item->unk;
+        num_fetched++;
+        This->cursor = list_next(&This->objects, This->cursor);
+    }
+    *pceltFetched = num_fetched;
+    return S_OK;
+}
+
+static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    int i;
+
+    TRACE("(%p,%u)\n", iface, celt);
+
+    for (i=0; i<celt; i++)
+    {
+        if (!This->cursor)
+            return S_FALSE;
+        This->cursor = list_next(&This->objects, This->cursor);
+    }
+    return S_OK;
+}
+
+static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+
+    TRACE("(%p)\n", iface);
+
+    This->cursor = list_head(&This->objects);
+    return S_OK;
+}
+
+static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
+{
+    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *new_enum;
+    ComponentEnumItem *old_item, *new_item;
+    HRESULT ret=S_OK;
+
+    new_enum = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
+    if (!new_enum)
+    {
+        *ppenum = NULL;
+        return E_OUTOFMEMORY;
+    }
+
+    new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
+    new_enum->ref = 1;
+    new_enum->cursor = NULL;
+
+    list_init(&new_enum->objects);
+    LIST_FOR_EACH_ENTRY(old_item, &This->objects, ComponentEnumItem, entry)
+    {
+        new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
+        if (!new_item)
+        {
+            ret = E_OUTOFMEMORY;
+            break;
+        }
+        new_item->unk = old_item->unk;
+        list_add_tail(&new_enum->objects, &new_item->entry);
+        IUnknown_AddRef(new_item->unk);
+        if (&old_item->entry == This->cursor) new_enum->cursor = &new_item->entry;
+    }
+
+    if (FAILED(ret))
+    {
+        IUnknown_Release((IUnknown*)new_enum);
+        *ppenum = NULL;
+    }
+    else
+        *ppenum = (IEnumUnknown*)new_enum;
+
+    return ret;
+}
+
+static const IEnumUnknownVtbl ComponentEnumVtbl = {
+    ComponentEnum_QueryInterface,
+    ComponentEnum_AddRef,
+    ComponentEnum_Release,
+    ComponentEnum_Next,
+    ComponentEnum_Skip,
+    ComponentEnum_Reset,
+    ComponentEnum_Clone
+};
+
+HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
+{
+    ComponentEnum *This;
+    ComponentEnumItem *item;
+    const struct category *category;
+    HKEY clsidkey, catidkey, instancekey;
+    WCHAR guidstring[39];
+    LONG res;
+    int i;
+    HRESULT hr=S_OK;
+    CLSID clsid;
+
+    if (options) FIXME("ignoring flags %x\n", options);
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, KEY_READ, &clsidkey);
+    if (res != ERROR_SUCCESS)
+        return HRESULT_FROM_WIN32(res);
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnum));
+    if (!This)
+    {
+        RegCloseKey(clsidkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
+    This->ref = 1;
+    list_init(&This->objects);
+
+    for (category=categories; category->type && hr == S_OK; category++)
+    {
+        if ((category->type & componentTypes) == 0) continue;
+        StringFromGUID2(category->catid, guidstring, 39);
+        res = RegOpenKeyExW(clsidkey, guidstring, 0, KEY_READ, &catidkey);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegOpenKeyExW(catidkey, instance_keyname, 0, KEY_READ, &instancekey);
+            if (res == ERROR_SUCCESS)
+            {
+                i=0;
+                for (;;i++)
+                {
+                    DWORD guidstring_size = 39;
+                    res = RegEnumKeyExW(instancekey, i, guidstring, &guidstring_size, NULL, NULL, NULL, NULL);
+                    if (res != ERROR_SUCCESS) break;
+
+                    item = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentEnumItem));
+                    if (!item) { hr = E_OUTOFMEMORY; break; }
+
+                    hr = CLSIDFromString(guidstring, &clsid);
+                    if (SUCCEEDED(hr))
+                    {
+                        hr = CreateComponentInfo(&clsid, (IWICComponentInfo**)&item->unk);
+                        if (SUCCEEDED(hr))
+                            list_add_tail(&This->objects, &item->entry);
+                    }
+
+                    if (!SUCCEEDED(hr))
+                    {
+                        HeapFree(GetProcessHeap(), 0, item);
+                        hr = S_OK;
+                    }
+                }
+                RegCloseKey(instancekey);
+            }
+            RegCloseKey(catidkey);
+        }
+        if (res != ERROR_SUCCESS && res != ERROR_NO_MORE_ITEMS)
+            hr = HRESULT_FROM_WIN32(res);
+    }
+    RegCloseKey(clsidkey);
+
+    if (SUCCEEDED(hr))
+    {
+        IEnumUnknown_Reset((IEnumUnknown*)This);
+        *ppIEnumUnknown = (IEnumUnknown*)This;
+    }
+    else
+    {
+        *ppIEnumUnknown = NULL;
+        IUnknown_Release((IUnknown*)This);
+    }
+
+    return hr;
+}
+
+HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst)
+{
+    HRESULT res;
+    IEnumUnknown *enumconverters;
+    IUnknown *unkconverterinfo;
+    IWICFormatConverterInfo *converterinfo=NULL;
+    IWICFormatConverter *converter=NULL;
+    GUID srcFormat;
+    WCHAR srcformatstr[39], dstformatstr[39];
+    BOOL canconvert;
+    ULONG num_fetched;
+
+    res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat);
+    if (FAILED(res)) return res;
+
+    if (IsEqualGUID(&srcFormat, dstFormat))
+    {
+        IWICBitmapSource_AddRef(pISrc);
+        *ppIDst = pISrc;
+        return S_OK;
+    }
+
+    StringFromGUID2(&srcFormat, srcformatstr, 39);
+    StringFromGUID2(dstFormat, dstformatstr, 39);
+
+    res = CreateComponentEnumerator(WICPixelFormatConverter, 0, &enumconverters);
+    if (FAILED(res)) return res;
+
+    while (!converter)
+    {
+        res = IEnumUnknown_Next(enumconverters, 1, &unkconverterinfo, &num_fetched);
+
+        if (res == S_OK)
+        {
+            res = IUnknown_QueryInterface(unkconverterinfo, &IID_IWICFormatConverterInfo, (void**)&converterinfo);
+
+            if (SUCCEEDED(res))
+            {
+                canconvert = ConverterSupportsFormat(converterinfo, srcformatstr);
+
+                if (canconvert)
+                    canconvert = ConverterSupportsFormat(converterinfo, dstformatstr);
+
+                if (canconvert)
+                {
+                    res = IWICFormatConverterInfo_CreateInstance(converterinfo, &converter);
+
+                    if (SUCCEEDED(res))
+                        res = IWICFormatConverter_CanConvert(converter, &srcFormat, dstFormat, &canconvert);
+
+                    if (SUCCEEDED(res) && canconvert)
+                        res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone,
+                            NULL, 0.0, WICBitmapPaletteTypeCustom);
+
+                    if (FAILED(res) || !canconvert)
+                    {
+                        if (converter)
+                        {
+                            IWICFormatConverter_Release(converter);
+                            converter = NULL;
+                        }
+                        res = S_OK;
+                    }
+                }
+
+                IWICFormatConverterInfo_Release(converterinfo);
+            }
+
+            IUnknown_Release(unkconverterinfo);
+        }
+        else
+            break;
+    }
+
+    IEnumUnknown_Release(enumconverters);
+
+    if (converter)
+    {
+        *ppIDst = (IWICBitmapSource*)converter;
+        return S_OK;
+    }
+    else
+    {
+        *ppIDst = NULL;
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
+    }
+}
diff --git a/reactos/dll/win32/windowscodecs/main.c b/reactos/dll/win32/windowscodecs/main.c
new file mode 100644 (file)
index 0000000..7ec5d41
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+
+    switch (fdwReason)
+    {
+        case DLL_WINE_PREATTACH:
+            return FALSE;    /* prefer native version */
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hinstDLL);
+            break;
+        case DLL_PROCESS_DETACH:
+            break;
+    }
+
+    return TRUE;
+}
+
+HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
+    UINT srcwidth, UINT srcheight, INT srcstride,
+    const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
+{
+    UINT bytesperrow;
+    UINT row_offset; /* number of bits into the source rows where the data starts */
+
+    if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
+        return E_INVALIDARG;
+
+    bytesperrow = ((bpp * rc->Width)+7)/8;
+
+    if (dststride < bytesperrow)
+        return E_INVALIDARG;
+
+    if ((dststride * rc->Height) > dstbuffersize)
+        return E_INVALIDARG;
+
+    row_offset = rc->X * bpp;
+
+    if (row_offset % 8 == 0)
+    {
+        /* everything lines up on a byte boundary */
+        UINT row;
+        const BYTE *src;
+        BYTE *dst;
+
+        src = srcbuffer + (row_offset / 8) + srcstride * rc->Y;
+        dst = dstbuffer;
+        for (row=0; row < rc->Height; row++)
+        {
+            memcpy(dst, src, bytesperrow);
+            src += srcstride;
+            dst += dststride;
+        }
+        return S_OK;
+    }
+    else
+    {
+        /* we have to do a weird bitwise copy. eww. */
+        FIXME("cannot reliably copy bitmap data if bpp < 8\n");
+        return E_FAIL;
+    }
+}
diff --git a/reactos/dll/win32/windowscodecs/palette.c b/reactos/dll/win32/windowscodecs/palette.c
new file mode 100644 (file)
index 0000000..842d3b5
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct {
+    const IWICPaletteVtbl *lpIWICPaletteVtbl;
+    LONG ref;
+    UINT count;
+    WICColor *colors;
+    WICBitmapPaletteType type;
+} PaletteImpl;
+
+static HRESULT WINAPI PaletteImpl_QueryInterface(IWICPalette *iface, REFIID iid,
+    void **ppv)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICPalette, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI PaletteImpl_AddRef(IWICPalette *iface)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI PaletteImpl_Release(IWICPalette *iface)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This->colors);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI PaletteImpl_InitializePredefined(IWICPalette *iface,
+    WICBitmapPaletteType ePaletteType, BOOL fAddTransparentColor)
+{
+    FIXME("(%p,%u,%i): stub\n", iface, ePaletteType, fAddTransparentColor);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PaletteImpl_InitializeCustom(IWICPalette *iface,
+    WICColor *pColors, UINT colorCount)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+    WICColor *new_colors;
+
+    TRACE("(%p,%p,%u)\n", iface, pColors, colorCount);
+
+    if (colorCount == 0)
+    {
+        new_colors = NULL;
+    }
+    else
+    {
+        if (!pColors) return E_INVALIDARG;
+        new_colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * colorCount);
+        if (!new_colors) return E_OUTOFMEMORY;
+        memcpy(new_colors, pColors, sizeof(WICColor) * colorCount);
+    }
+
+    HeapFree(GetProcessHeap(), 0, This->colors);
+    This->colors = new_colors;
+    This->count = colorCount;
+    This->type = WICBitmapPaletteTypeCustom;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *iface,
+    IWICBitmapSource *pISurface, UINT colorCount, BOOL fAddTransparentColor)
+{
+    FIXME("(%p,%p,%u,%i): stub\n", iface, pISurface, colorCount, fAddTransparentColor);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PaletteImpl_InitializeFromPalette(IWICPalette *iface,
+    IWICPalette *pIPalette)
+{
+    FIXME("(%p,%p): stub\n", iface, pIPalette);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PaletteImpl_GetType(IWICPalette *iface,
+    WICBitmapPaletteType *pePaletteType)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+
+    TRACE("(%p,%p)\n", iface, pePaletteType);
+
+    if (!pePaletteType) return E_INVALIDARG;
+
+    *pePaletteType = This->type;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_GetColorCount(IWICPalette *iface, UINT *pcCount)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+
+    TRACE("(%p,%p)\n", iface, pcCount);
+
+    if (!pcCount) return E_INVALIDARG;
+
+    *pcCount = This->count;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_GetColors(IWICPalette *iface, UINT colorCount,
+    WICColor *pColors, UINT *pcActualColors)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+
+    TRACE("(%p,%i,%p,%p)\n", iface, colorCount, pColors, pcActualColors);
+
+    if (!pColors || !pcActualColors) return E_INVALIDARG;
+
+    if (This->count < colorCount) colorCount = This->count;
+
+    memcpy(pColors, This->colors, sizeof(WICColor) * colorCount);
+
+    *pcActualColors = colorCount;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_IsBlackWhite(IWICPalette *iface, BOOL *pfIsBlackWhite)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+
+    TRACE("(%p,%p)\n", iface, pfIsBlackWhite);
+
+    if (!pfIsBlackWhite) return E_INVALIDARG;
+
+    if (This->type == WICBitmapPaletteTypeFixedBW)
+        *pfIsBlackWhite = TRUE;
+    else
+        *pfIsBlackWhite = FALSE;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_IsGrayscale(IWICPalette *iface, BOOL *pfIsGrayscale)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+
+    TRACE("(%p,%p)\n", iface, pfIsGrayscale);
+
+    if (!pfIsGrayscale) return E_INVALIDARG;
+
+    switch(This->type)
+    {
+        case WICBitmapPaletteTypeFixedBW:
+        case WICBitmapPaletteTypeFixedGray4:
+        case WICBitmapPaletteTypeFixedGray16:
+        case WICBitmapPaletteTypeFixedGray256:
+            *pfIsGrayscale = TRUE;
+            break;
+        default:
+            *pfIsGrayscale = FALSE;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PaletteImpl_HasAlpha(IWICPalette *iface, BOOL *pfHasAlpha)
+{
+    PaletteImpl *This = (PaletteImpl*)iface;
+    int i;
+
+    TRACE("(%p,%p)\n", iface, pfHasAlpha);
+
+    if (!pfHasAlpha) return E_INVALIDARG;
+
+    *pfHasAlpha = FALSE;
+
+    for (i=0; i<This->count; i++)
+        if ((This->colors[i]&0xff000000) != 0xff000000)
+        {
+            *pfHasAlpha = TRUE;
+            break;
+        }
+
+    return S_OK;
+}
+
+static const IWICPaletteVtbl PaletteImpl_Vtbl = {
+    PaletteImpl_QueryInterface,
+    PaletteImpl_AddRef,
+    PaletteImpl_Release,
+    PaletteImpl_InitializePredefined,
+    PaletteImpl_InitializeCustom,
+    PaletteImpl_InitializeFromBitmap,
+    PaletteImpl_InitializeFromPalette,
+    PaletteImpl_GetType,
+    PaletteImpl_GetColorCount,
+    PaletteImpl_GetColors,
+    PaletteImpl_IsBlackWhite,
+    PaletteImpl_IsGrayscale,
+    PaletteImpl_HasAlpha
+};
+
+HRESULT PaletteImpl_Create(IWICPalette **palette)
+{
+    PaletteImpl *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(PaletteImpl));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpIWICPaletteVtbl = &PaletteImpl_Vtbl;
+    This->ref = 1;
+    This->count = 0;
+    This->colors = NULL;
+    This->type = WICBitmapPaletteTypeCustom;
+
+    *palette = (IWICPalette*)This;
+
+    return S_OK;
+}
diff --git a/reactos/dll/win32/windowscodecs/propertybag.c b/reactos/dll/win32/windowscodecs/propertybag.c
new file mode 100644 (file)
index 0000000..ca40b3b
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct PropertyBag {
+    const IPropertyBag2Vtbl *lpVtbl;
+    LONG ref;
+} PropertyBag;
+
+static HRESULT WINAPI PropertyBag_QueryInterface(IPropertyBag2 *iface, REFIID iid,
+    void **ppv)
+{
+    PropertyBag *This = (PropertyBag*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IPropertyBag2, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI PropertyBag_AddRef(IPropertyBag2 *iface)
+{
+    PropertyBag *This = (PropertyBag*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI PropertyBag_Release(IPropertyBag2 *iface)
+{
+    PropertyBag *This = (PropertyBag*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI PropertyBag_Read(IPropertyBag2 *iface, ULONG cProperties,
+    PROPBAG2 *pPropBag, IErrorLog *pErrLog, VARIANT *pvarValue, HRESULT *phrError)
+{
+    FIXME("(%p,%u,%p,%p,%p,%p): stub\n", iface, cProperties, pPropBag, pErrLog, pvarValue, phrError);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyBag_Write(IPropertyBag2 *iface, ULONG cProperties,
+    PROPBAG2 *pPropBag, VARIANT *pvarValue)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cProperties, pPropBag, pvarValue);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyBag_CountProperties(IPropertyBag2 *iface, ULONG *pcProperties)
+{
+    FIXME("(%p,%p): stub\n", iface, pcProperties);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyBag_GetPropertyInfo(IPropertyBag2 *iface, ULONG iProperty,
+    ULONG cProperties, PROPBAG2 *pPropBag, ULONG *pcProperties)
+{
+    FIXME("(%p,%u,%u,%p,%p): stub\n", iface, iProperty, cProperties, pPropBag, pcProperties);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyBag_LoadObject(IPropertyBag2 *iface, LPCOLESTR pstrName,
+    DWORD dwHint, IUnknown *pUnkObject, IErrorLog *pErrLog)
+{
+    FIXME("(%p,%s,%u,%p,%p): stub\n", iface, debugstr_w(pstrName), dwHint, pUnkObject, pErrLog);
+    return E_NOTIMPL;
+}
+
+static const IPropertyBag2Vtbl PropertyBag_Vtbl = {
+    PropertyBag_QueryInterface,
+    PropertyBag_AddRef,
+    PropertyBag_Release,
+    PropertyBag_Read,
+    PropertyBag_Write,
+    PropertyBag_CountProperties,
+    PropertyBag_GetPropertyInfo,
+    PropertyBag_LoadObject
+};
+
+extern HRESULT CreatePropertyBag2(IPropertyBag2 **ppPropertyBag2)
+{
+    PropertyBag *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyBag));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->lpVtbl = &PropertyBag_Vtbl;
+    This->ref = 1;
+
+    *ppPropertyBag2 = (IPropertyBag2*)This;
+
+    return S_OK;
+}
diff --git a/reactos/dll/win32/windowscodecs/regsvr.c b/reactos/dll/win32/windowscodecs/regsvr.c
new file mode 100644 (file)
index 0000000..b931b19
--- /dev/null
@@ -0,0 +1,899 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+#define COBJMACROS
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "objbase.h"
+#include "ocidl.h"
+#include "wincodec.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+/***********************************************************************
+ *             interface for self-registering
+ */
+struct regsvr_coclass
+{
+    CLSID const *clsid;                /* NULL for end of list */
+    LPCSTR name;               /* can be NULL to omit */
+    LPCSTR ips;                        /* can be NULL to omit */
+    LPCSTR ips32;              /* can be NULL to omit */
+    LPCSTR ips32_tmodel;       /* can be NULL to omit */
+    LPCSTR progid;             /* can be NULL to omit */
+    LPCSTR viprogid;           /* can be NULL to omit */
+    LPCSTR progid_extra;       /* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+struct decoder_pattern
+{
+    DWORD length;    /* 0 for end of list */
+    DWORD position;
+    const BYTE *pattern;
+    const BYTE *mask;
+    DWORD endofstream;
+};
+
+struct regsvr_decoder
+{
+    CLSID const *clsid;         /* NULL for end of list */
+    LPCSTR author;
+    LPCSTR friendlyname;
+    LPCSTR version;
+    GUID const *vendor;
+    LPCSTR mimetypes;
+    LPCSTR extensions;
+    GUID const * const *formats;
+    const struct decoder_pattern *patterns;
+};
+
+static HRESULT register_decoders(struct regsvr_decoder const *list);
+static HRESULT unregister_decoders(struct regsvr_decoder const *list);
+
+struct regsvr_converter
+{
+    CLSID const *clsid;         /* NULL for end of list */
+    LPCSTR author;
+    LPCSTR friendlyname;
+    LPCSTR version;
+    GUID const *vendor;
+    GUID const * const *formats;
+};
+
+static HRESULT register_converters(struct regsvr_converter const *list);
+static HRESULT unregister_converters(struct regsvr_converter const *list);
+
+/***********************************************************************
+ *             static string constants
+ */
+static WCHAR const clsid_keyname[6] = {
+    'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+    'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const ips_keyname[13] = {
+    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+    0 };
+static WCHAR const ips32_keyname[15] = {
+    'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+    '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+    'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+    'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+    'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+    0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+static char const author_valuename[] = "Author";
+static char const friendlyname_valuename[] = "FriendlyName";
+static WCHAR const vendor_valuename[] = {'V','e','n','d','o','r',0};
+static char const version_valuename[] = "Version";
+static char const mimetypes_valuename[] = "MimeTypes";
+static char const extensions_valuename[] = "FileExtensions";
+static WCHAR const formats_keyname[] = {'F','o','r','m','a','t','s',0};
+static WCHAR const patterns_keyname[] = {'P','a','t','t','e','r','n','s',0};
+static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
+static WCHAR const clsid_valuename[] = {'C','L','S','I','D',0};
+static char const length_valuename[] = "Length";
+static char const position_valuename[] = "Position";
+static char const pattern_valuename[] = "Pattern";
+static char const mask_valuename[] = "Mask";
+static char const endofstream_valuename[] = "EndOfStream";
+static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
+
+/***********************************************************************
+ *             static helper functions
+ */
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+                                  WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+                                  char const *value);
+static LONG register_progid(WCHAR const *clsid,
+                           char const *progid, char const *curver_progid,
+                           char const *name, char const *extra);
+
+/***********************************************************************
+ *             register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       WCHAR buf[39];
+       HKEY clsid_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       if (list->name) {
+           res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+                                (CONST BYTE*)(list->name),
+                                strlen(list->name) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       }
+
+       if (list->ips) {
+           res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       }
+
+       if (list->ips32) {
+           HKEY ips32_key;
+
+           res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+                                 KEY_READ | KEY_WRITE, NULL,
+                                 &ips32_key, NULL);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+           res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+                                (CONST BYTE*)list->ips32,
+                                lstrlenA(list->ips32) + 1);
+           if (res == ERROR_SUCCESS && list->ips32_tmodel)
+               res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+                                    (CONST BYTE*)list->ips32_tmodel,
+                                    strlen(list->ips32_tmodel) + 1);
+           RegCloseKey(ips32_key);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       }
+
+       if (list->progid) {
+           res = register_key_defvalueA(clsid_key, progid_keyname,
+                                        list->progid);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+           res = register_progid(buf, list->progid, NULL,
+                                 list->name, list->progid_extra);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       }
+
+       if (list->viprogid) {
+           res = register_key_defvalueA(clsid_key, viprogid_keyname,
+                                        list->viprogid);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+           res = register_progid(buf, list->viprogid, list->progid,
+                                 list->name, list->progid_extra);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+       }
+
+    error_close_clsid_key:
+       RegCloseKey(clsid_key);
+    }
+
+error_close_coclass_key:
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                       KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       WCHAR buf[39];
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegDeleteTreeW(coclass_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       if (list->progid) {
+           res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid);
+           if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+           if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+       }
+
+       if (list->viprogid) {
+           res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid);
+           if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+           if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+       }
+    }
+
+error_close_coclass_key:
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             register_decoders
+ */
+static HRESULT register_decoders(struct regsvr_decoder const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY decoders_key;
+    HKEY instance_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       HKEY clsid_key;
+       HKEY instance_clsid_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+       if (res == ERROR_SUCCESS) {
+           res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(buf), 78);
+           RegCloseKey(instance_clsid_key);
+       }
+       if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        if (list->author) {
+           res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->author),
+                                strlen(list->author) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->friendlyname) {
+           res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->friendlyname),
+                                strlen(list->friendlyname) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->vendor) {
+            StringFromGUID2(list->vendor, buf, 39);
+           res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(buf), 78);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->version) {
+           res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->version),
+                                strlen(list->version) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->mimetypes) {
+           res = RegSetValueExA(clsid_key, mimetypes_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->mimetypes),
+                                strlen(list->mimetypes) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->extensions) {
+           res = RegSetValueExA(clsid_key, extensions_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->extensions),
+                                strlen(list->extensions) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->formats) {
+            HKEY formats_key;
+            GUID const * const *format;
+
+            res = RegCreateKeyExW(clsid_key, formats_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (format=list->formats; *format; ++format)
+            {
+                HKEY format_key;
+                StringFromGUID2(*format, buf, 39);
+                res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+                RegCloseKey(format_key);
+            }
+            RegCloseKey(formats_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->patterns) {
+            HKEY patterns_key;
+            int i;
+
+            res = RegCreateKeyExW(clsid_key, patterns_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &patterns_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (i=0; list->patterns[i].length; i++)
+            {
+                HKEY pattern_key;
+                static const WCHAR int_format[] = {'%','i',0};
+                snprintfW(buf, 39, int_format, i);
+                res = RegCreateKeyExW(patterns_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &pattern_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+               res = RegSetValueExA(pattern_key, length_valuename, 0, REG_DWORD,
+                                    (CONST BYTE*)(&list->patterns[i].length), 4);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, position_valuename, 0, REG_DWORD,
+                                        (CONST BYTE*)(&list->patterns[i].position), 4);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, pattern_valuename, 0, REG_BINARY,
+                                        list->patterns[i].pattern,
+                                        list->patterns[i].length);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, mask_valuename, 0, REG_BINARY,
+                                        list->patterns[i].mask,
+                                        list->patterns[i].length);
+                if (res == ERROR_SUCCESS)
+                   res = RegSetValueExA(pattern_key, endofstream_valuename, 0, REG_DWORD,
+                                        (CONST BYTE*)&(list->patterns[i].endofstream), 4);
+                RegCloseKey(pattern_key);
+            }
+            RegCloseKey(patterns_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+    error_close_clsid_key:
+       RegCloseKey(clsid_key);
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(decoders_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             unregister_decoders
+ */
+static HRESULT unregister_decoders(struct regsvr_decoder const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY decoders_key;
+    HKEY instance_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                       KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICBitmapDecoders, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &decoders_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(decoders_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       StringFromGUID2(list->clsid, buf, 39);
+
+       res = RegDeleteTreeW(coclass_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       res = RegDeleteTreeW(instance_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(decoders_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             register_converters
+ */
+static HRESULT register_converters(struct regsvr_converter const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY converters_key;
+    HKEY instance_key;
+
+    res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       HKEY clsid_key;
+       HKEY instance_clsid_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       StringFromGUID2(list->clsid, buf, 39);
+       res = RegCreateKeyExW(instance_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_clsid_key, NULL);
+       if (res == ERROR_SUCCESS) {
+           res = RegSetValueExW(instance_clsid_key, clsid_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(buf), 78);
+           RegCloseKey(instance_clsid_key);
+       }
+       if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+        if (list->author) {
+           res = RegSetValueExA(clsid_key, author_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->author),
+                                strlen(list->author) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->friendlyname) {
+           res = RegSetValueExA(clsid_key, friendlyname_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->friendlyname),
+                                strlen(list->friendlyname) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->vendor) {
+            StringFromGUID2(list->vendor, buf, 39);
+           res = RegSetValueExW(clsid_key, vendor_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(buf), 78);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->version) {
+           res = RegSetValueExA(clsid_key, version_valuename, 0, REG_SZ,
+                                (CONST BYTE*)(list->version),
+                                strlen(list->version) + 1);
+           if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+        if (list->formats) {
+            HKEY formats_key;
+            GUID const * const *format;
+
+            res = RegCreateKeyExW(clsid_key, pixelformats_keyname, 0, NULL, 0,
+                                  KEY_READ | KEY_WRITE, NULL, &formats_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+            for (format=list->formats; *format; ++format)
+            {
+                HKEY format_key;
+                StringFromGUID2(*format, buf, 39);
+                res = RegCreateKeyExW(formats_key, buf, 0, NULL, 0,
+                                      KEY_READ | KEY_WRITE, NULL, &format_key, NULL);
+                if (res != ERROR_SUCCESS) break;
+                RegCloseKey(format_key);
+            }
+            RegCloseKey(formats_key);
+            if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+        }
+
+    error_close_clsid_key:
+       RegCloseKey(clsid_key);
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(converters_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             unregister_converters
+ */
+static HRESULT unregister_converters(struct regsvr_converter const *list)
+{
+    LONG res = ERROR_SUCCESS;
+    HKEY coclass_key;
+    WCHAR buf[39];
+    HKEY converters_key;
+    HKEY instance_key;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+                       KEY_READ | KEY_WRITE, &coclass_key);
+    if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+
+    if (res == ERROR_SUCCESS)  {
+        StringFromGUID2(&CATID_WICFormatConverters, buf, 39);
+        res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &converters_key, NULL);
+        if (res == ERROR_SUCCESS)
+        {
+            res = RegCreateKeyExW(converters_key, instance_keyname, 0, NULL, 0,
+                             KEY_READ | KEY_WRITE, NULL, &instance_key, NULL);
+            if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+        }
+        if (res != ERROR_SUCCESS)
+            RegCloseKey(coclass_key);
+    }
+    if (res != ERROR_SUCCESS) goto error_return;
+
+    for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+       StringFromGUID2(list->clsid, buf, 39);
+
+       res = RegDeleteTreeW(coclass_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+       res = RegDeleteTreeW(instance_key, buf);
+       if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS;
+       if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+    }
+
+error_close_coclass_key:
+    RegCloseKey(instance_key);
+    RegCloseKey(converters_key);
+    RegCloseKey(coclass_key);
+error_return:
+    return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ *             register_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+    HKEY base,
+    WCHAR const *name,
+    WCHAR const *value)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegCreateKeyExW(base, name, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+    res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+                        (lstrlenW(value) + 1) * sizeof(WCHAR));
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *             register_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+    HKEY base,
+    WCHAR const *name,
+    char const *value)
+{
+    LONG res;
+    HKEY key;
+
+    res = RegCreateKeyExW(base, name, 0, NULL, 0,
+                         KEY_READ | KEY_WRITE, NULL, &key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+    res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+                        lstrlenA(value) + 1);
+    RegCloseKey(key);
+    return res;
+}
+
+/***********************************************************************
+ *             register_progid
+ */
+static LONG register_progid(
+    WCHAR const *clsid,
+    char const *progid,
+    char const *curver_progid,
+    char const *name,
+    char const *extra)
+{
+    LONG res;
+    HKEY progid_key;
+
+    res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+                         NULL, 0, KEY_READ | KEY_WRITE, NULL,
+                         &progid_key, NULL);
+    if (res != ERROR_SUCCESS) return res;
+
+    if (name) {
+       res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+                            (CONST BYTE*)name, strlen(name) + 1);
+       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (clsid) {
+       res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (curver_progid) {
+       res = register_key_defvalueA(progid_key, curver_keyname,
+                                    curver_progid);
+       if (res != ERROR_SUCCESS) goto error_close_progid_key;
+    }
+
+    if (extra) {
+       HKEY extra_key;
+
+       res = RegCreateKeyExA(progid_key, extra, 0,
+                             NULL, 0, KEY_READ | KEY_WRITE, NULL,
+                             &extra_key, NULL);
+       if (res == ERROR_SUCCESS)
+           RegCloseKey(extra_key);
+    }
+
+error_close_progid_key:
+    RegCloseKey(progid_key);
+    return res;
+}
+
+/***********************************************************************
+ *             coclass list
+ */
+static struct regsvr_coclass const coclass_list[] = {
+    {   &CLSID_WICImagingFactory,
+       "WIC Imaging Factory",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    {   &CLSID_WICBmpDecoder,
+       "WIC BMP Decoder",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    {   &CLSID_WICBmpEncoder,
+       "WIC BMP Encoder",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    {   &CLSID_WICGifDecoder,
+       "WIC GIF Decoder",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    {   &CLSID_WICIcoDecoder,
+       "WIC ICO Decoder",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    {   &CLSID_WICDefaultFormatConverter,
+       "WIC Default Format Converter",
+       NULL,
+       "windowscodecs.dll",
+       "Apartment"
+    },
+    { NULL }                   /* list terminator */
+};
+
+/***********************************************************************
+ *             decoder list
+ */
+static const BYTE mask_all[] = {0xff,0xff,0xff,0xff,0xff,0xff};
+
+static const BYTE bmp_magic[] = {0x42,0x4d};
+
+static GUID const * const bmp_formats[] = {
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat2bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
+    &GUID_WICPixelFormat16bppBGR555,
+    &GUID_WICPixelFormat16bppBGR565,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    NULL
+};
+
+static struct decoder_pattern const bmp_patterns[] = {
+    {2,0,bmp_magic,mask_all,0},
+    {0}
+};
+
+static const BYTE gif87a_magic[6] = "GIF87a";
+static const BYTE gif89a_magic[6] = "GIF89a";
+
+static GUID const * const gif_formats[] = {
+    &GUID_WICPixelFormat8bppIndexed,
+    NULL
+};
+
+static struct decoder_pattern const gif_patterns[] = {
+    {6,0,gif87a_magic,mask_all,0},
+    {6,0,gif89a_magic,mask_all,0},
+    {0}
+};
+
+static const BYTE ico_magic[] = {00,00,01,00};
+
+static GUID const * const ico_formats[] = {
+    &GUID_WICPixelFormat32bppBGRA,
+    NULL
+};
+
+static struct decoder_pattern const ico_patterns[] = {
+    {4,0,ico_magic,mask_all,0},
+    {0}
+};
+
+static struct regsvr_decoder const decoder_list[] = {
+    {   &CLSID_WICBmpDecoder,
+       "The Wine Project",
+       "BMP Decoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       "image/bmp",
+       ".bmp,.dib,.rle",
+       bmp_formats,
+       bmp_patterns
+    },
+    {   &CLSID_WICGifDecoder,
+       "The Wine Project",
+       "GIF Decoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       "image/gif",
+       ".gif",
+       gif_formats,
+       gif_patterns
+    },
+    {   &CLSID_WICIcoDecoder,
+       "The Wine Project",
+       "ICO Decoder",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       "image/vnd.microsoft.icon",
+       ".ico",
+       ico_formats,
+       ico_patterns
+    },
+    { NULL }                   /* list terminator */
+};
+
+static GUID const * const converter_formats[] = {
+    &GUID_WICPixelFormat1bppIndexed,
+    &GUID_WICPixelFormat4bppIndexed,
+    &GUID_WICPixelFormat8bppIndexed,
+    &GUID_WICPixelFormat16bppBGR555,
+    &GUID_WICPixelFormat16bppBGR565,
+    &GUID_WICPixelFormat24bppBGR,
+    &GUID_WICPixelFormat32bppBGR,
+    &GUID_WICPixelFormat32bppBGRA,
+    NULL
+};
+
+static struct regsvr_converter const converter_list[] = {
+    {   &CLSID_WICDefaultFormatConverter,
+       "The Wine Project",
+       "Default Pixel Format Converter",
+       "1.0.0.0",
+       &GUID_VendorMicrosoft,
+       converter_formats
+    },
+    { NULL }                   /* list terminator */
+};
+
+HRESULT WINAPI DllRegisterServer(void)
+{
+    HRESULT hr;
+
+    TRACE("\n");
+
+    hr = register_coclasses(coclass_list);
+    if (SUCCEEDED(hr))
+        register_decoders(decoder_list);
+    if (SUCCEEDED(hr))
+        register_converters(converter_list);
+    return hr;
+}
+
+HRESULT WINAPI DllUnregisterServer(void)
+{
+    HRESULT hr;
+
+    TRACE("\n");
+
+    hr = unregister_coclasses(coclass_list);
+    if (SUCCEEDED(hr))
+        unregister_decoders(decoder_list);
+    if (SUCCEEDED(hr))
+        unregister_converters(converter_list);
+    return hr;
+}
diff --git a/reactos/dll/win32/windowscodecs/stream.c b/reactos/dll/win32/windowscodecs/stream.c
new file mode 100644 (file)
index 0000000..ba1b2a6
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ * Copyright 2009 Tony Wasserka
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "wine/debug.h"
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "objbase.h"
+#include "wincodec.h"
+#include "wincodecs_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+/******************************************
+ * StreamOnMemory implementation
+ *
+ * Used by IWICStream_InitializeFromMemory
+ *
+ */
+typedef struct StreamOnMemory {
+    const IStreamVtbl *lpVtbl;
+    LONG ref;
+
+    BYTE *pbMemory;
+    DWORD dwMemsize;
+    DWORD dwCurPos;
+} StreamOnMemory;
+
+static HRESULT WINAPI StreamOnMemory_QueryInterface(IStream *iface,
+    REFIID iid, void **ppv)
+{
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
+        IsEqualIID(&IID_ISequentialStream, iid))
+    {
+        *ppv = iface;
+        IUnknown_AddRef((IUnknown*)*ppv);
+        return S_OK;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+}
+
+static ULONG WINAPI StreamOnMemory_AddRef(IStream *iface)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI StreamOnMemory_Release(IStream *iface)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0) {
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI StreamOnMemory_Read(IStream *iface,
+    void *pv, ULONG cb, ULONG *pcbRead)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    ULONG uBytesRead;
+    TRACE("(%p)\n", This);
+
+    if (!pv) return E_INVALIDARG;
+
+    uBytesRead = min(cb, This->dwMemsize - This->dwCurPos);
+    memcpy(pv, This->pbMemory + This->dwCurPos, uBytesRead);
+    This->dwCurPos += uBytesRead;
+    if (pcbRead) *pcbRead = uBytesRead;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI StreamOnMemory_Write(IStream *iface,
+    void const *pv, ULONG cb, ULONG *pcbWritten)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    TRACE("(%p)\n", This);
+
+    if (!pv) return E_INVALIDARG;
+
+    if (cb > This->dwMemsize - This->dwCurPos) return STG_E_MEDIUMFULL;
+    if (cb) {
+        memcpy(This->pbMemory + This->dwCurPos, pv, cb);
+        This->dwCurPos += cb;
+    }
+    if (pcbWritten) *pcbWritten = cb;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI StreamOnMemory_Seek(IStream *iface,
+    LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    LARGE_INTEGER NewPosition;
+    TRACE("(%p)\n", This);
+
+    if (dlibMove.QuadPart > 0xFFFFFFFF) return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
+
+    if (dwOrigin == STREAM_SEEK_SET) NewPosition.QuadPart = dlibMove.QuadPart;
+    else if (dwOrigin == STREAM_SEEK_CUR) NewPosition.QuadPart = This->dwCurPos + dlibMove.QuadPart;
+    else if (dwOrigin == STREAM_SEEK_END) NewPosition.QuadPart = This->dwMemsize + dlibMove.QuadPart;
+    else return E_INVALIDARG;
+
+    if (NewPosition.QuadPart > This->dwMemsize) return E_INVALIDARG;
+    if (NewPosition.QuadPart < 0) return E_INVALIDARG;
+    This->dwCurPos = NewPosition.LowPart;
+
+    if(plibNewPosition) plibNewPosition->QuadPart = This->dwCurPos;
+    return S_OK;
+}
+
+/* SetSize isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_SetSize(IStream *iface,
+    ULARGE_INTEGER libNewSize)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+/* CopyTo isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_CopyTo(IStream *iface,
+    IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+/* Commit isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_Commit(IStream *iface,
+    DWORD grfCommitFlags)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+/* Revert isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_Revert(IStream *iface)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+/* LockRegion isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_LockRegion(IStream *iface,
+    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+/* UnlockRegion isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_UnlockRegion(IStream *iface,
+    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI StreamOnMemory_Stat(IStream *iface,
+    STATSTG *pstatstg, DWORD grfStatFlag)
+{
+    StreamOnMemory *This = (StreamOnMemory*)iface;
+    TRACE("(%p)\n", This);
+
+    if (!pstatstg) return E_INVALIDARG;
+
+    ZeroMemory(pstatstg, sizeof(STATSTG));
+    pstatstg->type = STGTY_STREAM;
+    pstatstg->cbSize.QuadPart = This->dwMemsize;
+
+    return S_OK;
+}
+
+/* Clone isn't implemented in the native windowscodecs DLL either */
+static HRESULT WINAPI StreamOnMemory_Clone(IStream *iface,
+    IStream **ppstm)
+{
+    TRACE("(%p)\n", iface);
+    return E_NOTIMPL;
+}
+
+
+const IStreamVtbl StreamOnMemory_Vtbl =
+{
+    /*** IUnknown methods ***/
+    StreamOnMemory_QueryInterface,
+    StreamOnMemory_AddRef,
+    StreamOnMemory_Release,
+    /*** ISequentialStream methods ***/
+    StreamOnMemory_Read,
+    StreamOnMemory_Write,
+    /*** IStream methods ***/
+    StreamOnMemory_Seek,
+    StreamOnMemory_SetSize,
+    StreamOnMemory_CopyTo,
+    StreamOnMemory_Commit,
+    StreamOnMemory_Revert,
+    StreamOnMemory_LockRegion,
+    StreamOnMemory_UnlockRegion,
+    StreamOnMemory_Stat,
+    StreamOnMemory_Clone,
+};
+
+/******************************************
+ * IWICStream implementation
+ *
+ */
+typedef struct IWICStreamImpl
+{
+    const IWICStreamVtbl *lpVtbl;
+    LONG ref;
+
+    IStream *pStream;
+} IWICStreamImpl;
+
+static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface,
+    REFIID iid, void **ppv)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) ||
+        IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid))
+    {
+        *ppv = This;
+        IUnknown_AddRef((IUnknown*)*ppv);
+        return S_OK;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+}
+
+static ULONG WINAPI IWICStreamImpl_AddRef(IWICStream *iface)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IWICStreamImpl_Release(IWICStream *iface)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0) {
+        if (This->pStream) IStream_Release(This->pStream);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IWICStreamImpl_Read(IWICStream *iface,
+    void *pv, ULONG cb, ULONG *pcbRead)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Read(This->pStream, pv, cb, pcbRead);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Write(IWICStream *iface,
+    void const *pv, ULONG cb, ULONG *pcbWritten)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Write(This->pStream, pv, cb, pcbWritten);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Seek(IWICStream *iface,
+    LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Seek(This->pStream, dlibMove, dwOrigin, plibNewPosition);
+}
+
+static HRESULT WINAPI IWICStreamImpl_SetSize(IWICStream *iface,
+    ULARGE_INTEGER libNewSize)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_SetSize(This->pStream, libNewSize);
+}
+
+static HRESULT WINAPI IWICStreamImpl_CopyTo(IWICStream *iface,
+    IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_CopyTo(This->pStream, pstm, cb, pcbRead, pcbWritten);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Commit(IWICStream *iface,
+    DWORD grfCommitFlags)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Commit(This->pStream, grfCommitFlags);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Revert(IWICStream *iface)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Revert(This->pStream);
+}
+
+static HRESULT WINAPI IWICStreamImpl_LockRegion(IWICStream *iface,
+    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_LockRegion(This->pStream, libOffset, cb, dwLockType);
+}
+
+static HRESULT WINAPI IWICStreamImpl_UnlockRegion(IWICStream *iface,
+    ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_UnlockRegion(This->pStream, libOffset, cb, dwLockType);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Stat(IWICStream *iface,
+    STATSTG *pstatstg, DWORD grfStatFlag)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Stat(This->pStream, pstatstg, grfStatFlag);
+}
+
+static HRESULT WINAPI IWICStreamImpl_Clone(IWICStream *iface,
+    IStream **ppstm)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    TRACE("(%p): relay\n", This);
+
+    if (!This->pStream) return WINCODEC_ERR_NOTINITIALIZED;
+    return IStream_Clone(This->pStream, ppstm);
+}
+
+static HRESULT WINAPI IWICStreamImpl_InitializeFromIStream(IWICStream *iface,
+    IStream *pIStream)
+{
+    FIXME("(%p): stub\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IWICStreamImpl_InitializeFromFilename(IWICStream *iface,
+    LPCWSTR wzFileName, DWORD dwDesiredAccess)
+{
+    FIXME("(%p): stub\n", iface);
+    return E_NOTIMPL;
+}
+
+/******************************************
+ * IWICStream_InitializeFromMemory
+ *
+ * Initializes the internal IStream object to retrieve its data from a memory chunk.
+ *
+ * PARAMS
+ *   pbBuffer     [I] pointer to the memory chunk
+ *   cbBufferSize [I] number of bytes to use from the memory chunk
+ *
+ * RETURNS
+ *   SUCCESS: S_OK
+ *   FAILURE: E_INVALIDARG, if pbBuffer is NULL
+ *            E_OUTOFMEMORY, if we run out of memory
+ *            WINCODEC_ERR_WRONGSTATE, if the IStream object has already been initialized before
+ *
+ */
+static HRESULT WINAPI IWICStreamImpl_InitializeFromMemory(IWICStream *iface,
+    BYTE *pbBuffer, DWORD cbBufferSize)
+{
+    IWICStreamImpl *This = (IWICStreamImpl*)iface;
+    StreamOnMemory *pObject;
+    TRACE("(%p,%p)\n", iface, pbBuffer);
+
+    if (!pbBuffer) return E_INVALIDARG;
+    if (This->pStream) return WINCODEC_ERR_WRONGSTATE;
+
+    pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(StreamOnMemory));
+    if (!pObject) return E_OUTOFMEMORY;
+
+    pObject->lpVtbl = &StreamOnMemory_Vtbl;
+    pObject->ref = 1;
+    pObject->pbMemory = pbBuffer;
+    pObject->dwMemsize = cbBufferSize;
+    pObject->dwCurPos = 0;
+
+    This->pStream = (IStream*)pObject;
+    return S_OK;
+}
+
+static HRESULT WINAPI IWICStreamImpl_InitializeFromIStreamRegion(IWICStream *iface,
+    IStream *pIStream, ULARGE_INTEGER ulOffset, ULARGE_INTEGER ulMaxSize)
+{
+    FIXME("(%p): stub\n", iface);
+    return E_NOTIMPL;
+}
+
+
+const IWICStreamVtbl WICStream_Vtbl =
+{
+    /*** IUnknown methods ***/
+    IWICStreamImpl_QueryInterface,
+    IWICStreamImpl_AddRef,
+    IWICStreamImpl_Release,
+    /*** ISequentialStream methods ***/
+    IWICStreamImpl_Read,
+    IWICStreamImpl_Write,
+    /*** IStream methods ***/
+    IWICStreamImpl_Seek,
+    IWICStreamImpl_SetSize,
+    IWICStreamImpl_CopyTo,
+    IWICStreamImpl_Commit,
+    IWICStreamImpl_Revert,
+    IWICStreamImpl_LockRegion,
+    IWICStreamImpl_UnlockRegion,
+    IWICStreamImpl_Stat,
+    IWICStreamImpl_Clone,
+    /*** IWICStream methods ***/
+    IWICStreamImpl_InitializeFromIStream,
+    IWICStreamImpl_InitializeFromFilename,
+    IWICStreamImpl_InitializeFromMemory,
+    IWICStreamImpl_InitializeFromIStreamRegion,
+};
+
+HRESULT StreamImpl_Create(IWICStream **stream)
+{
+    IWICStreamImpl *pObject;
+
+    if( !stream ) return E_INVALIDARG;
+
+    pObject = HeapAlloc(GetProcessHeap(), 0, sizeof(IWICStreamImpl));
+    if( !pObject ) {
+        *stream = NULL;
+        return E_OUTOFMEMORY;
+    }
+
+    pObject->lpVtbl = &WICStream_Vtbl;
+    pObject->ref = 1;
+    pObject->pStream = NULL;
+
+    *stream = (IWICStream*)pObject;
+
+    return S_OK;
+}
diff --git a/reactos/dll/win32/windowscodecs/ungif.c b/reactos/dll/win32/windowscodecs/ungif.c
new file mode 100644 (file)
index 0000000..c24f387
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ * Gif extracting routines - derived from libungif
+ *
+ * Portions Copyright 2006 Mike McCormack
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * Original copyright notice:
+ *
+ * The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+
+/******************************************************************************
+ *   "Gif-Lib" - Yet another gif library.
+ *
+ * Written by:  Gershon Elber            IBM PC Ver 1.1,    Aug. 1990
+ ******************************************************************************
+ * The kernel of the GIF Decoding process can be found here.
+ ******************************************************************************
+ * History:
+ * 16 Jun 89 - Version 1.0 by Gershon Elber.
+ *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names).
+ *****************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "ungif.h"
+
+#include <stdarg.h>
+#include "windef.h"
+#include "winbase.h"
+
+static void *ungif_alloc( size_t sz )
+{
+    return HeapAlloc( GetProcessHeap(), 0, sz );
+}
+
+static void *ungif_calloc( size_t num, size_t sz )
+{
+    return HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, num*sz );
+}
+
+static void *ungif_realloc( void *ptr, size_t sz )
+{
+    return HeapReAlloc( GetProcessHeap(), 0, ptr, sz );
+}
+
+static void ungif_free( void *ptr )
+{
+    HeapFree( GetProcessHeap(), 0, ptr );
+}
+
+#define LZ_MAX_CODE         4095    /* Biggest code possible in 12 bits. */
+#define LZ_BITS             12
+
+#define NO_SUCH_CODE        4098    /* Impossible code, to signal empty. */
+
+typedef struct GifFilePrivateType {
+    GifWord BitsPerPixel,     /* Bits per pixel (Codes uses at least this + 1). */
+      ClearCode,   /* The CLEAR LZ code. */
+      EOFCode,     /* The EOF LZ code. */
+      RunningCode, /* The next code algorithm can generate. */
+      RunningBits, /* The number of bits required to represent RunningCode. */
+      MaxCode1,    /* 1 bigger than max. possible code, in RunningBits bits. */
+      LastCode,    /* The code before the current code. */
+      CrntCode,    /* Current algorithm code. */
+      StackPtr,    /* For character stack (see below). */
+      CrntShiftState;    /* Number of bits in CrntShiftDWord. */
+    unsigned long CrntShiftDWord;   /* For bytes decomposition into codes. */
+    unsigned long PixelCount;   /* Number of pixels in image. */
+    InputFunc Read;     /* function to read gif input (TVT) */
+    GifByteType Buf[256];   /* Compressed input is buffered here. */
+    GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
+    GifByteType Suffix[LZ_MAX_CODE + 1];    /* So we can trace the codes. */
+    GifPrefixType Prefix[LZ_MAX_CODE + 1];
+} GifFilePrivateType;
+
+/* avoid extra function call in case we use fread (TVT) */
+#define READ(_gif,_buf,_len) \
+    ((GifFilePrivateType*)_gif->Private)->Read(_gif,_buf,_len)
+
+static int DGifGetWord(GifFileType *GifFile, GifWord *Word);
+static int DGifSetupDecompress(GifFileType *GifFile);
+static int DGifDecompressLine(GifFileType *GifFile, GifPixelType *Line, int LineLen);
+static int DGifGetPrefixChar(const GifPrefixType *Prefix, int Code, int ClearCode);
+static int DGifDecompressInput(GifFileType *GifFile, int *Code);
+static int DGifBufferedInput(GifFileType *GifFile, GifByteType *Buf,
+                             GifByteType *NextByte);
+
+static int DGifGetExtensionNext(GifFileType * GifFile, GifByteType ** GifExtension);
+static int DGifGetCodeNext(GifFileType * GifFile, GifByteType ** GifCodeBlock);
+
+/******************************************************************************
+ * Miscellaneous utility functions
+ *****************************************************************************/
+
+/* return smallest bitfield size n will fit in */
+static int
+BitSize(int n) {
+
+    register int i;
+
+    for (i = 1; i <= 8; i++)
+        if ((1 << i) >= n)
+            break;
+    return (i);
+}
+
+/******************************************************************************
+ * Color map object functions
+ *****************************************************************************/
+
+/*
+ * Allocate a color map of given size; initialize with contents of
+ * ColorMap if that pointer is non-NULL.
+ */
+static ColorMapObject *
+MakeMapObject(int ColorCount,
+              const GifColorType * ColorMap) {
+
+    ColorMapObject *Object;
+
+    /*** FIXME: Our ColorCount has to be a power of two.  Is it necessary to
+     * make the user know that or should we automatically round up instead? */
+    if (ColorCount != (1 << BitSize(ColorCount))) {
+        return NULL;
+    }
+
+    Object = ungif_alloc(sizeof(ColorMapObject));
+    if (Object == NULL) {
+        return NULL;
+    }
+
+    Object->Colors = ungif_calloc(ColorCount, sizeof(GifColorType));
+    if (Object->Colors == NULL) {
+        return NULL;
+    }
+
+    Object->ColorCount = ColorCount;
+    Object->BitsPerPixel = BitSize(ColorCount);
+
+    if (ColorMap) {
+        memcpy(Object->Colors, ColorMap, ColorCount * sizeof(GifColorType));
+    }
+
+    return (Object);
+}
+
+/*
+ * Free a color map object
+ */
+static void
+FreeMapObject(ColorMapObject * Object) {
+
+    if (Object != NULL) {
+        ungif_free(Object->Colors);
+        ungif_free(Object);
+        /*** FIXME:
+         * When we are willing to break API we need to make this function
+         * FreeMapObject(ColorMapObject **Object)
+         * and do this assignment to NULL here:
+         * *Object = NULL;
+         */
+    }
+}
+
+static int
+AddExtensionBlock(SavedImage * New,
+                  int Len,
+                  const unsigned char ExtData[]) {
+
+    ExtensionBlock *ep;
+
+    if (New->ExtensionBlocks == NULL)
+        New->ExtensionBlocks = ungif_alloc(sizeof(ExtensionBlock));
+    else
+        New->ExtensionBlocks = ungif_realloc(New->ExtensionBlocks,
+                                      sizeof(ExtensionBlock) *
+                                      (New->ExtensionBlockCount + 1));
+
+    if (New->ExtensionBlocks == NULL)
+        return (GIF_ERROR);
+
+    ep = &New->ExtensionBlocks[New->ExtensionBlockCount++];
+
+    ep->ByteCount=Len;
+    ep->Bytes = ungif_alloc(ep->ByteCount);
+    if (ep->Bytes == NULL)
+        return (GIF_ERROR);
+
+    if (ExtData) {
+        memcpy(ep->Bytes, ExtData, Len);
+        ep->Function = New->Function;
+    }
+
+    return (GIF_OK);
+}
+
+static void
+FreeExtension(SavedImage * Image)
+{
+    ExtensionBlock *ep;
+
+    if ((Image == NULL) || (Image->ExtensionBlocks == NULL)) {
+        return;
+    }
+    for (ep = Image->ExtensionBlocks;
+         ep < (Image->ExtensionBlocks + Image->ExtensionBlockCount); ep++)
+        ungif_free(ep->Bytes);
+    ungif_free(Image->ExtensionBlocks);
+    Image->ExtensionBlocks = NULL;
+}
+
+/******************************************************************************
+ * Image block allocation functions
+******************************************************************************/
+
+static void
+FreeSavedImages(GifFileType * GifFile) {
+
+    SavedImage *sp;
+
+    if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
+        return;
+    }
+    for (sp = GifFile->SavedImages;
+         sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
+        if (sp->ImageDesc.ColorMap) {
+            FreeMapObject(sp->ImageDesc.ColorMap);
+            sp->ImageDesc.ColorMap = NULL;
+        }
+
+        ungif_free(sp->RasterBits);
+
+        if (sp->ExtensionBlocks)
+            FreeExtension(sp);
+    }
+    ungif_free(GifFile->SavedImages);
+    GifFile->SavedImages=NULL;
+}
+
+/******************************************************************************
+ * This routine should be called before any other DGif calls. Note that
+ * this routine is called automatically from DGif file open routines.
+ *****************************************************************************/
+static int
+DGifGetScreenDesc(GifFileType * GifFile) {
+
+    int i, BitsPerPixel;
+    GifByteType Buf[3];
+
+    /* Put the screen descriptor into the file: */
+    if (DGifGetWord(GifFile, &GifFile->SWidth) == GIF_ERROR ||
+        DGifGetWord(GifFile, &GifFile->SHeight) == GIF_ERROR)
+        return GIF_ERROR;
+
+    if (READ(GifFile, Buf, 3) != 3) {
+        return GIF_ERROR;
+    }
+    GifFile->SColorResolution = (((Buf[0] & 0x70) + 1) >> 4) + 1;
+    BitsPerPixel = (Buf[0] & 0x07) + 1;
+    GifFile->SBackGroundColor = Buf[1];
+    if (Buf[0] & 0x80) {    /* Do we have global color map? */
+
+        GifFile->SColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
+        if (GifFile->SColorMap == NULL) {
+            return GIF_ERROR;
+        }
+
+        /* Get the global color map: */
+        for (i = 0; i < GifFile->SColorMap->ColorCount; i++) {
+            if (READ(GifFile, Buf, 3) != 3) {
+                FreeMapObject(GifFile->SColorMap);
+                GifFile->SColorMap = NULL;
+                return GIF_ERROR;
+            }
+            GifFile->SColorMap->Colors[i].Red = Buf[0];
+            GifFile->SColorMap->Colors[i].Green = Buf[1];
+            GifFile->SColorMap->Colors[i].Blue = Buf[2];
+        }
+    } else {
+        GifFile->SColorMap = NULL;
+    }
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * This routine should be called before any attempt to read an image.
+ *****************************************************************************/
+static int
+DGifGetRecordType(GifFileType * GifFile,
+                  GifRecordType * Type) {
+
+    GifByteType Buf;
+
+    if (READ(GifFile, &Buf, 1) != 1) {
+        return GIF_ERROR;
+    }
+
+    switch (Buf) {
+      case ',':
+          *Type = IMAGE_DESC_RECORD_TYPE;
+          break;
+      case '!':
+          *Type = EXTENSION_RECORD_TYPE;
+          break;
+      case ';':
+          *Type = TERMINATE_RECORD_TYPE;
+          break;
+      default:
+          *Type = UNDEFINED_RECORD_TYPE;
+          return GIF_ERROR;
+    }
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * This routine should be called before any attempt to read an image.
+ * Note it is assumed the Image desc. header (',') has been read.
+ *****************************************************************************/
+static int
+DGifGetImageDesc(GifFileType * GifFile) {
+
+    int i, BitsPerPixel;
+    GifByteType Buf[3];
+    GifFilePrivateType *Private = GifFile->Private;
+    SavedImage *sp;
+
+    if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR ||
+        DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR ||
+        DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR ||
+        DGifGetWord(GifFile, &GifFile->Image.Height) == GIF_ERROR)
+        return GIF_ERROR;
+    if (READ(GifFile, Buf, 1) != 1) {
+        return GIF_ERROR;
+    }
+    BitsPerPixel = (Buf[0] & 0x07) + 1;
+    GifFile->Image.Interlace = (Buf[0] & 0x40);
+    if (Buf[0] & 0x80) {    /* Does this image have local color map? */
+
+        /*** FIXME: Why do we check both of these in order to do this?
+         * Why do we have both Image and SavedImages? */
+        if (GifFile->Image.ColorMap && GifFile->SavedImages == NULL)
+            FreeMapObject(GifFile->Image.ColorMap);
+
+        GifFile->Image.ColorMap = MakeMapObject(1 << BitsPerPixel, NULL);
+        if (GifFile->Image.ColorMap == NULL) {
+            return GIF_ERROR;
+        }
+
+        /* Get the image local color map: */
+        for (i = 0; i < GifFile->Image.ColorMap->ColorCount; i++) {
+            if (READ(GifFile, Buf, 3) != 3) {
+                FreeMapObject(GifFile->Image.ColorMap);
+                GifFile->Image.ColorMap = NULL;
+                return GIF_ERROR;
+            }
+            GifFile->Image.ColorMap->Colors[i].Red = Buf[0];
+            GifFile->Image.ColorMap->Colors[i].Green = Buf[1];
+            GifFile->Image.ColorMap->Colors[i].Blue = Buf[2];
+        }
+    } else if (GifFile->Image.ColorMap) {
+        FreeMapObject(GifFile->Image.ColorMap);
+        GifFile->Image.ColorMap = NULL;
+    }
+
+    if (GifFile->SavedImages) {
+        if ((GifFile->SavedImages = ungif_realloc(GifFile->SavedImages,
+                                      sizeof(SavedImage) *
+                                      (GifFile->ImageCount + 1))) == NULL) {
+            return GIF_ERROR;
+        }
+    } else {
+        if ((GifFile->SavedImages = ungif_alloc(sizeof(SavedImage))) == NULL) {
+            return GIF_ERROR;
+        }
+    }
+
+    sp = &GifFile->SavedImages[GifFile->ImageCount];
+    sp->ImageDesc = GifFile->Image;
+    if (GifFile->Image.ColorMap != NULL) {
+        sp->ImageDesc.ColorMap = MakeMapObject(
+                                 GifFile->Image.ColorMap->ColorCount,
+                                 GifFile->Image.ColorMap->Colors);
+        if (sp->ImageDesc.ColorMap == NULL) {
+            return GIF_ERROR;
+        }
+    }
+    sp->RasterBits = NULL;
+    sp->ExtensionBlockCount = 0;
+    sp->ExtensionBlocks = NULL;
+
+    GifFile->ImageCount++;
+
+    Private->PixelCount = (long)GifFile->Image.Width *
+       (long)GifFile->Image.Height;
+
+    DGifSetupDecompress(GifFile);  /* Reset decompress algorithm parameters. */
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Get one full scanned line (Line) of length LineLen from GIF file.
+ *****************************************************************************/
+static int
+DGifGetLine(GifFileType * GifFile,
+            GifPixelType * Line,
+            int LineLen) {
+
+    GifByteType *Dummy;
+    GifFilePrivateType *Private = GifFile->Private;
+
+    if (!LineLen)
+        LineLen = GifFile->Image.Width;
+
+    if ((Private->PixelCount -= LineLen) > 0xffff0000UL) {
+        return GIF_ERROR;
+    }
+
+    if (DGifDecompressLine(GifFile, Line, LineLen) == GIF_OK) {
+        if (Private->PixelCount == 0) {
+            /* We probably would not be called any more, so lets clean
+             * everything before we return: need to flush out all rest of
+             * image until empty block (size 0) detected. We use GetCodeNext. */
+            do
+                if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR)
+                    return GIF_ERROR;
+            while (Dummy != NULL) ;
+        }
+        return GIF_OK;
+    } else
+        return GIF_ERROR;
+}
+
+/******************************************************************************
+ * Get an extension block (see GIF manual) from gif file. This routine only
+ * returns the first data block, and DGifGetExtensionNext should be called
+ * after this one until NULL extension is returned.
+ * The Extension should NOT be freed by the user (not dynamically allocated).
+ * Note it is assumed the Extension desc. header ('!') has been read.
+ *****************************************************************************/
+static int
+DGifGetExtension(GifFileType * GifFile,
+                 int *ExtCode,
+                 GifByteType ** Extension) {
+
+    GifByteType Buf;
+
+    if (READ(GifFile, &Buf, 1) != 1) {
+        return GIF_ERROR;
+    }
+    *ExtCode = Buf;
+
+    return DGifGetExtensionNext(GifFile, Extension);
+}
+
+/******************************************************************************
+ * Get a following extension block (see GIF manual) from gif file. This
+ * routine should be called until NULL Extension is returned.
+ * The Extension should NOT be freed by the user (not dynamically allocated).
+ *****************************************************************************/
+static int
+DGifGetExtensionNext(GifFileType * GifFile,
+                     GifByteType ** Extension) {
+
+    GifByteType Buf;
+    GifFilePrivateType *Private = GifFile->Private;
+
+    if (READ(GifFile, &Buf, 1) != 1) {
+        return GIF_ERROR;
+    }
+    if (Buf > 0) {
+        *Extension = Private->Buf;    /* Use private unused buffer. */
+        (*Extension)[0] = Buf;  /* Pascal strings notation (pos. 0 is len.). */
+        if (READ(GifFile, &((*Extension)[1]), Buf) != Buf) {
+            return GIF_ERROR;
+        }
+    } else
+        *Extension = NULL;
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Get 2 bytes (word) from the given file:
+ *****************************************************************************/
+static int
+DGifGetWord(GifFileType * GifFile,
+            GifWord *Word) {
+
+    unsigned char c[2];
+
+    if (READ(GifFile, c, 2) != 2) {
+        return GIF_ERROR;
+    }
+
+    *Word = (((unsigned int)c[1]) << 8) + c[0];
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Continue to get the image code in compressed form. This routine should be
+ * called until NULL block is returned.
+ * The block should NOT be freed by the user (not dynamically allocated).
+ *****************************************************************************/
+static int
+DGifGetCodeNext(GifFileType * GifFile,
+                GifByteType ** CodeBlock) {
+
+    GifByteType Buf;
+    GifFilePrivateType *Private = GifFile->Private;
+
+    if (READ(GifFile, &Buf, 1) != 1) {
+        return GIF_ERROR;
+    }
+
+    if (Buf > 0) {
+        *CodeBlock = Private->Buf;    /* Use private unused buffer. */
+        (*CodeBlock)[0] = Buf;  /* Pascal strings notation (pos. 0 is len.). */
+        if (READ(GifFile, &((*CodeBlock)[1]), Buf) != Buf) {
+            return GIF_ERROR;
+        }
+    } else {
+        *CodeBlock = NULL;
+        Private->Buf[0] = 0;    /* Make sure the buffer is empty! */
+        Private->PixelCount = 0;    /* And local info. indicate image read. */
+    }
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Setup the LZ decompression for this image:
+ *****************************************************************************/
+static int
+DGifSetupDecompress(GifFileType * GifFile) {
+
+    int i, BitsPerPixel;
+    GifByteType CodeSize;
+    GifPrefixType *Prefix;
+    GifFilePrivateType *Private = GifFile->Private;
+
+    READ(GifFile, &CodeSize, 1);    /* Read Code size from file. */
+    BitsPerPixel = CodeSize;
+
+    Private->Buf[0] = 0;    /* Input Buffer empty. */
+    Private->BitsPerPixel = BitsPerPixel;
+    Private->ClearCode = (1 << BitsPerPixel);
+    Private->EOFCode = Private->ClearCode + 1;
+    Private->RunningCode = Private->EOFCode + 1;
+    Private->RunningBits = BitsPerPixel + 1;    /* Number of bits per code. */
+    Private->MaxCode1 = 1 << Private->RunningBits;    /* Max. code + 1. */
+    Private->StackPtr = 0;    /* No pixels on the pixel stack. */
+    Private->LastCode = NO_SUCH_CODE;
+    Private->CrntShiftState = 0;    /* No information in CrntShiftDWord. */
+    Private->CrntShiftDWord = 0;
+
+    Prefix = Private->Prefix;
+    for (i = 0; i <= LZ_MAX_CODE; i++)
+        Prefix[i] = NO_SUCH_CODE;
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * The LZ decompression routine:
+ * This version decompress the given gif file into Line of length LineLen.
+ * This routine can be called few times (one per scan line, for example), in
+ * order the complete the whole image.
+ *****************************************************************************/
+static int
+DGifDecompressLine(GifFileType * GifFile,
+                   GifPixelType * Line,
+                   int LineLen) {
+
+    int i = 0;
+    int j, CrntCode, EOFCode, ClearCode, CrntPrefix, LastCode, StackPtr;
+    GifByteType *Stack, *Suffix;
+    GifPrefixType *Prefix;
+    GifFilePrivateType *Private = GifFile->Private;
+
+    StackPtr = Private->StackPtr;
+    Prefix = Private->Prefix;
+    Suffix = Private->Suffix;
+    Stack = Private->Stack;
+    EOFCode = Private->EOFCode;
+    ClearCode = Private->ClearCode;
+    LastCode = Private->LastCode;
+
+    if (StackPtr != 0) {
+        /* Let pop the stack off before continuing to read the gif file: */
+        while (StackPtr != 0 && i < LineLen)
+            Line[i++] = Stack[--StackPtr];
+    }
+
+    while (i < LineLen) {    /* Decode LineLen items. */
+        if (DGifDecompressInput(GifFile, &CrntCode) == GIF_ERROR)
+            return GIF_ERROR;
+
+        if (CrntCode == EOFCode) {
+            /* Note, however, that usually we will not be here as we will stop
+             * decoding as soon as we got all the pixel, or EOF code will
+             * not be read at all, and DGifGetLine/Pixel clean everything.  */
+            if (i != LineLen - 1 || Private->PixelCount != 0) {
+                return GIF_ERROR;
+            }
+            i++;
+        } else if (CrntCode == ClearCode) {
+            /* We need to start over again: */
+            for (j = 0; j <= LZ_MAX_CODE; j++)
+                Prefix[j] = NO_SUCH_CODE;
+            Private->RunningCode = Private->EOFCode + 1;
+            Private->RunningBits = Private->BitsPerPixel + 1;
+            Private->MaxCode1 = 1 << Private->RunningBits;
+            LastCode = Private->LastCode = NO_SUCH_CODE;
+        } else {
+            /* It's a regular code - if in pixel range simply add it to output
+             * stream, otherwise trace to codes linked list until the prefix
+             * is in pixel range: */
+            if (CrntCode < ClearCode) {
+                /* This is simple - its pixel scalar, so add it to output: */
+                Line[i++] = CrntCode;
+            } else {
+                /* It's a code to be traced: trace the linked list
+                 * until the prefix is a pixel, while pushing the suffix
+                 * pixels on our stack. If we done, pop the stack in reverse
+                 * order (that's what stack is good for!) for output.  */
+                if (Prefix[CrntCode] == NO_SUCH_CODE) {
+                    /* Only allowed if CrntCode is exactly the running code:
+                     * In that case CrntCode = XXXCode, CrntCode or the
+                     * prefix code is last code and the suffix char is
+                     * exactly the prefix of last code! */
+                    if (CrntCode == Private->RunningCode - 2) {
+                        CrntPrefix = LastCode;
+                        Suffix[Private->RunningCode - 2] =
+                           Stack[StackPtr++] = DGifGetPrefixChar(Prefix,
+                                                                 LastCode,
+                                                                 ClearCode);
+                    } else {
+                        return GIF_ERROR;
+                    }
+                } else
+                    CrntPrefix = CrntCode;
+
+                /* Now (if image is O.K.) we should not get a NO_SUCH_CODE
+                 * during the trace. As we might loop forever, in case of
+                 * defective image, we count the number of loops we trace
+                 * and stop if we got LZ_MAX_CODE. Obviously we cannot
+                 * loop more than that.  */
+                j = 0;
+                while (j++ <= LZ_MAX_CODE &&
+                       CrntPrefix > ClearCode && CrntPrefix <= LZ_MAX_CODE) {
+                    Stack[StackPtr++] = Suffix[CrntPrefix];
+                    CrntPrefix = Prefix[CrntPrefix];
+                }
+                if (j >= LZ_MAX_CODE || CrntPrefix > LZ_MAX_CODE) {
+                    return GIF_ERROR;
+                }
+                /* Push the last character on stack: */
+                Stack[StackPtr++] = CrntPrefix;
+
+                /* Now lets pop all the stack into output: */
+                while (StackPtr != 0 && i < LineLen)
+                    Line[i++] = Stack[--StackPtr];
+            }
+            if (LastCode != NO_SUCH_CODE) {
+                Prefix[Private->RunningCode - 2] = LastCode;
+
+                if (CrntCode == Private->RunningCode - 2) {
+                    /* Only allowed if CrntCode is exactly the running code:
+                     * In that case CrntCode = XXXCode, CrntCode or the
+                     * prefix code is last code and the suffix char is
+                     * exactly the prefix of last code! */
+                    Suffix[Private->RunningCode - 2] =
+                       DGifGetPrefixChar(Prefix, LastCode, ClearCode);
+                } else {
+                    Suffix[Private->RunningCode - 2] =
+                       DGifGetPrefixChar(Prefix, CrntCode, ClearCode);
+                }
+            }
+            LastCode = CrntCode;
+        }
+    }
+
+    Private->LastCode = LastCode;
+    Private->StackPtr = StackPtr;
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Routine to trace the Prefixes linked list until we get a prefix which is
+ * not code, but a pixel value (less than ClearCode). Returns that pixel value.
+ * If image is defective, we might loop here forever, so we limit the loops to
+ * the maximum possible if image O.k. - LZ_MAX_CODE times.
+ *****************************************************************************/
+static int
+DGifGetPrefixChar(const GifPrefixType *Prefix,
+                  int Code,
+                  int ClearCode) {
+
+    int i = 0;
+
+    while (Code > ClearCode && i++ <= LZ_MAX_CODE)
+        Code = Prefix[Code];
+    return Code;
+}
+
+/******************************************************************************
+ * The LZ decompression input routine:
+ * This routine is responsible for the decompression of the bit stream from
+ * 8 bits (bytes) packets, into the real codes.
+ * Returns GIF_OK if read successfully.
+ *****************************************************************************/
+static int
+DGifDecompressInput(GifFileType * GifFile,
+                    int *Code) {
+
+    GifFilePrivateType *Private = GifFile->Private;
+
+    GifByteType NextByte;
+    static const unsigned short CodeMasks[] = {
+        0x0000, 0x0001, 0x0003, 0x0007,
+        0x000f, 0x001f, 0x003f, 0x007f,
+        0x00ff, 0x01ff, 0x03ff, 0x07ff,
+        0x0fff
+    };
+    /* The image can't contain more than LZ_BITS per code. */
+    if (Private->RunningBits > LZ_BITS) {
+        return GIF_ERROR;
+    }
+
+    while (Private->CrntShiftState < Private->RunningBits) {
+        /* Needs to get more bytes from input stream for next code: */
+        if (DGifBufferedInput(GifFile, Private->Buf, &NextByte) == GIF_ERROR) {
+            return GIF_ERROR;
+        }
+        Private->CrntShiftDWord |=
+           ((unsigned long)NextByte) << Private->CrntShiftState;
+        Private->CrntShiftState += 8;
+    }
+    *Code = Private->CrntShiftDWord & CodeMasks[Private->RunningBits];
+
+    Private->CrntShiftDWord >>= Private->RunningBits;
+    Private->CrntShiftState -= Private->RunningBits;
+
+    /* If code cannot fit into RunningBits bits, must raise its size. Note
+     * however that codes above 4095 are used for special signaling.
+     * If we're using LZ_BITS bits already and we're at the max code, just
+     * keep using the table as it is, don't increment Private->RunningCode.
+     */
+    if (Private->RunningCode < LZ_MAX_CODE + 2 &&
+            ++Private->RunningCode > Private->MaxCode1 &&
+            Private->RunningBits < LZ_BITS) {
+        Private->MaxCode1 <<= 1;
+        Private->RunningBits++;
+    }
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * This routines read one gif data block at a time and buffers it internally
+ * so that the decompression routine could access it.
+ * The routine returns the next byte from its internal buffer (or read next
+ * block in if buffer empty) and returns GIF_OK if successful.
+ *****************************************************************************/
+static int
+DGifBufferedInput(GifFileType * GifFile,
+                  GifByteType * Buf,
+                  GifByteType * NextByte) {
+
+    if (Buf[0] == 0) {
+        /* Needs to read the next buffer - this one is empty: */
+        if (READ(GifFile, Buf, 1) != 1) {
+            return GIF_ERROR;
+        }
+        /* There shouldn't be any empty data blocks here as the LZW spec
+         * says the LZW termination code should come first.  Therefore we
+         * shouldn't be inside this routine at that point.
+         */
+        if (Buf[0] == 0) {
+            return GIF_ERROR;
+        }
+        if (READ(GifFile, &Buf[1], Buf[0]) != Buf[0]) {
+            return GIF_ERROR;
+        }
+        *NextByte = Buf[1];
+        Buf[1] = 2;    /* We use now the second place as last char read! */
+        Buf[0]--;
+    } else {
+        *NextByte = Buf[Buf[1]++];
+        Buf[0]--;
+    }
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * This routine reads an entire GIF into core, hanging all its state info off
+ * the GifFileType pointer.  Call DGifOpenFileName() or DGifOpenFileHandle()
+ * first to initialize I/O.  Its inverse is EGifSpew().
+ ******************************************************************************/
+int
+DGifSlurp(GifFileType * GifFile) {
+
+    int ImageSize;
+    GifRecordType RecordType;
+    SavedImage *sp;
+    GifByteType *ExtData;
+    SavedImage temp_save;
+
+    temp_save.ExtensionBlocks = NULL;
+    temp_save.ExtensionBlockCount = 0;
+
+    do {
+        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)
+            return (GIF_ERROR);
+
+        switch (RecordType) {
+          case IMAGE_DESC_RECORD_TYPE:
+              if (DGifGetImageDesc(GifFile) == GIF_ERROR)
+                  return (GIF_ERROR);
+
+              sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
+              ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
+
+              sp->RasterBits = ungif_alloc(ImageSize * sizeof(GifPixelType));
+              if (sp->RasterBits == NULL) {
+                  return GIF_ERROR;
+              }
+              if (DGifGetLine(GifFile, sp->RasterBits, ImageSize) ==
+                  GIF_ERROR)
+                  return (GIF_ERROR);
+              if (temp_save.ExtensionBlocks) {
+                  sp->ExtensionBlocks = temp_save.ExtensionBlocks;
+                  sp->ExtensionBlockCount = temp_save.ExtensionBlockCount;
+
+                  temp_save.ExtensionBlocks = NULL;
+                  temp_save.ExtensionBlockCount = 0;
+
+                  /* FIXME: The following is wrong.  It is left in only for
+                   * backwards compatibility.  Someday it should go away. Use
+                   * the sp->ExtensionBlocks->Function variable instead. */
+                  sp->Function = sp->ExtensionBlocks[0].Function;
+              }
+              break;
+
+          case EXTENSION_RECORD_TYPE:
+              if (DGifGetExtension(GifFile, &temp_save.Function, &ExtData) ==
+                  GIF_ERROR)
+                  return (GIF_ERROR);
+              while (ExtData != NULL) {
+
+                  /* Create an extension block with our data */
+                  if (AddExtensionBlock(&temp_save, ExtData[0], &ExtData[1])
+                      == GIF_ERROR)
+                      return (GIF_ERROR);
+
+                  if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)
+                      return (GIF_ERROR);
+                  temp_save.Function = 0;
+              }
+              break;
+
+          case TERMINATE_RECORD_TYPE:
+              break;
+
+          default:    /* Should be trapped by DGifGetRecordType */
+              break;
+        }
+    } while (RecordType != TERMINATE_RECORD_TYPE);
+
+    /* Just in case the Gif has an extension block without an associated
+     * image... (Should we save this into a savefile structure with no image
+     * instead? Have to check if the present writing code can handle that as
+     * well.... */
+    if (temp_save.ExtensionBlocks)
+        FreeExtension(&temp_save);
+
+    return (GIF_OK);
+}
+
+/******************************************************************************
+ * GifFileType constructor with user supplied input function (TVT)
+ *****************************************************************************/
+GifFileType *
+DGifOpen(void *userData,
+         InputFunc readFunc) {
+
+    unsigned char Buf[GIF_STAMP_LEN + 1];
+    GifFileType *GifFile;
+    GifFilePrivateType *Private;
+
+    GifFile = ungif_alloc(sizeof(GifFileType));
+    if (GifFile == NULL) {
+        return NULL;
+    }
+
+    memset(GifFile, '\0', sizeof(GifFileType));
+
+    Private = ungif_alloc(sizeof(GifFilePrivateType));
+    if (!Private) {
+        ungif_free(GifFile);
+        return NULL;
+    }
+
+    GifFile->Private = (void*)Private;
+
+    Private->Read = readFunc;    /* TVT */
+    GifFile->UserData = userData;    /* TVT */
+
+    /* Lets see if this is a GIF file: */
+    if (READ(GifFile, Buf, GIF_STAMP_LEN) != GIF_STAMP_LEN) {
+        ungif_free(Private);
+        ungif_free(GifFile);
+        return NULL;
+    }
+
+    /* The GIF Version number is ignored at this time. Maybe we should do
+     * something more useful with it. */
+    Buf[GIF_STAMP_LEN] = 0;
+    if (memcmp(GIF_STAMP, Buf, GIF_VERSION_POS) != 0) {
+        ungif_free(Private);
+        ungif_free(GifFile);
+        return NULL;
+    }
+
+    if (DGifGetScreenDesc(GifFile) == GIF_ERROR) {
+        ungif_free(Private);
+        ungif_free(GifFile);
+        return NULL;
+    }
+
+    return GifFile;
+}
+
+/******************************************************************************
+ * This routine should be called last, to close the GIF file.
+ *****************************************************************************/
+int
+DGifCloseFile(GifFileType * GifFile) {
+
+    GifFilePrivateType *Private;
+
+    if (GifFile == NULL)
+        return GIF_ERROR;
+
+    Private = GifFile->Private;
+
+    if (GifFile->Image.ColorMap) {
+        FreeMapObject(GifFile->Image.ColorMap);
+        GifFile->Image.ColorMap = NULL;
+    }
+
+    if (GifFile->SColorMap) {
+        FreeMapObject(GifFile->SColorMap);
+        GifFile->SColorMap = NULL;
+    }
+
+    ungif_free(Private);
+    Private = NULL;
+
+    if (GifFile->SavedImages) {
+        FreeSavedImages(GifFile);
+        GifFile->SavedImages = NULL;
+    }
+
+    ungif_free(GifFile);
+
+    return GIF_OK;
+}
diff --git a/reactos/dll/win32/windowscodecs/ungif.h b/reactos/dll/win32/windowscodecs/ungif.h
new file mode 100644 (file)
index 0000000..e71dad8
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Gif extracting routines - derived from libungif
+ *
+ * Portions Copyright 2006 Mike McCormack
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * Original copyright notice:
+ *
+ * The GIFLIB distribution is Copyright (c) 1997  Eric S. Raymond
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ */
+
+/******************************************************************************
+ * In order to make life a little bit easier when using the GIF file format,
+ * this library was written, and which does all the dirty work...
+ *
+ *                                        Written by Gershon Elber,  Jun. 1989
+ *                                        Hacks by Eric S. Raymond,  Sep. 1992
+ ******************************************************************************
+ * History:
+ * 14 Jun 89 - Version 1.0 by Gershon Elber.
+ *  3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names)
+ * 15 Sep 90 - Version 2.0 by Eric S. Raymond (Changes to support GIF slurp)
+ * 26 Jun 96 - Version 3.0 by Eric S. Raymond (Full GIF89 support)
+ * 17 Dec 98 - Version 4.0 by Toshio Kuratomi (Fix extension writing code)
+ *****************************************************************************/
+
+#ifndef _UNGIF_H_
+#define _UNGIF_H_ 1
+
+#define GIF_ERROR   0
+#define GIF_OK      1
+
+#ifndef TRUE
+#define TRUE        1
+#endif /* TRUE */
+#ifndef FALSE
+#define FALSE       0
+#endif /* FALSE */
+
+#ifndef NULL
+#define NULL        0
+#endif /* NULL */
+
+#define GIF_STAMP "GIFVER"          /* First chars in file - GIF stamp.  */
+#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
+#define GIF_VERSION_POS 3           /* Version first character in stamp. */
+#define GIF87_STAMP "GIF87a"        /* First chars in file - GIF stamp.  */
+#define GIF89_STAMP "GIF89a"        /* First chars in file - GIF stamp.  */
+
+#define GIF_FILE_BUFFER_SIZE 16384  /* Files uses bigger buffers than usual. */
+
+typedef int GifBooleanType;
+typedef unsigned char GifPixelType;
+typedef unsigned char *GifRowType;
+typedef unsigned char GifByteType;
+typedef unsigned int GifPrefixType;
+typedef int GifWord;
+
+typedef struct GifColorType {
+    GifByteType Red, Green, Blue;
+} GifColorType;
+
+typedef struct ColorMapObject {
+    int ColorCount;
+    int BitsPerPixel;
+    GifColorType *Colors;
+} ColorMapObject;
+
+typedef struct GifImageDesc {
+    GifWord Left, Top, Width, Height,   /* Current image dimensions. */
+      Interlace;                    /* Sequential/Interlaced lines. */
+    ColorMapObject *ColorMap;       /* The local color map */
+} GifImageDesc;
+
+typedef struct GifFileType {
+    GifWord SWidth, SHeight,        /* Screen dimensions. */
+      SColorResolution,         /* How many colors can we generate? */
+      SBackGroundColor;         /* I hope you understand this one... */
+    ColorMapObject *SColorMap;  /* NULL if not exists. */
+    int ImageCount;             /* Number of current image */
+    GifImageDesc Image;         /* Block describing current image */
+    struct SavedImage *SavedImages; /* Use this to accumulate file state */
+    void *UserData;             /* hook to attach user data (TVT) */
+    void *Private;              /* Don't mess with this! */
+} GifFileType;
+
+typedef enum {
+    UNDEFINED_RECORD_TYPE,
+    SCREEN_DESC_RECORD_TYPE,
+    IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
+    EXTENSION_RECORD_TYPE,  /* Begin with '!' */
+    TERMINATE_RECORD_TYPE   /* Begin with ';' */
+} GifRecordType;
+
+/* func type to read gif data from arbitrary sources (TVT) */
+typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
+
+/*  GIF89 extension function codes */
+
+#define COMMENT_EXT_FUNC_CODE     0xfe    /* comment */
+#define GRAPHICS_EXT_FUNC_CODE    0xf9    /* graphics control */
+#define PLAINTEXT_EXT_FUNC_CODE   0x01    /* plaintext */
+#define APPLICATION_EXT_FUNC_CODE 0xff    /* application block */
+
+/* public interface to ungif.c */
+int DGifSlurp(GifFileType * GifFile);
+GifFileType *DGifOpen(void *userPtr, InputFunc readFunc);
+int DGifCloseFile(GifFileType * GifFile);
+
+#define D_GIF_ERR_OPEN_FAILED    101    /* And DGif possible errors. */
+#define D_GIF_ERR_READ_FAILED    102
+#define D_GIF_ERR_NOT_GIF_FILE   103
+#define D_GIF_ERR_NO_SCRN_DSCR   104
+#define D_GIF_ERR_NO_IMAG_DSCR   105
+#define D_GIF_ERR_NO_COLOR_MAP   106
+#define D_GIF_ERR_WRONG_RECORD   107
+#define D_GIF_ERR_DATA_TOO_BIG   108
+#define D_GIF_ERR_NOT_ENOUGH_MEM 109
+#define D_GIF_ERR_CLOSE_FAILED   110
+#define D_GIF_ERR_NOT_READABLE   111
+#define D_GIF_ERR_IMAGE_DEFECT   112
+#define D_GIF_ERR_EOF_TOO_SOON   113
+
+/******************************************************************************
+ * Support for the in-core structures allocation (slurp mode).
+ *****************************************************************************/
+
+/* This is the in-core version of an extension record */
+typedef struct {
+    int ByteCount;
+    char *Bytes;
+    int Function;   /* Holds the type of the Extension block. */
+} ExtensionBlock;
+
+/* This holds an image header, its unpacked raster bits, and extensions */
+typedef struct SavedImage {
+    GifImageDesc ImageDesc;
+    unsigned char *RasterBits;
+    int Function;   /* DEPRECATED: Use ExtensionBlocks[x].Function instead */
+    int ExtensionBlockCount;
+    ExtensionBlock *ExtensionBlocks;
+} SavedImage;
+
+#endif /* _UNGIF_H_ */
diff --git a/reactos/dll/win32/windowscodecs/version.rc b/reactos/dll/win32/windowscodecs/version.rc
new file mode 100644 (file)
index 0000000..40378d3
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2008 Louis Lenders
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WINE_FILEDESCRIPTION_STR "Wine Windows Codecs Library"
+#define WINE_FILENAME_STR "windowscodecs.dll"
+#define WINE_FILEVERSION 6,0,6001,170099
+#define WINE_FILEVERSION_STR "6.0.6001.17009"
+#define WINE_PRODUCTVERSION 6,0,6001,170099
+#define WINE_PRODUCTVERSION_STR "6.0.6001.17009"
+
+#include "wine/wine_common_ver.rc"
diff --git a/reactos/dll/win32/windowscodecs/wincodecs_private.h b/reactos/dll/win32/windowscodecs/wincodecs_private.h
new file mode 100644 (file)
index 0000000..d4441d0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef WINCODECS_PRIVATE_H
+#define WINCODECS_PRIVATE_H
+
+extern HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
+extern HRESULT ImagingFactory_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
+extern HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
+extern HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv);
+extern HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID riid, void** ppv);
+extern HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv);
+
+extern HRESULT PaletteImpl_Create(IWICPalette **palette);
+extern HRESULT StreamImpl_Create(IWICStream **stream);
+
+extern HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
+    UINT srcwidth, UINT srcheight, INT srcstride,
+    const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer);
+
+extern HRESULT CreatePropertyBag2(IPropertyBag2 **ppPropertyBag2);
+
+extern HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo);
+extern HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown);
+
+#endif /* WINCODECS_PRIVATE_H */
diff --git a/reactos/dll/win32/windowscodecs/windowscodecs.rbuild b/reactos/dll/win32/windowscodecs/windowscodecs.rbuild
new file mode 100644 (file)
index 0000000..2f0c872
--- /dev/null
@@ -0,0 +1,32 @@
+<module name="windowscodecs" type="win32dll" baseaddress="${BASEADDRESS_WINDOWSCODECS}" installbase="system32" installname="windowscodecs.dll" allowwarnings="true">
+       <autoregister infsection="OleControlDlls" type="DllRegisterServer" />
+       <importlibrary definition="windowscodecs.spec" />
+       <include base="windowscodecs">.</include>
+       <include base="ReactOS">include/reactos/wine</include>
+       <define name="__WINESRC__" />
+
+       <redefine name="_WIN32_WINNT">0x600</redefine>
+
+       <library>wine</library>
+       <library>uuid</library>
+       <library>ole32</library>
+       <library>advapi32</library>
+       <library>kernel32</library>
+
+       <file>bmpdecode.c</file>
+       <file>bmpencode.c</file>
+       <file>clsfactory.c</file>
+       <file>converter.c</file>
+       <file>gifformat.c</file>
+       <file>icoformat.c</file>
+       <file>imgfactory.c</file>
+       <file>info.c</file>
+       <file>main.c</file>
+       <file>palette.c</file>
+       <file>propertybag.c</file>
+       <file>regsvr.c</file>
+       <file>stream.c</file>
+       <file>ungif.c</file>
+
+       <file>version.rc</file>
+</module>
diff --git a/reactos/dll/win32/windowscodecs/windowscodecs.spec b/reactos/dll/win32/windowscodecs/windowscodecs.spec
new file mode 100644 (file)
index 0000000..d0b6a7e
--- /dev/null
@@ -0,0 +1,116 @@
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
+@ stub IEnumString_Next_WIC_Proxy
+@ stub IEnumString_Reset_WIC_Proxy
+@ stub IPropertyBag2_Write_Proxy
+@ stub IWICBitmapClipper_Initialize_Proxy
+@ stub IWICBitmapCodecInfo_DoesSupportAnimation_Proxy
+@ stub IWICBitmapCodecInfo_DoesSupportLossless_Proxy
+@ stub IWICBitmapCodecInfo_DoesSupportMultiframe_Proxy
+@ stub IWICBitmapCodecInfo_GetContainerFormat_Proxy
+@ stub IWICBitmapCodecInfo_GetDeviceManufacturer_Proxy
+@ stub IWICBitmapCodecInfo_GetDeviceModels_Proxy
+@ stub IWICBitmapCodecInfo_GetFileExtensions_Proxy
+@ stub IWICBitmapCodecInfo_GetMimeTypes_Proxy
+@ stub IWICBitmapDecoder_CopyPalette_Proxy
+@ stub IWICBitmapDecoder_GetColorContexts_Proxy
+@ stub IWICBitmapDecoder_GetDecoderInfo_Proxy
+@ stub IWICBitmapDecoder_GetFrameCount_Proxy
+@ stub IWICBitmapDecoder_GetFrame_Proxy
+@ stub IWICBitmapDecoder_GetMetadataQueryReader_Proxy
+@ stub IWICBitmapDecoder_GetPreview_Proxy
+@ stub IWICBitmapDecoder_GetThumbnail_Proxy
+@ stub IWICBitmapEncoder_Commit_Proxy
+@ stub IWICBitmapEncoder_CreateNewFrame_Proxy
+@ stub IWICBitmapEncoder_GetEncoderInfo_Proxy
+@ stub IWICBitmapEncoder_GetMetadataQueryWriter_Proxy
+@ stub IWICBitmapEncoder_Initialize_Proxy
+@ stub IWICBitmapEncoder_SetPalette_Proxy
+@ stub IWICBitmapEncoder_SetThumbnail_Proxy
+@ stub IWICBitmapFlipRotator_Initialize_Proxy
+@ stub IWICBitmapFrameDecode_GetColorContexts_Proxy
+@ stub IWICBitmapFrameDecode_GetMetadataQueryReader_Proxy
+@ stub IWICBitmapFrameDecode_GetThumbnail_Proxy
+@ stub IWICBitmapFrameEncode_Commit_Proxy
+@ stub IWICBitmapFrameEncode_GetMetadataQueryWriter_Proxy
+@ stub IWICBitmapFrameEncode_Initialize_Proxy
+@ stub IWICBitmapFrameEncode_SetColorContexts_Proxy
+@ stub IWICBitmapFrameEncode_SetResolution_Proxy
+@ stub IWICBitmapFrameEncode_SetSize_Proxy
+@ stub IWICBitmapFrameEncode_SetThumbnail_Proxy
+@ stub IWICBitmapFrameEncode_WriteSource_Proxy
+@ stub IWICBitmapLock_GetDataPointer_STA_Proxy
+@ stub IWICBitmapLock_GetStride_Proxy
+@ stub IWICBitmapScaler_Initialize_Proxy
+@ stub IWICBitmapSource_CopyPalette_Proxy
+@ stub IWICBitmapSource_CopyPixels_Proxy
+@ stub IWICBitmapSource_GetPixelFormat_Proxy
+@ stub IWICBitmapSource_GetResolution_Proxy
+@ stub IWICBitmapSource_GetSize_Proxy
+@ stub IWICBitmap_Lock_Proxy
+@ stub IWICBitmap_SetPalette_Proxy
+@ stub IWICBitmap_SetResolution_Proxy
+@ stub IWICColorContext_InitializeFromMemory_Proxy
+@ stub IWICComponentFactory_CreateMetadataWriterFromReader_Proxy
+@ stub IWICComponentFactory_CreateQueryWriterFromBlockWriter_Proxy
+@ stub IWICComponentInfo_GetAuthor_Proxy
+@ stub IWICComponentInfo_GetCLSID_Proxy
+@ stub IWICComponentInfo_GetFriendlyName_Proxy
+@ stub IWICComponentInfo_GetSpecVersion_Proxy
+@ stub IWICComponentInfo_GetVersion_Proxy
+@ stub IWICFastMetadataEncoder_Commit_Proxy
+@ stub IWICFastMetadataEncoder_GetMetadataQueryWriter_Proxy
+@ stub IWICFormatConverter_Initialize_Proxy
+@ stub IWICImagingFactory_CreateBitmapClipper_Proxy
+@ stub IWICImagingFactory_CreateBitmapFlipRotator_Proxy
+@ stub IWICImagingFactory_CreateBitmapFromHBITMAP_Proxy
+@ stub IWICImagingFactory_CreateBitmapFromHICON_Proxy
+@ stub IWICImagingFactory_CreateBitmapFromMemory_Proxy
+@ stub IWICImagingFactory_CreateBitmapFromSource_Proxy
+@ stub IWICImagingFactory_CreateBitmapScaler_Proxy
+@ stub IWICImagingFactory_CreateBitmap_Proxy
+@ stub IWICImagingFactory_CreateComponentInfo_Proxy
+@ stub IWICImagingFactory_CreateDecoderFromFileHandle_Proxy
+@ stub IWICImagingFactory_CreateDecoderFromFilename_Proxy
+@ stub IWICImagingFactory_CreateDecoderFromStream_Proxy
+@ stub IWICImagingFactory_CreateEncoder_Proxy
+@ stub IWICImagingFactory_CreateFastMetadataEncoderFromDecoder_Proxy
+@ stub IWICImagingFactory_CreateFastMetadataEncoderFromFrameDecode_Proxy
+@ stub IWICImagingFactory_CreateFormatConverter_Proxy
+@ stub IWICImagingFactory_CreatePalette_Proxy
+@ stub IWICImagingFactory_CreateQueryWriterFromReader_Proxy
+@ stub IWICImagingFactory_CreateQueryWriter_Proxy
+@ stub IWICImagingFactory_CreateStream_Proxy
+@ stub IWICMetadataBlockReader_GetCount_Proxy
+@ stub IWICMetadataBlockReader_GetReaderByIndex_Proxy
+@ stub IWICMetadataQueryReader_GetContainerFormat_Proxy
+@ stub IWICMetadataQueryReader_GetEnumerator_Proxy
+@ stub IWICMetadataQueryReader_GetLocation_Proxy
+@ stub IWICMetadataQueryReader_GetMetadataByName_Proxy
+@ stub IWICMetadataQueryWriter_RemoveMetadataByName_Proxy
+@ stub IWICMetadataQueryWriter_SetMetadataByName_Proxy
+@ stub IWICPalette_GetColorCount_Proxy
+@ stub IWICPalette_GetColors_Proxy
+@ stub IWICPalette_GetType_Proxy
+@ stub IWICPalette_HasAlpha_Proxy
+@ stub IWICPalette_InitializeCustom_Proxy
+@ stub IWICPalette_InitializeFromBitmap_Proxy
+@ stub IWICPalette_InitializeFromPalette_Proxy
+@ stub IWICPalette_InitializePredefined_Proxy
+@ stub IWICPixelFormatInfo_GetBitsPerPixel_Proxy
+@ stub IWICPixelFormatInfo_GetChannelCount_Proxy
+@ stub IWICPixelFormatInfo_GetChannelMask_Proxy
+@ stub IWICStream_InitializeFromIStream_Proxy
+@ stub IWICStream_InitializeFromMemory_Proxy
+@ stdcall WICConvertBitmapSource(ptr ptr ptr)
+@ stub WICCreateBitmapFromSection
+@ stub WICCreateColorContext_Proxy
+@ stub WICCreateImagingFactory_Proxy
+@ stub WICGetMetadataContentSize
+@ stub WICMapGuidToShortName
+@ stub WICMapSchemaToName
+@ stub WICMapShortNameToGuid
+@ stub WICMatchMetadataContent
+@ stub WICSerializeMetadataContent
+@ stub WICSetEncoderFormat_Proxy
index 283aeab..ad9c497 100644 (file)
@@ -52,6 +52,7 @@
        <file>unknwn.idl</file>
        <file>urlhist.idl</file>
        <file>urlmon.idl</file>
+       <file>wincodec.idl</file>
        <file>mimeole.idl</file>
        <file>mscoree.idl</file>
        <file>mshtmhst.idl</file>
diff --git a/reactos/include/psdk/wincodec.idl b/reactos/include/psdk/wincodec.idl
new file mode 100644 (file)
index 0000000..80601c1
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * Copyright 2009 Vincent Povirk for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+import "wtypes.idl";
+import "propidl.idl";
+import "objidl.idl";
+import "ocidl.idl";
+
+#define CODEC_FORCE_DWORD 0x7fffffff
+
+typedef enum WICDecodeOptions {
+    WICDecodeMetadataCacheOnDemand = 0x00000000,
+    WICDecodeMetadataCacheOnLoad = 0x00000001,
+    WICMETADATACACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICDecodeOptions;
+
+typedef enum WICBitmapCreateCacheOption {
+    WICBitmapNoCache = 0x00000000,
+    WICBitmapCacheOnDemand = 0x00000001,
+    WICBitmapCacheOnLoad = 0x00000002,
+    WICBITMAPCREATECACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICBitmapCreateCacheOption;
+
+typedef enum WICBitmapAlphaChannelOption {
+    WICBitmapUseAlpha = 0x00000000,
+    WICBitmapUsePremultipliedAlpha = 0x00000001,
+    WICBitmapIgnoreAlpha = 0x00000002,
+    WICBITMAPALPHACHANNELOPTIONS_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICBitmapAlphaChannelOption;
+
+typedef enum WICBitmapDecoderCapabilities {
+    WICBitmapDecoderCapabilitySameEncoder = 0x00000001,
+    WICBitmapDecoderCapabilityCanDecodeAllImages = 0x00000002,
+    WICBitmapDecoderCapabilityCanDecodeSomeImages = 0x00000004,
+    WICBitmapDecoderCapabilityCanEnumerateMetadata = 0x00000008,
+    WICBitmapDecoderCapabilityCanDecodeThumbnail = 0x00000010,
+} WICBitmapDecoderCapabilities;
+
+typedef enum WICBitmapDitherType {
+    WICBitmapDitherTypeNone = 0x00000000,
+    WICBitmapDitherTypeSolid = 0x00000000,
+    WICBitmapDitherTypeOrdered4x4 = 0x00000001,
+    WICBitmapDitherTypeOrdered8x8 = 0x00000002,
+    WICBitmapDitherTypeOrdered16x16 = 0x00000003,
+    WICBitmapDitherTypeSpiral4x4 = 0x00000004,
+    WICBitmapDitherTypeSpiral8x8 = 0x00000005,
+    WICBitmapDitherTypeDualSpiral4x4 = 0x00000006,
+    WICBitmapDitherTypeDualSpiral8x8 = 0x00000007,
+    WICBitmapDitherTypeErrorDiffusion = 0x00000008,
+    WICBITMAPDITHERTYPE_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICBitmapDitherType;
+
+typedef enum WICBitmapEncoderCacheOption {
+    WICBitmapEncoderCacheInMemory = 0x00000000,
+    WICBitmapEncoderCacheTempFile = 0x00000001,
+    WICBitmapEncoderNoCache = 0x00000002,
+    WICBITMAPENCODERCACHEOPTION_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICBitmapEncoderCacheOption;
+
+typedef enum WICBitmapPaletteType {
+    WICBitmapPaletteTypeCustom = 0x00000000,
+    WICBitmapPaletteTypeMedianCut = 0x00000001,
+    WICBitmapPaletteTypeFixedBW = 0x00000002,
+    WICBitmapPaletteTypeFixedHalftone8 = 0x00000003,
+    WICBitmapPaletteTypeFixedHalftone27 = 0x00000004,
+    WICBitmapPaletteTypeFixedHalftone64 = 0x00000005,
+    WICBitmapPaletteTypeFixedHalftone125 = 0x00000006,
+    WICBitmapPaletteTypeFixedHalftone216 = 0x00000007,
+    WICBitmapPaletteTypeFixedWebPalette = WICBitmapPaletteTypeFixedHalftone216,
+    WICBitmapPaletteTypeFixedHalftone252 = 0x00000008,
+    WICBitmapPaletteTypeFixedHalftone256 = 0x00000009,
+    WICBitmapPaletteTypeFixedGray4 = 0x0000000A,
+    WICBitmapPaletteTypeFixedGray16 = 0x0000000B,
+    WICBitmapPaletteTypeFixedGray256 = 0x0000000C,
+    WICBITMAPPALETTETYPE_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICBitmapPaletteType;
+
+typedef enum WICComponentType {
+    WICDecoder = 0x00000001,
+    WICEncoder = 0x00000002,
+    WICPixelFormatConverter = 0x00000004,
+    WICMetadataReader = 0x00000008,
+    WICMetadataWriter = 0x00000010,
+    WICPixelFormat = 0x00000020,
+    WICCOMPONENTTYPE_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICComponentType;
+
+typedef enum WICComponentSigning {
+    WICComponentSigned = 0x00000001,
+    WICComponentUnsigned = 0x00000002,
+    WICComponentSafe = 0x00000004,
+    WICComponentDisabled = 0x80000000
+} WICComponentSigning;
+
+typedef enum WICComponentEnumerateOptions {
+    WICComponentEnumerateDefault = 0x00000000,
+    WICComponentEnumerateRefresh = 0x00000001,
+    WICComponentEnumerateBuiltInOnly = 0x20000000,
+    WICComponentEnumerateUnsigned = 0x40000000,
+    WICComponentEnumerateDisabled = 0x80000000
+} WICComponentEnumerateOptions;
+
+typedef GUID WICPixelFormatGUID;
+typedef REFGUID REFWICPixelFormatGUID;
+
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormatDontCare, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x00);")
+cpp_quote("#define GUID_WICPixelFormatUndefined GUID_WICPixelFormatDontCare")
+
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat1bppIndexed, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x01);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat2bppIndexed, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x02);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat4bppIndexed, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x03);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat8bppIndexed, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x04);")
+
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat16bppBGR555, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x09);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat16bppBGR565, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x0a);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat24bppBGR, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x0c);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat32bppBGR, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x0e);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat32bppBGRA, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x0f);")
+cpp_quote("DEFINE_GUID(GUID_WICPixelFormat32bppPBGRA, 0x6fddc324,0x4e03,0x4bfe,0xb1,0x85,0x3d,0x77,0x76,0x8d,0xc9,0x10);")
+
+typedef struct WICRect {
+    INT X;
+    INT Y;
+    INT Width;
+    INT Height;
+} WICRect;
+
+typedef struct WICBitmapPattern {
+    ULARGE_INTEGER Position;
+    ULONG Length;
+    BYTE *Pattern;
+    BYTE *Mask;
+    BOOL EndOfStream;
+} WICBitmapPattern;
+
+typedef UINT32 WICColor;
+
+cpp_quote("#define WINCODEC_ERR_WRONGSTATE 0x88982f04")
+cpp_quote("#define WINCODEC_ERR_NOTINITIALIZED 0x88982f0c")
+cpp_quote("#define WINCODEC_ERR_CODECNOTHUMBNAIL 0x88982f44")
+cpp_quote("#define WINCODEC_ERR_PALETTEUNAVAILABLE 0x88982f45")
+cpp_quote("#define WINCODEC_ERR_COMPONENTNOTFOUND 0x88982f50")
+cpp_quote("#define WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT 0x88982f80")
+cpp_quote("#define WINCODEC_ERR_UNSUPPORTEDOPERATION 0x88982f81")
+cpp_quote("#define WINCODEC_ERR_INSUFFICIENTBUFFER 0x88982f8c")
+
+interface IWICBitmap;
+interface IWICPalette;
+interface IWICBitmapScaler;
+interface IWICBitmapClipper;
+interface IWICBitmapFlipRotator;
+interface IWICColorContext;
+interface IWICColorTransform;
+interface IWICFastMetadataEncoder;
+interface IWICMetadataQueryReader;
+interface IWICMetadataQueryWriter;
+
+[
+    object,
+    uuid(00000120-a8f2-4877-ba0a-fd2b6645fb94)
+]
+interface IWICBitmapSource : IUnknown
+{
+    HRESULT GetSize(
+        [out] UINT *puiWidth,
+        [out] UINT *puiHeight);
+
+    HRESULT GetPixelFormat(
+        [out] WICPixelFormatGUID *pPixelFormat);
+
+    HRESULT GetResolution(
+        [out] double *pDpiX,
+        [out] double *pDpiY);
+
+    HRESULT CopyPalette(
+        [in] IWICPalette *pIPalette);
+
+    HRESULT CopyPixels(
+        [in] const WICRect *prc,
+        [in] UINT cbStride,
+        [in] UINT cbBufferSize,
+        [out, size_is(cbBufferSize)] BYTE *pbBuffer);
+}
+
+[
+    object,
+    uuid(00000040-a8f2-4877-ba0a-fd2b6645fb94)
+]
+interface IWICPalette : IUnknown
+{
+    HRESULT InitializePredefined(
+        [in] WICBitmapPaletteType ePaletteType,
+        [in] BOOL fAddTransparentColor);
+
+    HRESULT InitializeCustom(
+        [in, size_is(colorCount)] WICColor *pColors,
+        [in] UINT colorCount);
+
+    HRESULT InitializeFromBitmap(
+        [in] IWICBitmapSource *pISurface,
+        [in] UINT colorCount,
+        [in] BOOL fAddTransparentColor);
+
+    HRESULT InitializeFromPalette(
+        [in] IWICPalette *pIPalette);
+
+    HRESULT GetType(
+        [out] WICBitmapPaletteType *pePaletteType);
+
+    HRESULT GetColorCount(
+        [out] UINT *pcCount);
+
+    HRESULT GetColors(
+        [in] UINT colorCount,
+        [out, size_is(colorCount)] WICColor *pColors,
+        [out] UINT *pcActualColors);
+
+    HRESULT IsBlackWhite(
+        [out] BOOL *pfIsBlackWhite);
+
+    HRESULT IsGrayscale(
+        [out] BOOL *pfIsGrayscale);
+
+    HRESULT HasAlpha(
+        [out] BOOL *pfHasAlpha);
+}
+
+[
+    object,
+    uuid(23bc3f0a-698b-4357-886b-f24d50671334)
+]
+interface IWICComponentInfo : IUnknown
+{
+    HRESULT GetComponentType(
+        [out] WICComponentType *pType);
+
+    HRESULT GetCLSID(
+        [out] CLSID *pclsid);
+
+    HRESULT GetSigningStatus(
+        [out] DWORD *pStatus);
+
+    HRESULT GetAuthor(
+        [in] UINT cchAuthor,
+        [in, out, unique, size_is(cchAuthor)] WCHAR *wzAuthor,
+        [out] UINT *pcchActual);
+
+    HRESULT GetVendorGUID(
+        [out] GUID *pguidVendor);
+
+    HRESULT GetVersion(
+        [in] UINT cchVersion,
+        [in, out, unique, size_is(cchVersion)] WCHAR *wzVersion,
+        [out] UINT *pcchActual);
+
+    HRESULT GetSpecVersion(
+        [in] UINT cchSpecVersion,
+        [in, out, unique, size_is(cchSpecVersion)] WCHAR *wzSpecVersion,
+        [out] UINT *pcchActual);
+
+    HRESULT GetFriendlyName(
+        [in] UINT cchFriendlyName,
+        [in, out, unique, size_is(cchFriendlyName)] WCHAR *wzFriendlyName,
+        [out] UINT *pcchActual);
+}
+
+[
+    object,
+    uuid(3b16811b-6a43-4ec9-a813-3d930c13b940)
+]
+interface IWICBitmapFrameDecode : IWICBitmapSource
+{
+    HRESULT GetMetadataQueryReader(
+        [out] IWICMetadataQueryReader **ppIMetadataQueryReader);
+
+    HRESULT GetColorContexts(
+        [in] UINT cCount,
+        [in, out, unique, size_is(cCount)] IWICColorContext **ppIColorContexts,
+        [out] UINT *pcActualCount);
+
+    HRESULT GetThumbnail(
+        [out] IWICBitmapSource **ppIThumbnail);
+}
+
+[
+    object,
+    uuid(e87a44c4-b76e-4c47-8b09-298eb12a2714)
+]
+interface IWICBitmapCodecInfo : IWICComponentInfo
+{
+    HRESULT GetContainerFormat(
+        [out] GUID *pguidContainerFormat);
+
+    HRESULT GetPixelFormats(
+        [in] UINT cFormats,
+        [in, out, unique, size_is(cFormats)] GUID *pguidPixelFormats,
+        [out] UINT *pcActual);
+
+    HRESULT GetColorManagementVersion(
+        [in] UINT cchColorManagementVersion,
+        [in, out, unique, size_is(cchColorManagementVersion)] WCHAR *wzColorManagementVersion,
+        [out] UINT *pcchActual);
+
+    HRESULT GetDeviceManufacturer(
+        [in] UINT cchDeviceManufacturer,
+        [in, out, unique, size_is(cchDeviceManufacturer)] WCHAR *wzDeviceManufacturer,
+        [out] UINT *pcchActual);
+
+    HRESULT GetDeviceModels(
+        [in] UINT cchDeviceModels,
+        [in, out, unique, size_is(cchDeviceModels)] WCHAR *wzDeviceModels,
+        [out] UINT *pcchActual);
+
+    HRESULT GetMimeTypes(
+        [in] UINT cchMimeTypes,
+        [in, out, unique, size_is(cchMimeTypes)] WCHAR *wzMimeTypes,
+        [out] UINT *pcchActual);
+
+    HRESULT GetFileExtensions(
+        [in] UINT cchFileExtensions,
+        [in, out, unique, size_is(cchFileExtensions)] WCHAR *wzFileExtensions,
+        [out] UINT *pcchActual);
+
+    HRESULT DoesSupportAnimation(
+        [out] BOOL *pfSupportAnimation);
+
+    HRESULT DoesSupportChromaKey(
+        [out] BOOL *pfSupportChromaKey);
+
+    HRESULT DoesSupportLossless(
+        [out] BOOL *pfSupportLossless);
+
+    HRESULT DoesSupportMultiframe(
+        [out] BOOL *pfSupportMultiframe);
+
+    HRESULT MatchesMimeType(
+        [in] LPCWSTR wzMimeType,
+        [out] BOOL *pfMatches);
+}
+
+interface IWICBitmapDecoder;
+
+[
+    object,
+    uuid(d8cd007f-d08f-4191-9bfc-236ea7f0e4b5)
+]
+interface IWICBitmapDecoderInfo : IWICBitmapCodecInfo
+{
+    [local]
+    HRESULT GetPatterns(
+        [in] UINT cbSizePatterns,
+        [in, out, unique] WICBitmapPattern *pPatterns,
+        [in, out, unique] UINT *pcPatterns,
+        [in, out, unique] UINT *pcbPatternsActual);
+
+    HRESULT MatchesPattern(
+        [in] IStream *pIStream,
+        [out] BOOL *pfMatches);
+
+    HRESULT CreateInstance(
+        [out] IWICBitmapDecoder **ppIBitmapDecoder);
+}
+
+[
+    object,
+    uuid(9edde9e7-8dee-47ea-99df-e6faf2ed44bf)
+]
+interface IWICBitmapDecoder : IUnknown
+{
+    HRESULT QueryCapability(
+        [in] IStream *pIStream,
+        [out] DWORD *pdwCapability);
+
+    HRESULT Initialize(
+        [in] IStream *pIStream,
+        [in] WICDecodeOptions cacheOptions);
+
+    HRESULT GetContainerFormat(
+        [out] GUID *pguidContainerFormat);
+
+    HRESULT GetDecoderInfo(
+        [out] IWICBitmapDecoderInfo **ppIDecoderInfo);
+
+    HRESULT CopyPalette(
+        [in] IWICPalette *pIPalette);
+
+    HRESULT GetMetadataQueryReader(
+        [out] IWICMetadataQueryReader **ppIMetadataQueryReader);
+
+    HRESULT GetPreview(
+        [out] IWICBitmapSource **ppIBitmapSource);
+
+    HRESULT GetColorContexts(
+        [in] UINT cCount,
+        [in, out, unique, size_is(cCount)] IWICColorContext **ppIColorContexts,
+        [out] UINT *pcActualCount);
+
+    HRESULT GetThumbnail(
+        [out] IWICBitmapSource **ppIThumbnail);
+
+    HRESULT GetFrameCount(
+        [out] UINT *pCount);
+
+    HRESULT GetFrame(
+        [in] UINT index,
+        [out] IWICBitmapFrameDecode **ppIBitmapFrame);
+}
+
+[
+    object,
+    uuid(00000105-a8f2-4877-ba0a-fd2b6645fb94)
+]
+interface IWICBitmapFrameEncode : IUnknown
+{
+    HRESULT Initialize(
+        [in, unique] IPropertyBag2 *pIEncoderOptions);
+
+    HRESULT SetSize(
+        [in] UINT uiWidth,
+        [in] UINT uiHeight);
+
+    HRESULT SetResolution(
+        [in] double dpiX,
+        [in] double dpiY);
+
+    HRESULT SetPixelFormat(
+        [in, out] WICPixelFormatGUID *pPixelFormat);
+
+    HRESULT SetColorContexts(
+        [in] UINT cCount,
+        [in, size_is(cCount)] IWICColorContext **ppIColorContext);
+
+    HRESULT SetPalette(
+        [in] IWICPalette *pIPalette);
+
+    HRESULT SetThumbnail(
+        [in] IWICBitmapSource *pIThumbnail);
+
+    HRESULT WritePixels(
+        [in] UINT lineCount,
+        [in] UINT cbStride,
+        [in] UINT cbBufferSize,
+        [in, size_is(cbBufferSize)] BYTE *pbPixels);
+
+    HRESULT WriteSource(
+        [in] IWICBitmapSource *pIBitmapSource,
+        [in, unique] WICRect *prc);
+
+    HRESULT Commit();
+
+    HRESULT GetMetadataQueryWriter(
+        IWICMetadataQueryWriter **ppIMetadataQueryWriter);
+}
+
+interface IWICBitmapEncoder;
+
+[
+    object,
+    uuid(94c9b4ee-a09f-4f92-8a1e-4a9bce7e76fb)
+]
+interface IWICBitmapEncoderInfo : IWICBitmapCodecInfo
+{
+    HRESULT CreateInstance(
+        [out] IWICBitmapEncoder **ppIBitmapEncoder);
+}
+
+[
+    object,
+    uuid(00000103-a8f2-4877-ba0a-fd2b6645fb94)
+]
+interface IWICBitmapEncoder : IUnknown
+{
+    HRESULT Initialize(
+        [in] IStream *pIStream,
+        [in] WICBitmapEncoderCacheOption cacheOption);
+
+    HRESULT GetContainerFormat(
+        [out] GUID *pguidContainerFormat);
+
+    HRESULT GetEncoderInfo(
+        [out] IWICBitmapEncoderInfo **ppIEncoderInfo);
+
+    HRESULT SetColorContexts(
+        [in] UINT cCount,
+        [in, size_is(cCount)] IWICColorContext **ppIColorContext);
+
+    HRESULT SetPalette(
+        [in] IWICPalette *pIPalette);
+
+    HRESULT SetThumbnail(
+        [in] IWICBitmapSource *pIThumbnail);
+
+    HRESULT SetPreview(
+        [in] IWICBitmapSource *pIPreview);
+
+    HRESULT CreateNewFrame(
+        [out] IWICBitmapFrameEncode **ppIFrameEncode,
+        [in, out, unique] IPropertyBag2 **ppIEncoderOptions);
+
+    HRESULT Commit();
+
+    HRESULT GetMetadataQueryWriter(
+        [out] IWICMetadataQueryWriter **ppIMetadataQueryWriter);
+}
+
+[
+    object,
+    uuid(00000301-a8f2-4877-ba0a-fd2b6645fb94)
+]
+interface IWICFormatConverter : IWICBitmapSource
+{
+    HRESULT Initialize(
+        [in] IWICBitmapSource *pISource,
+        [in] REFWICPixelFormatGUID dstFormat,
+        [in] WICBitmapDitherType dither,
+        [in] IWICPalette *pIPalette,
+        [in] double alphaThresholdPercent,
+        [in] WICBitmapPaletteType paletteTranslate);
+
+    HRESULT CanConvert(
+        [in] REFWICPixelFormatGUID srcPixelFormat,
+        [in] REFWICPixelFormatGUID dstPixelFormat,
+        [out] BOOL *pfCanConvert);
+}
+
+[
+    object,
+    uuid(9f34fb65-13f4-4f15-bc57-3726b5e53d9f)
+]
+interface IWICFormatConverterInfo : IWICComponentInfo
+{
+    HRESULT GetPixelFormats(
+        [in] UINT cFormats,
+        [in, out, size_is(cFormats)] WICPixelFormatGUID *pPixelFormatGUIDs,
+        [out] UINT *pcActual);
+
+    HRESULT CreateInstance(
+        [out] IWICFormatConverter **ppIConverter);
+}
+
+[
+    object,
+    uuid(135ff860-22b7-4ddf-b0f6-218f4f299a43)
+]
+interface IWICStream : IStream
+{
+    HRESULT InitializeFromIStream(
+        [in] IStream *pIStream);
+
+    HRESULT InitializeFromFilename(
+        [in] LPCWSTR wzFileName,
+        [in] DWORD dwAccessMode);
+
+    HRESULT InitializeFromMemory(
+        [in, size_is(cbBufferSize)] BYTE *pbBuffer,
+        [in] DWORD cbBufferSize);
+
+    HRESULT InitializeFromIStreamRegion(
+        [in] IStream *pIStream,
+        [in] ULARGE_INTEGER ulOffset,
+        [in] ULARGE_INTEGER ulMaxSize);
+}
+
+cpp_quote("DEFINE_GUID(CLSID_WICImagingFactory, 0xcacaf262,0x9370,0x4615,0xa1,0x3b,0x9f,0x55,0x39,0xda,0x4c,0x0a);")
+
+[
+    object,
+    uuid(ec5ec8a9-c395-4314-9c77-54d7a935ff70)
+]
+interface IWICImagingFactory : IUnknown
+{
+    HRESULT CreateDecoderFromFilename(
+        [in] LPCWSTR wzFilename,
+        [in, unique] const GUID *pguidVendor,
+        [in] DWORD dwDesiredAccess,
+        [in] WICDecodeOptions metadataOptions,
+        [out, retval] IWICBitmapDecoder **ppIDecoder);
+
+    HRESULT CreateDecoderFromStream(
+        [in] IStream *pIStream,
+        [in, unique] const GUID *pguidVendor,
+        [in] WICDecodeOptions metadataOptions,
+        [out, retval] IWICBitmapDecoder **ppIDecoder);
+
+    HRESULT CreateDecoderFromFileHandle(
+        [in] ULONG_PTR hFile,
+        [in, unique] const GUID *pguidVendor,
+        [in] WICDecodeOptions metadataOptions,
+        [out, retval] IWICBitmapDecoder **ppIDecoder);
+
+    HRESULT CreateComponentInfo(
+        [in] REFCLSID clsidComponent,
+        [out] IWICComponentInfo **ppIInfo);
+
+    HRESULT CreateDecoder(
+        [in] REFGUID guidContainerFormat,
+        [in, unique] const GUID *pguidVendor,
+        [out, retval] IWICBitmapDecoder **ppIDecoder);
+
+    HRESULT CreateEncoder(
+        [in] REFGUID guidContainerFormat,
+        [in, unique] const GUID *pguidVendor,
+        [out, retval] IWICBitmapEncoder **ppIEncoder);
+
+    HRESULT CreatePalette(
+        [out] IWICPalette **ppIPalette);
+
+    HRESULT CreateFormatConverter(
+        [out] IWICFormatConverter **ppIFormatConverter);
+
+    HRESULT CreateBitmapScaler(
+        [out] IWICBitmapScaler **ppIBitmapScaler);
+
+    HRESULT CreateBitmapClipper(
+        [out] IWICBitmapClipper **ppIBitmapClipper);
+
+    HRESULT CreateBitmapFlipRotator(
+        [out] IWICBitmapFlipRotator **ppIBitmapFlipRotator);
+
+    HRESULT CreateStream(
+        [out] IWICStream **ppIWICStream);
+
+    HRESULT CreateColorContext(
+        [out] IWICColorContext **ppIWICColorContext);
+
+    HRESULT CreateColorTransformer(
+        [out] IWICColorTransform **ppIWICColorTransform);
+
+    HRESULT CreateBitmap(
+        [in] UINT uiWidth,
+        [in] UINT uiHeight,
+        [in] REFWICPixelFormatGUID pixelFormat,
+        [in] WICBitmapCreateCacheOption option,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateBitmapFromSource(
+        [in] IWICBitmapSource *piBitmapSource,
+        [in] WICBitmapCreateCacheOption option,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateBitmapFromSourceRect(
+        [in] IWICBitmapSource *piBitmapSource,
+        [in] UINT x,
+        [in] UINT y,
+        [in] UINT width,
+        [in] UINT height,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateBitmapFromMemory(
+        [in] UINT uiWidth,
+        [in] UINT uiHeight,
+        [in] REFWICPixelFormatGUID pixelFormat,
+        [in] UINT cbStride,
+        [in] UINT cbBufferSize,
+        [in, size_is(cbBufferSize)] BYTE *pbBuffer,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateBitmapFromHBITMAP(
+        [in] HBITMAP hBitmap,
+        [in, unique] HPALETTE hPalette,
+        [in] WICBitmapAlphaChannelOption options,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateBitmapFromHICON(
+        [in] HICON hIcon,
+        [out] IWICBitmap **ppIBitmap);
+
+    HRESULT CreateComponentEnumerator(
+        [in] DWORD componentTypes,
+        [in] DWORD options,
+        [out] IEnumUnknown **ppIEnumUnknown);
+
+    HRESULT CreateFastMetadataEncoderFromDecoder(
+        [in] IWICBitmapDecoder *pIDecoder,
+        [out] IWICFastMetadataEncoder **ppIFastEncoder);
+
+    HRESULT CreateFastMetadataEncoderFromFrameDecode(
+        [in] IWICBitmapFrameDecode *pIFrameDecoder,
+        [out] IWICFastMetadataEncoder **ppIFastEncoder);
+
+    HRESULT CreateQueryWriter(
+        [in] REFGUID guidMetadataFormat,
+        [in, unique] const GUID *pguidVendor,
+        [out] IWICMetadataQueryWriter **ppIQueryWriter);
+
+    HRESULT CreateQueryWriterFromReader(
+        [in] IWICMetadataQueryReader *pIQueryReader,
+        [in, unique] const GUID *pguidVendor,
+        [out] IWICMetadataQueryWriter **ppIQueryWriter);
+}
+
+cpp_quote("HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst);")
+
+cpp_quote("DEFINE_GUID(CLSID_WICBmpDecoder, 0x6b462062,0x7cbf,0x400d,0x9f,0xdb,0x81,0x3d,0xd1,0x0f,0x27,0x78);")
+cpp_quote("DEFINE_GUID(CLSID_WICPngDecoder, 0x389ea17b,0x5078,0x4cde,0xb6,0xef,0x25,0xc1,0x51,0x75,0xc7,0x51);")
+cpp_quote("DEFINE_GUID(CLSID_WICIcoDecoder, 0xc61bfcdf,0x2e0f,0x4aad,0xa8,0xd7,0xe0,0x6b,0xaf,0xeb,0xcd,0xfe);")
+cpp_quote("DEFINE_GUID(CLSID_WICJpegDecoder, 0x9456a480,0xe88b,0x43ea,0x9e,0x73,0x0b,0x2d,0x9b,0x71,0xb1,0xca);")
+cpp_quote("DEFINE_GUID(CLSID_WICGifDecoder, 0x381dda3c,0x9ce9,0x4834,0xa2,0x3e,0x1f,0x98,0xf8,0xfc,0x52,0xbe);")
+cpp_quote("DEFINE_GUID(CLSID_WICTiffDecoder, 0xb54e85d9,0xfe23,0x499f,0x8b,0x88,0x6a,0xce,0xa7,0x13,0x75,0x2b);")
+cpp_quote("DEFINE_GUID(CLSID_WICWmpDecoder, 0xa26cec36,0x234c,0x4950,0xae,0x16,0xe3,0x4a,0xac,0xe7,0x1d,0x0d);")
+
+cpp_quote("DEFINE_GUID(CLSID_WICBmpEncoder, 0x69be8bb4,0xd66d,0x47c8,0x86,0x5a,0xed,0x15,0x89,0x43,0x37,0x82);")
+cpp_quote("DEFINE_GUID(CLSID_WICPngEncoder, 0x27949969,0x876a,0x41d7,0x94,0x47,0x56,0x8f,0x6a,0x35,0xa4,0xdc);")
+cpp_quote("DEFINE_GUID(CLSID_WICJpegEncoder, 0x1a34f5c1,0x4a5a,0x46dc,0xb6,0x44,0x1f,0x45,0x67,0xe7,0xa6,0x76);")
+cpp_quote("DEFINE_GUID(CLSID_WICGifEncoder, 0x114f5598,0x0b22,0x40a0,0x86,0xa1,0xc8,0x3e,0xa4,0x95,0xad,0xbd);")
+cpp_quote("DEFINE_GUID(CLSID_WICTiffEncoder, 0x0131be10,0x2001,0x4c5f,0xa9,0xb0,0xcc,0x88,0xfa,0xb6,0x4c,0xe8);")
+cpp_quote("DEFINE_GUID(CLSID_WICWmpEncoder, 0xac4ce3cb,0xe1c1,0x44cd,0x82,0x15,0x5a,0x16,0x65,0x50,0x9e,0xc2);")
+
+cpp_quote("DEFINE_GUID(CLSID_WICDefaultFormatConverter, 0x1a3f11dc,0xb514,0x4b17,0x8c,0x5f,0x21,0x54,0x51,0x38,0x52,0xf1);")
+
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatBmp, 0x0af1d87e,0xfcfe,0x4188,0xbd,0xeb,0xa7,0x90,0x64,0x71,0xcb,0xe3);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatPng, 0x1b7cfaf4,0x713f,0x473c,0xbb,0xcd,0x61,0x37,0x42,0x5f,0xae,0xaf);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatIco, 0xa3a860c4,0x338f,0x4c17,0x91,0x9a,0xfb,0xa4,0xb5,0x62,0x8f,0x21);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatJpeg, 0x19e4a5aa,0x5662,0x4fc5,0xa0,0xc0,0x17,0x58,0x02,0x8e,0x10,0x57);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatTiff, 0x163bcc30,0xe2e9,0x4f0b,0x96,0x1d,0xa3,0xe9,0xfd,0xb7,0x88,0xa3);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatGif, 0x1f8a5601,0x7d4d,0x4cbd,0x9c,0x82,0x1b,0xc8,0xd4,0xee,0xb9,0xa5);")
+cpp_quote("DEFINE_GUID(GUID_ContainerFormatWmp, 0x57a37caa,0x367a,0x4540,0x91,0x6b,0xf1,0x83,0xc5,0x09,0x3a,0x4b);")
+
+cpp_quote("DEFINE_GUID(GUID_VendorMicrosoft, 0xf0e749ca,0xedef,0x4589,0xa7,0x3a,0xee,0x0e,0x62,0x6a,0x2a,0x2b);")
+
+cpp_quote("DEFINE_GUID(CATID_WICBitmapDecoders, 0x7ed96837,0x96f0,0x4812,0xb2,0x11,0xf1,0x3c,0x24,0x11,0x7e,0xd3);")
+cpp_quote("DEFINE_GUID(CATID_WICBitmapEncoders, 0xac757296,0x3522,0x4e11,0x98,0x62,0xc1,0x7b,0xe5,0xa1,0x76,0x7e);")
+cpp_quote("DEFINE_GUID(CATID_WICFormatConverters, 0x7835eae8,0xbf14,0x49d1,0x93,0xce,0x53,0x3a,0x40,0x7b,0x22,0x48);")
index 0f241d7..bd4ea29 100644 (file)
@@ -163,6 +163,7 @@ reactos/dll/win32/urlmon          # Autosync
 reactos/dll/win32/usp10           # Autosync
 reactos/dll/win32/uxtheme         # Autosync
 reactos/dll/win32/version         # Autosync
+reactos/dll/win32/windowscodecs   # Autosync
 reactos/dll/win32/winemp3.acm     # Autosync
 reactos/dll/win32/wininet         # Autosync
 reactos/dll/win32/winhttp         # Autosync