[PATCH 5/8] windowscodecs: Use the unix library to find PNG metadata.

Esme Povirk esme at codeweavers.com
Fri Oct 9 14:56:20 CDT 2020


Signed-off-by: Esme Povirk <esme at codeweavers.com>
---
 dlls/windowscodecs/libpng.c            |  77 +++++++++++++
 dlls/windowscodecs/main.c              |   1 +
 dlls/windowscodecs/pngformat.c         | 143 ++++---------------------
 dlls/windowscodecs/unix_iface.c        |   8 ++
 dlls/windowscodecs/unix_lib.c          |   1 +
 dlls/windowscodecs/wincodecs_common.h  |  51 +++++++++
 dlls/windowscodecs/wincodecs_private.h |  15 +++
 7 files changed, 174 insertions(+), 122 deletions(-)

diff --git a/dlls/windowscodecs/libpng.c b/dlls/windowscodecs/libpng.c
index 397d2d371ef..8a4db91f2a9 100644
--- a/dlls/windowscodecs/libpng.c
+++ b/dlls/windowscodecs/libpng.c
@@ -133,6 +133,7 @@ static void *load_libpng(void)
 struct png_decoder
 {
     struct decoder decoder;
+    IStream *stream;
     struct decoder_frame decoder_frame;
     UINT stride;
     BYTE *image_bits;
@@ -425,6 +426,8 @@ HRESULT CDECL png_decoder_initialize(struct decoder *iface, IStream *stream, str
                 WICBitmapDecoderCapabilityCanEnumerateMetadata;
     st->frame_count = 1;
 
+    This->stream = stream;
+
     hr = S_OK;
 
 end:
@@ -455,6 +458,79 @@ HRESULT CDECL png_decoder_copy_pixels(struct decoder *iface, UINT frame,
         prc, stride, buffersize, buffer);
 }
 
+HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface,
+    UINT frame, UINT *count, struct decoder_block **blocks)
+{
+    struct png_decoder *This = impl_from_decoder(iface);
+    HRESULT hr;
+    struct decoder_block *result = NULL;
+    ULONGLONG seek;
+    BYTE chunk_type[4];
+    ULONG chunk_size;
+    ULONGLONG chunk_start;
+    ULONG metadata_blocks_size = 0;
+
+    seek = 8;
+    *count = 0;
+
+    do
+    {
+        hr = stream_seek(This->stream, seek, STREAM_SEEK_SET, &chunk_start);
+        if (FAILED(hr)) goto end;
+
+        hr = read_png_chunk(This->stream, chunk_type, NULL, &chunk_size);
+        if (FAILED(hr)) goto end;
+
+        if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
+            memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
+        {
+            /* This chunk is considered metadata. */
+            if (*count == metadata_blocks_size)
+            {
+                struct decoder_block *new_metadata_blocks;
+                ULONG new_metadata_blocks_size;
+
+                new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
+                new_metadata_blocks = RtlAllocateHeap(GetProcessHeap(), 0,
+                    new_metadata_blocks_size * sizeof(*new_metadata_blocks));
+
+                if (!new_metadata_blocks)
+                {
+                    hr = E_OUTOFMEMORY;
+                    goto end;
+                }
+
+                memcpy(new_metadata_blocks, result,
+                    *count * sizeof(*new_metadata_blocks));
+
+                RtlFreeHeap(GetProcessHeap(), 0, result);
+                result = new_metadata_blocks;
+                metadata_blocks_size = new_metadata_blocks_size;
+            }
+
+            result[*count].offset = chunk_start;
+            result[*count].length = chunk_size + 12;
+            result[*count].options = WICMetadataCreationAllowUnknown;
+            (*count)++;
+        }
+
+        seek = chunk_start + chunk_size + 12; /* skip data and CRC */
+    } while (memcmp(chunk_type, "IEND", 4));
+
+end:
+    if (SUCCEEDED(hr))
+    {
+        *blocks = result;
+    }
+    else
+    {
+        *count = 0;
+        *blocks = NULL;
+        RtlFreeHeap(GetProcessHeap(), 0, result);
+    }
+    return hr;
+}
+
 void CDECL png_decoder_destroy(struct decoder* iface)
 {
     struct png_decoder *This = impl_from_decoder(iface);
@@ -467,6 +543,7 @@ static const struct decoder_funcs png_decoder_vtable = {
     png_decoder_initialize,
     png_decoder_get_frame_info,
     png_decoder_copy_pixels,
+    png_decoder_get_metadata_blocks,
     png_decoder_destroy
 };
 
diff --git a/dlls/windowscodecs/main.c b/dlls/windowscodecs/main.c
index 982c8ddfada..4dcc146d6c8 100644
--- a/dlls/windowscodecs/main.c
+++ b/dlls/windowscodecs/main.c
@@ -24,6 +24,7 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "winternl.h"
 #include "objbase.h"
 
 #include "wincodecs_private.h"
diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c
index 834cc81d306..1d696a4fe01 100644
--- a/dlls/windowscodecs/pngformat.c
+++ b/dlls/windowscodecs/pngformat.c
@@ -44,47 +44,6 @@ static inline ULONG read_ulong_be(BYTE* data)
     return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 }
 
