windowscodecs: Start loading PNG in unix lib.

Signed-off-by: Esme Povirk <esme@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Esme Povirk 2020-10-09 14:56:17 -05:00 committed by Alexandre Julliard
parent 0f61ed18ef
commit 6aa8e17975
7 changed files with 247 additions and 6 deletions

View File

@ -42,6 +42,67 @@ WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
#ifdef SONAME_LIBPNG
#include <png.h>
static void *libpng_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(png_create_info_struct);
MAKE_FUNCPTR(png_create_read_struct);
MAKE_FUNCPTR(png_destroy_read_struct);
MAKE_FUNCPTR(png_error);
MAKE_FUNCPTR(png_get_error_ptr);
MAKE_FUNCPTR(png_get_io_ptr);
MAKE_FUNCPTR(png_read_info);
MAKE_FUNCPTR(png_set_crc_action);
MAKE_FUNCPTR(png_set_error_fn);
MAKE_FUNCPTR(png_set_read_fn);
#undef MAKE_FUNCPTR
static CRITICAL_SECTION init_png_cs;
static CRITICAL_SECTION_DEBUG init_png_cs_debug =
{
0, 0, &init_png_cs,
{ &init_png_cs_debug.ProcessLocksList,
&init_png_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": init_png_cs") }
};
static CRITICAL_SECTION init_png_cs = { &init_png_cs_debug, -1, 0, 0, 0, 0 };
static void *load_libpng(void)
{
void *result;
RtlEnterCriticalSection(&init_png_cs);
if(!libpng_handle && (libpng_handle = dlopen(SONAME_LIBPNG, RTLD_NOW)) != NULL) {
#define LOAD_FUNCPTR(f) \
if((p##f = dlsym(libpng_handle, #f)) == NULL) { \
libpng_handle = NULL; \
RtlLeaveCriticalSection(&init_png_cs); \
return NULL; \
}
LOAD_FUNCPTR(png_create_info_struct);
LOAD_FUNCPTR(png_create_read_struct);
LOAD_FUNCPTR(png_destroy_read_struct);
LOAD_FUNCPTR(png_error);
LOAD_FUNCPTR(png_get_error_ptr);
LOAD_FUNCPTR(png_get_io_ptr);
LOAD_FUNCPTR(png_read_info);
LOAD_FUNCPTR(png_set_crc_action);
LOAD_FUNCPTR(png_set_error_fn);
LOAD_FUNCPTR(png_set_read_fn);
#undef LOAD_FUNCPTR
}
result = libpng_handle;
RtlLeaveCriticalSection(&init_png_cs);
return result;
}
struct png_decoder
{
struct decoder decoder;
@ -52,6 +113,97 @@ static inline struct png_decoder *impl_from_decoder(struct decoder* iface)
return CONTAINING_RECORD(iface, struct png_decoder, decoder);
}
static void user_error_fn(png_structp png_ptr, png_const_charp error_message)
{
jmp_buf *pjmpbuf;
/* This uses setjmp/longjmp just like the default. We can't use the
* default because there's no way to access the jmp buffer in the png_struct
* that works in 1.2 and 1.4 and allows us to dynamically load libpng. */
WARN("PNG error: %s\n", debugstr_a(error_message));
pjmpbuf = ppng_get_error_ptr(png_ptr);
longjmp(*pjmpbuf, 1);
}
static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message)
{
WARN("PNG warning: %s\n", debugstr_a(warning_message));
}
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
{
IStream *stream = ppng_get_io_ptr(png_ptr);
HRESULT hr;
ULONG bytesread;
hr = stream_read(stream, data, length, &bytesread);
if (FAILED(hr) || bytesread != length)
{
ppng_error(png_ptr, "failed reading data");
}
}
HRESULT CDECL png_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st)
{
png_structp png_ptr;
png_infop info_ptr;
png_infop end_info;
jmp_buf jmpbuf;
HRESULT hr = E_FAIL;
png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
{
return E_FAIL;
}
info_ptr = ppng_create_info_struct(png_ptr);
if (!info_ptr)
{
ppng_destroy_read_struct(&png_ptr, NULL, NULL);
return E_FAIL;
}
end_info = ppng_create_info_struct(png_ptr);
if (!end_info)
{
ppng_destroy_read_struct(&png_ptr, &info_ptr, NULL);
return E_FAIL;
}
/* set up setjmp/longjmp error handling */
if (setjmp(jmpbuf))
{
hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT;
goto end;
}
ppng_set_error_fn(png_ptr, jmpbuf, user_error_fn, user_warning_fn);
ppng_set_crc_action(png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE);
/* seek to the start of the stream */
hr = stream_seek(stream, 0, STREAM_SEEK_SET, NULL);
if (FAILED(hr))
{
goto end;
}
/* set up custom i/o handling */
ppng_set_read_fn(png_ptr, stream, user_read_data);
/* read the header */
ppng_read_info(png_ptr, info_ptr);
st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
WICBitmapDecoderCapabilityCanDecodeSomeImages |
WICBitmapDecoderCapabilityCanEnumerateMetadata;
st->frame_count = 1;
hr = S_OK;
end:
ppng_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
return hr;
}
void CDECL png_decoder_destroy(struct decoder* iface)
{
struct png_decoder *This = impl_from_decoder(iface);
@ -60,6 +212,7 @@ void CDECL png_decoder_destroy(struct decoder* iface)
}
static const struct decoder_funcs png_decoder_vtable = {
png_decoder_initialize,
png_decoder_destroy
};
@ -67,7 +220,11 @@ HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **res
{
struct png_decoder *This;
TRACE("\n");
if (!load_libpng())
{
ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG);
return E_FAIL;
}
This = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*This));

