From 751e4a44db847913d76615f6ec583c2f4c18c905 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Fri, 11 Mar 2016 03:48:46 +0100
Subject: windowscodecs: Implement WICCreateBitmapFromSection(Ex). (v2)

---
 dlls/windowscodecs/bitmap.c           | 27 ++++++++-----
 dlls/windowscodecs/imgfactory.c       | 73 ++++++++++++++++++++++++++++++++++-
 dlls/windowscodecs/windowscodecs.spec |  3 +-
 include/wincodec.idl                  |  8 ++++
 4 files changed, 100 insertions(+), 11 deletions(-)

diff --git a/dlls/windowscodecs/bitmap.c b/dlls/windowscodecs/bitmap.c
index 85d0076..2fa19b4 100644
--- a/dlls/windowscodecs/bitmap.c
+++ b/dlls/windowscodecs/bitmap.c
@@ -46,6 +46,7 @@ typedef struct BitmapImpl {
     int palette_set;
     LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
     BYTE *data;
+    BOOL is_section; /* TRUE if data is a section created by an application */
     UINT width, height;
     UINT stride;
     UINT bpp;
@@ -285,7 +286,10 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface)
         if (This->palette) IWICPalette_Release(This->palette);
         This->cs.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&This->cs);
-        HeapFree(GetProcessHeap(), 0, This->data);
+        if (This->is_section)
+            UnmapViewOfFile(This->data);
+        else
+            HeapFree(GetProcessHeap(), 0, This->data);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -695,13 +699,12 @@ static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl =
 };
 
 HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
-    UINT stride, UINT datasize, BYTE *bits,
+    UINT stride, UINT datasize, BYTE *data,
     REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
     IWICBitmap **ppIBitmap)
 {
     HRESULT hr;
     BitmapImpl *This;
-    BYTE *data;
     UINT bpp;
 
     hr = get_pixelformat_bpp(pixelFormat, &bpp);
@@ -714,14 +717,20 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
     if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG;
 
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl));
-    data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize);
-    if (!This || !data)
+    if (!This) return E_OUTOFMEMORY;
+
+    if (!data)
     {
-        HeapFree(GetProcessHeap(), 0, This);
-        HeapFree(GetProcessHeap(), 0, data);
-        return E_OUTOFMEMORY;
+        data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize);
+        if (!data)
+        {
+            HeapFree(GetProcessHeap(), 0, This);
+            return E_OUTOFMEMORY;
+        }
+        This->is_section = FALSE;
     }
-    if (bits) memcpy(data, bits, datasize);
+    else
+        This->is_section = TRUE;
 
     This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl;
     This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl;
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c
index f2455fc..d6c4c64 100644
--- a/dlls/windowscodecs/imgfactory.c
+++ b/dlls/windowscodecs/imgfactory.c
@@ -597,12 +597,36 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFacto
     UINT width, UINT height, REFWICPixelFormatGUID format, UINT stride,
     UINT size, BYTE *buffer, IWICBitmap **bitmap)
 {
+    HRESULT hr;
+
     TRACE("(%p,%u,%u,%s,%u,%u,%p,%p\n", iface, width, height,
         debugstr_guid(format), stride, size, buffer, bitmap);
 
     if (!stride || !size || !buffer || !bitmap) return E_INVALIDARG;
 
-    return BitmapImpl_Create(width, height, stride, size, buffer, format, WICBitmapCacheOnLoad, bitmap);
+    hr = BitmapImpl_Create(width, height, stride, size, NULL, format, WICBitmapCacheOnLoad, bitmap);
+    if (SUCCEEDED(hr))
+    {
+        IWICBitmapLock *lock;
+
+        hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock);
+        if (SUCCEEDED(hr))
+        {
+            UINT buffersize;
+            BYTE *data;
+
+            IWICBitmapLock_GetDataPointer(lock, &buffersize, &data);
+            memcpy(data, buffer, buffersize);
+
+            IWICBitmapLock_Release(lock);
+        }
+        else
+        {
+            IWICBitmap_Release(*bitmap);
+            *bitmap = NULL;
+        }
+    }
+    return hr;
 }
 
 static BOOL get_16bpp_format(HBITMAP hbm, WICPixelFormatGUID *format)