-static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size)
-{
-    BYTE header[8];
-    HRESULT hr;
-    ULONG bytesread;
-
-    hr = IStream_Read(stream, header, 8, &bytesread);
-    if (FAILED(hr) || bytesread < 8)
-    {
-        if (SUCCEEDED(hr))
-            hr = E_FAIL;
-        return hr;
-    }
-
-    *data_size = read_ulong_be(&header[0]);
-
-    memcpy(type, &header[4], 4);
-
-    if (data)
-    {
-        *data = HeapAlloc(GetProcessHeap(), 0, *data_size);
-        if (!*data)
-            return E_OUTOFMEMORY;
-
-        hr = IStream_Read(stream, *data, *data_size, &bytesread);
-
-        if (FAILED(hr) || bytesread < *data_size)
-        {
-            if (SUCCEEDED(hr))
-                hr = E_FAIL;
-            HeapFree(GetProcessHeap(), 0, *data);
-            *data = NULL;
-            return hr;
-        }
-
-        /* Windows ignores CRC of the chunk */
-    }
-
-    return S_OK;
-}
-
 static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor,
     DWORD persist_options, MetadataItem **items, DWORD *item_count)
 {
@@ -459,7 +418,7 @@ typedef struct {
     BYTE *image_bits;
     CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */
     ULONG metadata_count;
-    metadata_block_info* metadata_blocks;
+    struct decoder_block* metadata_blocks;
 } PngDecoder;
 
 static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
@@ -515,7 +474,6 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
 {
     PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
-    ULONG i;
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
@@ -530,11 +488,6 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
         This->lock.DebugInfo->Spare[0] = 0;
         DeleteCriticalSection(&This->lock);
         HeapFree(GetProcessHeap(), 0, This->image_bits);
-        for (i=0; i<This->metadata_count; i++)
-        {
-            if (This->metadata_blocks[i].reader)
-                IWICMetadataReader_Release(This->metadata_blocks[i].reader);
-        }
         HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -587,10 +540,6 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p
     png_uint_32 transparency;
     png_color_16p trans_values;
     jmp_buf jmpbuf;
-    BYTE chunk_type[4];
-    ULONG chunk_size;
-    ULARGE_INTEGER chunk_start;
-    ULONG metadata_blocks_size = 0;
 
     TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
 
@@ -783,52 +732,7 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p
 
     ppng_read_end(This->png_ptr, This->end_info);
 
-    /* Find the metadata chunks in the file. */
-    seek.QuadPart = 8;
-
-    do
-    {
-        hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start);
-        if (FAILED(hr)) goto end;
-
-        hr = read_png_chunk(pIStream, chunk_type, NULL, &chunk_size);
-        if (FAILED(hr)) goto end;
-
-        if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' &&
-            memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4))
-        {
-            /* This chunk is considered metadata. */
-            if (This->metadata_count == metadata_blocks_size)
-            {
-                metadata_block_info* new_metadata_blocks;
-                ULONG new_metadata_blocks_size;
-
-                new_metadata_blocks_size = 4 + metadata_blocks_size * 2;
-                new_metadata_blocks = HeapAlloc(GetProcessHeap(), 0,
-                    new_metadata_blocks_size * sizeof(*new_metadata_blocks));
-
-                if (!new_metadata_blocks)
-                {
-                    hr = E_OUTOFMEMORY;
-                    goto end;
-                }
-
-                memcpy(new_metadata_blocks, This->metadata_blocks,
-                    This->metadata_count * sizeof(*new_metadata_blocks));
-
-                HeapFree(GetProcessHeap(), 0, This->metadata_blocks);
-                This->metadata_blocks = new_metadata_blocks;
-                metadata_blocks_size = new_metadata_blocks_size;
-            }
-
-            This->metadata_blocks[This->metadata_count].ofs = chunk_start;
-            This->metadata_blocks[This->metadata_count].len.QuadPart = chunk_size + 12;
-            This->metadata_blocks[This->metadata_count].reader = NULL;
-            This->metadata_count++;
-        }
-
-        seek.QuadPart = chunk_start.QuadPart + chunk_size + 12; /* skip data and CRC */
-    } while (memcmp(chunk_type, "IEND", 4));
+    decoder_get_metadata_blocks(This->png_decoder, 0, &This->metadata_count, &This->metadata_blocks);
 
     This->stream = pIStream;
     IStream_AddRef(This->stream);
