[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