Signed-off-by: Esme Povirk esme@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); };