View File

@ -255,6 +255,25 @@ HRESULT write_source(IWICBitmapFrameEncode *iface,
return hr;
}
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read)
{
return IStream_Read(stream, buffer, read, bytes_read);
}
HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position)
{
HRESULT hr;
LARGE_INTEGER ofs_large;
ULARGE_INTEGER pos_large;
ofs_large.QuadPart = ofs;
hr = IStream_Seek(stream, ofs_large, origin, &pos_large);
if (new_position)
*new_position = pos_large.QuadPart;
return hr;
}
void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
{
UINT x, y;

View File

@ -446,6 +446,7 @@ typedef struct {
IStream *stream;
struct decoder *png_decoder;
struct decoder_info decoder_info;
struct decoder_stat file_info;
png_structp png_ptr;
png_infop info_ptr;
png_infop end_info;
@ -543,6 +544,7 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface)
static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
DWORD *capability)
{
PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
HRESULT hr;
TRACE("(%p,%p,%p)\n", iface, stream, capability);
@ -552,9 +554,7 @@ static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStre
hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
if (hr != S_OK) return hr;
*capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
WICBitmapDecoderCapabilityCanDecodeSomeImages;
/* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
*capability = (This->file_info.flags & DECODER_FLAGS_CAPABILITY_MASK);
return S_OK;
}
@ -595,6 +595,16 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p
EnterCriticalSection(&This->lock);
if (This->initialized)
{
hr = WINCODEC_ERR_WRONGSTATE;
goto end;
}
hr = decoder_initialize(This->png_decoder, pIStream, &This->file_info);
if (FAILED(hr))
goto end;
/* initialize libpng */
This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!This->png_ptr)
@ -896,9 +906,12 @@ static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface,
static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface,
UINT *pCount)
{
PngDecoder *This = impl_from_IWICBitmapDecoder(iface);
if (!pCount) return E_INVALIDARG;
*pCount = 1;
if (!This->initialized) return WINCODEC_ERR_WRONGSTATE;
*pCount = This->file_info.frame_count;
return S_OK;
}

View File