@@ -1174,3 +1198,50 @@ HRESULT ComponentFactory_CreateInstance(REFIID iid, void** ppv)
 
     return ret;
 }
+
+HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height,
+        REFWICPixelFormatGUID format, HANDLE section, UINT stride,
+        UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap)
+{
+    DWORD access;
+    void *buffer;
+    HRESULT hr;
+
+    TRACE("%u,%u,%s,%p,%u,%#x,%#x,%p\n", width, height, debugstr_guid(format),
+        section, stride, offset, wicaccess, bitmap);
+
+    if (!width || !height || !section || !bitmap) return E_INVALIDARG;
+
+    switch (wicaccess)
+    {
+    case WICSectionAccessLevelReadWrite:
+        access = FILE_MAP_READ | FILE_MAP_WRITE;
+        break;
+
+    case WICSectionAccessLevelRead:
+        access = FILE_MAP_READ;
+        break;
+
+    default:
+        FIXME("unsupported access %#x\n", wicaccess);
+        return E_INVALIDARG;
+    }
+
+    buffer = MapViewOfFile(section, access, 0, offset, 0);
+    if (!buffer) return HRESULT_FROM_WIN32(GetLastError());
+
+    hr = BitmapImpl_Create(width, height, stride, 0, buffer, format, WICBitmapCacheOnLoad, bitmap);
+    if (FAILED(hr)) UnmapViewOfFile(buffer);
+    return hr;
+}
+
+HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height,
+        REFWICPixelFormatGUID format, HANDLE section,
+        UINT stride, UINT offset, IWICBitmap **bitmap)
+{
+    TRACE("%u,%u,%s,%p,%u,%u,%p\n", width, height, debugstr_guid(format),
+        section, stride, offset, bitmap);
+
+    return WICCreateBitmapFromSectionEx(width, height, format, section,
+        stride, offset, WICSectionAccessLevelRead, bitmap);
+}
diff --git a/dlls/windowscodecs/windowscodecs.spec b/dlls/windowscodecs/windowscodecs.spec
index 81a827e..7ee76d9 100644
--- a/dlls/windowscodecs/windowscodecs.spec
+++ b/dlls/windowscodecs/windowscodecs.spec
@@ -105,7 +105,8 @@
 @ stdcall IWICStream_InitializeFromIStream_Proxy(ptr ptr) IWICStream_InitializeFromIStream_Proxy_W
 @ stdcall IWICStream_InitializeFromMemory_Proxy(ptr ptr long) IWICStream_InitializeFromMemory_Proxy_W
 @ stdcall WICConvertBitmapSource(ptr ptr ptr)
-@ stub WICCreateBitmapFromSection
+@ stdcall WICCreateBitmapFromSection(long long ptr long long long ptr)
+@ stdcall WICCreateBitmapFromSectionEx(long long ptr long long long long ptr)
 @ stdcall WICCreateColorContext_Proxy(ptr ptr)
 @ stdcall WICCreateImagingFactory_Proxy(long ptr)
 @ stub WICGetMetadataContentSize
diff --git a/include/wincodec.idl b/include/wincodec.idl
index 639d925..00a8da8 100644
--- a/include/wincodec.idl
+++ b/include/wincodec.idl
@@ -168,6 +168,12 @@ typedef enum WICTiffCompressionOption {
     WICTIFFCOMPRESSIONOPTION_FORCE_DWORD = CODEC_FORCE_DWORD
 } WICTiffCompressionOption;
 
+typedef enum WICSectionAccessLevel {
+    WICSectionAccessLevelRead = 0x00000001,
+    WICSectionAccessLevelReadWrite = 0x00000003,
+    WICSectionAccessLevel_FORCE_DWORD = CODEC_FORCE_DWORD
+} WICSectionAccessLevel;
+
 typedef GUID WICPixelFormatGUID;
 typedef REFGUID REFWICPixelFormatGUID;
 
@@ -982,6 +988,8 @@ interface IWICEnumMetadataItem : IUnknown
 }
 
 cpp_quote("HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst);")
+cpp_quote("HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, IWICBitmap **bitmap);")
+cpp_quote("HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, WICSectionAccessLevel access, IWICBitmap **bitmap);")
 
 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);")
-- 
2.7.1