@@ -1185,39 +1089,34 @@ static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
     if (nIndex >= This->metadata_count || !ppIMetadataReader)
         return E_INVALIDARG;
 
-    if (!This->metadata_blocks[nIndex].reader)
-    {
-        hr = StreamImpl_Create(&stream);
+    hr = StreamImpl_Create(&stream);
 
-        if (SUCCEEDED(hr))
-        {
-            hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream,
-                This->metadata_blocks[nIndex].ofs, This->metadata_blocks[nIndex].len);
+    if (SUCCEEDED(hr))
+    {
+        ULARGE_INTEGER offset, length;
 
-            if (SUCCEEDED(hr))
-                hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
+        offset.QuadPart = This->metadata_blocks[nIndex].offset;
+        length.QuadPart = This->metadata_blocks[nIndex].length;
+        hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream,
+            offset, length);
 
-            if (SUCCEEDED(hr))
-            {
-                hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
-                    &GUID_ContainerFormatPng, NULL, WICMetadataCreationAllowUnknown,
-                    (IStream*)stream, &This->metadata_blocks[nIndex].reader);
+        if (SUCCEEDED(hr))
+            hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory);
 
-                IWICComponentFactory_Release(factory);
-            }
+        if (SUCCEEDED(hr))
+        {
+            hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
+                &GUID_ContainerFormatPng, NULL, This->metadata_blocks[nIndex].options,
+                (IStream*)stream, ppIMetadataReader);
 
-            IWICStream_Release(stream);
+            IWICComponentFactory_Release(factory);
         }
 
-        if (FAILED(hr))
-        {
-            *ppIMetadataReader = NULL;
-            return hr;
-        }
+        IWICStream_Release(stream);
     }
 
-    *ppIMetadataReader = This->metadata_blocks[nIndex].reader;
-    IWICMetadataReader_AddRef(*ppIMetadataReader);
+    if (FAILED(hr))
+        *ppIMetadataReader = NULL;
 
     return S_OK;
 }
diff --git a/dlls/windowscodecs/unix_iface.c b/dlls/windowscodecs/unix_iface.c
index 46bcacff941..8d22b49ba22 100644
--- a/dlls/windowscodecs/unix_iface.c
+++ b/dlls/windowscodecs/unix_iface.c
@@ -85,6 +85,13 @@ HRESULT CDECL decoder_wrapper_copy_pixels(struct decoder* iface, UINT frame,
     return unix_funcs->decoder_copy_pixels(This->unix_decoder, frame, prc, stride, buffersize, buffer);
 }
 
+HRESULT CDECL decoder_wrapper_get_metadata_blocks(struct decoder* iface,
+    UINT frame, UINT *count, struct decoder_block **blocks)
+{
+    struct decoder_wrapper* This = impl_from_decoder(iface);
+    return unix_funcs->decoder_get_metadata_blocks(This->unix_decoder, frame, count, blocks);
+}
+
 void CDECL decoder_wrapper_destroy(struct decoder* iface)
 {
     struct decoder_wrapper* This = impl_from_decoder(iface);
@@ -96,6 +103,7 @@ static const struct decoder_funcs decoder_wrapper_vtable = {
     decoder_wrapper_initialize,
     decoder_wrapper_get_frame_info,
     decoder_wrapper_copy_pixels,
+    decoder_wrapper_get_metadata_blocks,
     decoder_wrapper_destroy
 };
 
diff --git a/dlls/windowscodecs/unix_lib.c b/dlls/windowscodecs/unix_lib.c
index 5ab1cb342e6..58c68018430 100644
--- a/dlls/windowscodecs/unix_lib.c
+++ b/dlls/windowscodecs/unix_lib.c
@@ -70,6 +70,7 @@ static const struct unix_funcs unix_funcs = {
     decoder_initialize,
     decoder_get_frame_info,
     decoder_copy_pixels,
+    decoder_get_metadata_blocks,
     decoder_destroy
 };
 
diff --git a/dlls/windowscodecs/wincodecs_common.h b/dlls/windowscodecs/wincodecs_common.h
index f116fb6fd8f..5489a055a27 100644
--- a/dlls/windowscodecs/wincodecs_common.h
+++ b/dlls/windowscodecs/wincodecs_common.h
@@ -32,6 +32,11 @@ HRESULT CDECL decoder_copy_pixels(struct decoder *decoder, UINT frame,
     return decoder->vtable->copy_pixels(decoder, frame, prc, stride, buffersize, buffer);
 }
 
+HRESULT CDECL decoder_get_metadata_blocks(struct decoder *decoder, UINT frame, UINT *count, struct decoder_block **blocks)
+{
+    return decoder->vtable->get_metadata_blocks(decoder, frame, count, blocks);
+}
+
 void CDECL decoder_destroy(struct decoder *decoder)
 {
     decoder->vtable->destroy(decoder);
@@ -102,3 +107,49 @@ HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
     }
 }
 