@ -39,9 +39,14 @@ static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
static const struct unix_funcs *unix_funcs;
static const struct win32_funcs win32_funcs = {
stream_read,
stream_seek
};
static BOOL WINAPI load_unixlib( INIT_ONCE *once, void *param, void **context )
{
__wine_init_unix_lib( windowscodecs_module, DLL_PROCESS_ATTACH, NULL, &unix_funcs );
__wine_init_unix_lib( windowscodecs_module, DLL_PROCESS_ATTACH, &win32_funcs, &unix_funcs );
return TRUE;
}
@ -61,6 +66,12 @@ static inline struct decoder_wrapper *impl_from_decoder(struct decoder* iface)
return CONTAINING_RECORD(iface, struct decoder_wrapper, win32_decoder);
}
HRESULT CDECL decoder_wrapper_initialize(struct decoder* iface, IStream* stream, struct decoder_stat *st)
{
struct decoder_wrapper* This = impl_from_decoder(iface);
return unix_funcs->decoder_initialize(This->unix_decoder, stream, st);
}
void CDECL decoder_wrapper_destroy(struct decoder* iface)
{
struct decoder_wrapper* This = impl_from_decoder(iface);
@ -69,6 +80,7 @@ void CDECL decoder_wrapper_destroy(struct decoder* iface)
}
static const struct decoder_funcs decoder_wrapper_vtable = {
decoder_wrapper_initialize,
decoder_wrapper_destroy
};

View File

@ -43,6 +43,18 @@
#include "wincodecs_common.h"
static const struct win32_funcs *win32_funcs;
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read)
{
return win32_funcs->stream_read(stream, buffer, read, bytes_read);
}
HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position)
{
return win32_funcs->stream_seek(stream, ofs, origin, new_position);
}
HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result)
{
if (IsEqualGUID(decoder_clsid, &CLSID_WICPngDecoder))
@ -53,6 +65,7 @@ HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *in
static const struct unix_funcs unix_funcs = {
decoder_create,
decoder_initialize,
decoder_destroy
};
@ -60,6 +73,8 @@ NTSTATUS CDECL __wine_init_unix_lib( HMODULE module, DWORD reason, const void *p
{
if (reason != DLL_PROCESS_ATTACH) return STATUS_SUCCESS;
win32_funcs = ptr_in;
*(const struct unix_funcs **)ptr_out = &unix_funcs;
return STATUS_SUCCESS;
}

View File

@ -16,6 +16,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
HRESULT CDECL decoder_initialize(struct decoder *decoder, IStream *stream, struct decoder_stat *st)
{
return decoder->vtable->initialize(decoder, stream, st);
}
void CDECL decoder_destroy(struct decoder *decoder)
{
decoder->vtable->destroy(decoder);

View File

@ -259,6 +259,14 @@ struct decoder_info
CLSID clsid;
};
#define DECODER_FLAGS_CAPABILITY_MASK 0x1f
struct decoder_stat
{
DWORD flags;
DWORD frame_count;
};
struct decoder
{
const struct decoder_funcs *vtable;
@ -266,10 +274,21 @@ struct decoder
struct decoder_funcs
{
HRESULT (CDECL *initialize)(struct decoder* This, IStream *stream, struct decoder_stat *st);
void (CDECL *destroy)(struct decoder* This);
};
HRESULT CDECL stream_read(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read);
HRESULT CDECL stream_seek(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position);
struct win32_funcs
{
HRESULT (CDECL *stream_read)(IStream *stream, void *buffer, ULONG read, ULONG *bytes_read);
HRESULT (CDECL *stream_seek)(IStream *stream, LONGLONG ofs, DWORD origin, ULONGLONG *new_position);
};
HRESULT CDECL decoder_create(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result);
HRESULT CDECL decoder_initialize(struct decoder *This, IStream *stream, struct decoder_stat *st);
void CDECL decoder_destroy(struct decoder *This);
HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **result);
@ -277,6 +296,7 @@ HRESULT CDECL png_decoder_create(struct decoder_info *info, struct decoder **res
struct unix_funcs
{
HRESULT (CDECL *decoder_create)(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result);
HRESULT (CDECL *decoder_initialize)(struct decoder *This, IStream *stream, struct decoder_stat *st);
void (CDECL *decoder_destroy)(struct decoder* This);
};