+static inline ULONG read_ulong_be(BYTE* data)
+{
+    return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
+}
+
+HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size)
+{
+    BYTE header[8];
+    HRESULT hr;
+    ULONG bytesread;
+
+    hr = stream_read(stream, header, 8, &bytesread);
+    if (FAILED(hr) || bytesread < 8)
+    {
+        if (SUCCEEDED(hr))
+            hr = E_FAIL;
+        return hr;
+    }
+
+    *data_size = read_ulong_be(&header[0]);
+
+    memcpy(type, &header[4], 4);
+
+    if (data)
+    {
+        *data = RtlAllocateHeap(GetProcessHeap(), 0, *data_size);
+        if (!*data)
+            return E_OUTOFMEMORY;
+
+        hr = stream_read(stream, *data, *data_size, &bytesread);
+
+        if (FAILED(hr) || bytesread < *data_size)
+        {
+            if (SUCCEEDED(hr))
+                hr = E_FAIL;
+            RtlFreeHeap(GetProcessHeap(), 0, *data);
+            *data = NULL;
+            return hr;
+        }
+
+        /* Windows ignores CRC of the chunk */
+    }
+
+    return S_OK;
+}
+
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h
index 24cae3652f4..3c0b73e893f 100644
--- a/dlls/windowscodecs/wincodecs_private.h
+++ b/dlls/windowscodecs/wincodecs_private.h
@@ -249,6 +249,8 @@ static inline const char *debug_wic_rect(const WICRect *rect)
 
 HMODULE windowscodecs_module;
 
+HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size);
+
 /* unixlib iface */
 struct decoder_funcs;
 
@@ -277,6 +279,13 @@ struct decoder_frame
     WICColor palette[256];
 };
 
+struct decoder_block
+{
+    ULONGLONG offset;
+    ULONGLONG length;
+    DWORD options;
+};
+
 struct decoder
 {
     const struct decoder_funcs *vtable;
@@ -288,6 +297,8 @@ struct decoder_funcs
     HRESULT (CDECL *get_frame_info)(struct decoder* This, UINT frame, struct decoder_frame *info);
     HRESULT (CDECL *copy_pixels)(struct decoder* This, UINT frame, const WICRect *prc,
         UINT stride, UINT buffersize, BYTE *buffer);
+    HRESULT (CDECL *get_metadata_blocks)(struct decoder* This, UINT frame, UINT *count,
+        struct decoder_block **blocks);
     void (CDECL *destroy)(struct decoder* This);
 };
 
@@ -305,6 +316,8 @@ HRESULT CDECL decoder_initialize(struct decoder *This, IStream *stream, struct d
 HRESULT CDECL decoder_get_frame_info(struct decoder* This, UINT frame, struct decoder_frame *info);
 HRESULT CDECL decoder_copy_pixels(struct decoder* This, UINT frame, const WICRect *prc,
     UINT stride, UINT buffersize, BYTE *buffer);
+HRESULT CDECL decoder_get_metadata_blocks(struct decoder* This, UINT frame, UINT *count,
+    struct decoder_block **blocks);
 void CDECL decoder_destroy(struct decoder *This);
 
 HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result);
@@ -316,6 +329,8 @@ struct unix_funcs
     HRESULT (CDECL *decoder_get_frame_info)(struct decoder* This, UINT frame, struct decoder_frame *info);
     HRESULT (CDECL *decoder_copy_pixels)(struct decoder* This, UINT frame, const WICRect *prc,
         UINT stride, UINT buffersize, BYTE *buffer);
+    HRESULT (CDECL *decoder_get_metadata_blocks)(struct decoder* This, UINT frame, UINT *count,
+        struct decoder_block **blocks);
     void (CDECL *decoder_destroy)(struct decoder* This);
 };
 
-- 
2.17.1




More information about the wine-devel mailing list