From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/ungif.c | 23 +++++++++++++++++++++-- dlls/windowscodecs/ungif.h | 1 + 2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/windowscodecs/ungif.c b/dlls/windowscodecs/ungif.c index 63aa02427c6..aa0552c04ce 100644 --- a/dlls/windowscodecs/ungif.c +++ b/dlls/windowscodecs/ungif.c @@ -77,6 +77,7 @@ typedef struct GifFilePrivateType { unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */ unsigned long PixelCount; /* Number of pixels in image. */ InputFunc Read; /* function to read gif input (TVT) */ + int Offset; /* accumulated file read offset */ GifByteType Buf[256]; /* Compressed input is buffered here. */ GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */ GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */ @@ -85,7 +86,21 @@ typedef struct GifFilePrivateType {
/* avoid extra function call in case we use fread (TVT) */ #define READ(_gif,_buf,_len) \ - ((GifFilePrivateType*)_gif->Private)->Read(_gif,_buf,_len) + _READ(_gif,_buf,_len) + +static int _READ(GifFileType *_gif, GifByteType *_buf, int _len) +{ + GifFilePrivateType *Private = (GifFilePrivateType *)_gif->Private; + int ret; + + Private->Offset += (ret = Private->Read(_gif, _buf, _len)); + return ret; +} + +static int GetFileOffset(GifFileType *GifFile) +{ + return ((GifFilePrivateType *)GifFile->Private)->Offset; +}
static int DGifGetWord(GifFileType *GifFile, GifWord *Word); static int DGifSetupDecompress(GifFileType *GifFile); @@ -367,11 +382,13 @@ DGifGetRecordType(GifFileType * GifFile, static int DGifGetImageDesc(GifFileType * GifFile) {
- int i, BitsPerPixel, SortFlag; + int i, BitsPerPixel, SortFlag, ImageDescOffset; GifByteType Buf[3]; GifFilePrivateType *Private = GifFile->Private; SavedImage *sp;
+ ImageDescOffset = GetFileOffset(GifFile); + if (DGifGetWord(GifFile, &GifFile->Image.Left) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Top) == GIF_ERROR || DGifGetWord(GifFile, &GifFile->Image.Width) == GIF_ERROR || @@ -417,6 +434,7 @@ DGifGetImageDesc(GifFileType * GifFile) {
sp = &GifFile->SavedImages[GifFile->ImageCount]; sp->ImageDesc = GifFile->Image; + sp->ImageDescOffset = ImageDescOffset; if (GifFile->Image.ColorMap != NULL) { sp->ImageDesc.ColorMap = MakeMapObject( GifFile->Image.ColorMap->ColorCount, @@ -984,6 +1002,7 @@ DGifOpen(void *userData, GifFile->Private = (void*)Private;
Private->Read = readFunc; /* TVT */ + Private->Offset = 0; GifFile->UserData = userData; /* TVT */
/* Lets see if this is a GIF file: */ diff --git a/dlls/windowscodecs/ungif.h b/dlls/windowscodecs/ungif.h index f61a7eb1e16..c402109bc67 100644 --- a/dlls/windowscodecs/ungif.h +++ b/dlls/windowscodecs/ungif.h @@ -170,6 +170,7 @@ int DGifCloseFile(GifFileType * GifFile); /* This holds an image header, its unpacked raster bits, and extensions */ typedef struct SavedImage { GifImageDesc ImageDesc; + int ImageDescOffset; unsigned char *RasterBits; Extensions Extensions; } SavedImage;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 7 +++++++ dlls/windowscodecs/wincodecs_private.h | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index ea8bb2d75bb..d956ed149ce 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -638,6 +638,13 @@ static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBloc if (SUCCEEDED(hr)) hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); } + else if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_OFFSET_IS_PTR) + { + BYTE *data = (BYTE *)(ULONG_PTR)This->metadata_blocks[nIndex].offset; + UINT size = This->metadata_blocks[nIndex].length; + + hr = IWICStream_InitializeFromMemory(stream, data, size); + } else { ULARGE_INTEGER offset, length; diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index c255df06f84..d9493b5607e 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -290,9 +290,14 @@ struct decoder_frame WICColor palette[256]; };
-#define DECODER_BLOCK_OPTION_MASK 0x0001000F -#define DECODER_BLOCK_FULL_STREAM 0x80000000 -#define DECODER_BLOCK_READER_CLSID 0x40000000 +enum decoder_block_options +{ + DECODER_BLOCK_OPTION_MASK = 0x0001000F, + DECODER_BLOCK_FULL_STREAM = 0x80000000, + DECODER_BLOCK_READER_CLSID = 0x40000000, + DECODER_BLOCK_OFFSET_IS_PTR = 0x20000000, +}; + struct decoder_block { ULONGLONG offset;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 304 ++++++++++++++++++++--------------- 1 file changed, 171 insertions(+), 133 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index d956ed149ce..3b594c71101 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -30,7 +30,18 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
-typedef struct { +typedef struct CommonDecoder CommonDecoder; + +struct metadata_block_reader +{ + BOOL metadata_initialized; + UINT metadata_count; + struct decoder_block *metadata_blocks; + UINT frame; + CommonDecoder *decoder; +}; + +typedef struct CommonDecoder { IWICBitmapDecoder IWICBitmapDecoder_iface; LONG ref; CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */ @@ -41,6 +52,158 @@ typedef struct { WICDecodeOptions cache_options; } CommonDecoder;
+static void metadata_block_reader_initialize(struct metadata_block_reader *block_reader, CommonDecoder *decoder, UINT frame) +{ + memset(block_reader, 0, sizeof(*block_reader)); + block_reader->decoder = decoder; + block_reader->frame = frame; +} + +static void metadata_block_reader_cleanup(struct metadata_block_reader *block_reader) +{ + free(block_reader->metadata_blocks); +} + +static HRESULT metadata_block_reader_initialize_metadata(struct metadata_block_reader *block_reader) +{ + HRESULT hr = S_OK; + + if (block_reader->metadata_initialized) + return S_OK; + + EnterCriticalSection(&block_reader->decoder->lock); + + if (!block_reader->metadata_initialized) + { + hr = decoder_get_metadata_blocks(block_reader->decoder->decoder, block_reader->frame, + &block_reader->metadata_count, &block_reader->metadata_blocks); + if (SUCCEEDED(hr)) + block_reader->metadata_initialized = TRUE; + } + + LeaveCriticalSection(&block_reader->decoder->lock); + + return hr; +} + +static HRESULT metadata_block_reader_get_container_format(struct metadata_block_reader *block_reader, GUID *format) +{ + if (!format) return E_INVALIDARG; + *format = block_reader->decoder->decoder_info.block_format; + return S_OK; +} + +static HRESULT metadata_block_reader_get_count(struct metadata_block_reader *block_reader, UINT *count) +{ + HRESULT hr; + + if (!count) return E_INVALIDARG; + + hr = metadata_block_reader_initialize_metadata(block_reader); + if (SUCCEEDED(hr)) + *count = block_reader->metadata_count; + + return hr; +} + +static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *block_reader, + UINT index, IWICMetadataReader **ret_reader) +{ + IWICComponentFactory *factory = NULL; + IWICStream *stream; + HRESULT hr; + + if (!ret_reader) + return E_INVALIDARG; + + hr = metadata_block_reader_initialize_metadata(block_reader); + + if (SUCCEEDED(hr) && index >= block_reader->metadata_count) + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) + hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory); + + if (SUCCEEDED(hr)) + hr = IWICComponentFactory_CreateStream(factory, &stream); + + if (SUCCEEDED(hr)) + { + if (block_reader->metadata_blocks[index].options & DECODER_BLOCK_FULL_STREAM) + { + LARGE_INTEGER offset; + offset.QuadPart = block_reader->metadata_blocks[index].offset; + + hr = IWICStream_InitializeFromIStream(stream, block_reader->decoder->stream); + + if (SUCCEEDED(hr)) + hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); + } + else if (block_reader->metadata_blocks[index].options & DECODER_BLOCK_OFFSET_IS_PTR) + { + BYTE *data = (BYTE *)(ULONG_PTR)block_reader->metadata_blocks[index].offset; + UINT size = block_reader->metadata_blocks[index].length; + + hr = IWICStream_InitializeFromMemory(stream, data, size); + } + else + { + ULARGE_INTEGER offset, length; + + offset.QuadPart = block_reader->metadata_blocks[index].offset; + length.QuadPart = block_reader->metadata_blocks[index].length; + + hr = IWICStream_InitializeFromIStreamRegion(stream, block_reader->decoder->stream, + offset, length); + } + + if (block_reader->metadata_blocks[index].options & DECODER_BLOCK_READER_CLSID) + { + IWICMetadataReader *reader; + IWICPersistStream *persist; + if (SUCCEEDED(hr)) + { + hr = create_instance(&block_reader->metadata_blocks[index].reader_clsid, + &IID_IWICMetadataReader, (void**)&reader); + } + + if (SUCCEEDED(hr)) + { + hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist); + + if (SUCCEEDED(hr)) + { + hr = IWICPersistStream_LoadEx(persist, (IStream*)stream, NULL, + block_reader->metadata_blocks[index].options & DECODER_BLOCK_OPTION_MASK); + + IWICPersistStream_Release(persist); + } + + if (SUCCEEDED(hr)) + *ret_reader = reader; + else + IWICMetadataReader_Release(reader); + } + } + else + { + hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, + &block_reader->decoder->decoder_info.block_format, NULL, + block_reader->metadata_blocks[index].options & DECODER_BLOCK_OPTION_MASK, + (IStream *)stream, ret_reader); + } + + IWICStream_Release(stream); + } + + if (factory) IWICComponentFactory_Release(factory); + + if (FAILED(hr)) + *ret_reader = NULL; + + return hr; +} + static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) { return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface); @@ -248,9 +411,7 @@ typedef struct { CommonDecoder *parent; DWORD frame; struct decoder_frame decoder_frame; - BOOL metadata_initialized; - UINT metadata_count; - struct decoder_block* metadata_blocks; + struct metadata_block_reader block_reader; } CommonDecoderFrame;
static inline CommonDecoderFrame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) @@ -310,7 +471,7 @@ static ULONG WINAPI CommonDecoderFrame_Release(IWICBitmapFrameDecode *iface) if (ref == 0) { IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); - free(This->metadata_blocks); + metadata_block_reader_cleanup(&This->block_reader); free(This); }
@@ -559,148 +720,27 @@ static HRESULT WINAPI CommonDecoderFrame_Block_GetContainerFormat(IWICMetadataBl GUID *pguidContainerFormat) { CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); - if (!pguidContainerFormat) return E_INVALIDARG; - *pguidContainerFormat = This->parent->decoder_info.block_format; - return S_OK; -} - -static HRESULT CommonDecoderFrame_InitializeMetadata(CommonDecoderFrame *This) -{ - HRESULT hr=S_OK; - - if (This->metadata_initialized) - return S_OK; - - EnterCriticalSection(&This->parent->lock); - - if (!This->metadata_initialized) - { - hr = decoder_get_metadata_blocks(This->parent->decoder, This->frame, &This->metadata_count, &This->metadata_blocks); - if (SUCCEEDED(hr)) - This->metadata_initialized = TRUE; - } - - LeaveCriticalSection(&This->parent->lock); - - return hr; + return metadata_block_reader_get_container_format(&This->block_reader, pguidContainerFormat); }
static HRESULT WINAPI CommonDecoderFrame_Block_GetCount(IWICMetadataBlockReader *iface, UINT *pcCount) { CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); - HRESULT hr;
TRACE("%p,%p\n", iface, pcCount);
- if (!pcCount) return E_INVALIDARG; - - hr = CommonDecoderFrame_InitializeMetadata(This); - if (SUCCEEDED(hr)) - *pcCount = This->metadata_count; - - return hr; + return metadata_block_reader_get_count(&This->block_reader, pcCount); }
static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, UINT nIndex, IWICMetadataReader **ppIMetadataReader) { CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); - HRESULT hr; - IWICComponentFactory* factory = NULL; - IWICStream* stream;
TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader);
- if (!ppIMetadataReader) - return E_INVALIDARG; - - hr = CommonDecoderFrame_InitializeMetadata(This); - - if (SUCCEEDED(hr) && nIndex >= This->metadata_count) - hr = E_INVALIDARG; - - if (SUCCEEDED(hr)) - hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory); - - if (SUCCEEDED(hr)) - hr = IWICComponentFactory_CreateStream(factory, &stream); - - if (SUCCEEDED(hr)) - { - if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_FULL_STREAM) - { - LARGE_INTEGER offset; - offset.QuadPart = This->metadata_blocks[nIndex].offset; - - hr = IWICStream_InitializeFromIStream(stream, This->parent->stream); - - if (SUCCEEDED(hr)) - hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); - } - else if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_OFFSET_IS_PTR) - { - BYTE *data = (BYTE *)(ULONG_PTR)This->metadata_blocks[nIndex].offset; - UINT size = This->metadata_blocks[nIndex].length; - - hr = IWICStream_InitializeFromMemory(stream, data, size); - } - else - { - ULARGE_INTEGER offset, length; - - offset.QuadPart = This->metadata_blocks[nIndex].offset; - length.QuadPart = This->metadata_blocks[nIndex].length; - - hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream, - offset, length); - } - - if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_READER_CLSID) - { - IWICMetadataReader *reader; - IWICPersistStream *persist; - if (SUCCEEDED(hr)) - { - hr = create_instance(&This->metadata_blocks[nIndex].reader_clsid, - &IID_IWICMetadataReader, (void**)&reader); - } - - if (SUCCEEDED(hr)) - { - hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist); - - if (SUCCEEDED(hr)) - { - hr = IWICPersistStream_LoadEx(persist, (IStream*)stream, NULL, - This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK); - - IWICPersistStream_Release(persist); - } - - if (SUCCEEDED(hr)) - *ppIMetadataReader = reader; - else - IWICMetadataReader_Release(reader); - } - } - else - { - hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, - &This->parent->decoder_info.block_format, NULL, - This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK, - (IStream*)stream, ppIMetadataReader); - } - - IWICStream_Release(stream); - } - - if (factory) IWICComponentFactory_Release(factory); - - if (FAILED(hr)) - *ppIMetadataReader = NULL; - - return S_OK; + return metadata_block_reader_get_reader(&This->block_reader, nIndex, ppIMetadataReader); }
static HRESULT WINAPI CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader *iface, @@ -751,14 +791,12 @@ static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, result->ref = 1; result->parent = This; result->frame = index; - result->metadata_initialized = FALSE; - result->metadata_count = 0; - result->metadata_blocks = NULL; + metadata_block_reader_initialize(&result->block_reader, This, index);
hr = decoder_get_frame_info(This->decoder, index, &result->decoder_frame);
if (SUCCEEDED(hr) && This->cache_options == WICDecodeMetadataCacheOnLoad) - hr = CommonDecoderFrame_InitializeMetadata(result); + hr = metadata_block_reader_initialize_metadata(&result->block_reader);
if (FAILED(hr)) free(result);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 112 +++++++++++++++++++++---- dlls/windowscodecs/wincodecs_private.h | 8 +- 2 files changed, 104 insertions(+), 16 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index 3b594c71101..37ad8c10007 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -43,12 +43,14 @@ struct metadata_block_reader
typedef struct CommonDecoder { IWICBitmapDecoder IWICBitmapDecoder_iface; + IWICMetadataBlockReader IWICMetadataBlockReader_iface; LONG ref; CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */ IStream *stream; struct decoder *decoder; struct decoder_info decoder_info; struct decoder_stat file_info; + struct metadata_block_reader block_reader; WICDecodeOptions cache_options; } CommonDecoder;
@@ -209,6 +211,11 @@ static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *ifac return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface); }
+static inline CommonDecoder *impl_decoder_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoder, IWICMetadataBlockReader_iface); +} + static HRESULT WINAPI CommonDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, void **ppv) { @@ -221,6 +228,10 @@ static HRESULT WINAPI CommonDecoder_QueryInterface(IWICBitmapDecoder *iface, REF { *ppv = &This->IWICBitmapDecoder_iface; } + else if (This->file_info.flags & DECODER_FLAGS_METADATA_AT_DECODER && IsEqualIID(&IID_IWICMetadataBlockReader, iid)) + { + *ppv = &This->IWICMetadataBlockReader_iface; + } else { *ppv = NULL; @@ -254,6 +265,7 @@ static ULONG WINAPI CommonDecoder_Release(IWICBitmapDecoder *iface) IStream_Release(This->stream); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); + metadata_block_reader_cleanup(&This->block_reader); decoder_destroy(This->decoder); free(This); } @@ -330,13 +342,34 @@ static HRESULT WINAPI CommonDecoder_CopyPalette(IWICBitmapDecoder *iface, return WINCODEC_ERR_PALETTEUNAVAILABLE; }
+static HRESULT common_decoder_create_query_reader(IWICMetadataBlockReader *block_reader, IWICMetadataQueryReader **query_reader) +{ + IWICComponentFactory *factory; + HRESULT hr; + + hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void **)&factory); + + if (SUCCEEDED(hr)) + { + hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, block_reader, query_reader); + IWICComponentFactory_Release(factory); + } + + return hr; +} + static HRESULT WINAPI CommonDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, IWICMetadataQueryReader **reader) { + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%p)\n", iface, reader);
if (!reader) return E_INVALIDARG;
+ if (This->file_info.flags & DECODER_FLAGS_METADATA_AT_DECODER) + return common_decoder_create_query_reader(&This->IWICMetadataBlockReader_iface, reader); + *reader = NULL; return WINCODEC_ERR_UNSUPPORTEDOPERATION; } @@ -404,6 +437,68 @@ static const IWICBitmapDecoderVtbl CommonDecoder_Vtbl = { CommonDecoder_GetFrame };
+static HRESULT WINAPI CommonDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, + void **ppv) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + return IWICBitmapDecoder_QueryInterface(&decoder->IWICBitmapDecoder_iface, iid, ppv); +} + +static ULONG WINAPI CommonDecoder_Block_AddRef(IWICMetadataBlockReader *iface) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + return IWICBitmapDecoder_AddRef(&decoder->IWICBitmapDecoder_iface); +} + +static ULONG WINAPI CommonDecoder_Block_Release(IWICMetadataBlockReader *iface) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + return IWICBitmapDecoder_Release(&decoder->IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI CommonDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, GUID *format) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + return metadata_block_reader_get_container_format(&decoder->block_reader, format); +} + +static HRESULT WINAPI CommonDecoder_Block_GetCount(IWICMetadataBlockReader *iface, UINT *count) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + + TRACE("%p,%p\n", iface, count); + + return metadata_block_reader_get_count(&decoder->block_reader, count); +} + +static HRESULT WINAPI CommonDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, + UINT index, IWICMetadataReader **reader) +{ + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + + TRACE("%p,%d,%p\n", iface, index, reader); + + return metadata_block_reader_get_reader(&decoder->block_reader, index, reader); +} + +static HRESULT WINAPI CommonDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, + IEnumUnknown **ppIEnumMetadata) +{ + FIXME("%p,%p\n", iface, ppIEnumMetadata); + return E_NOTIMPL; +} + +static const IWICMetadataBlockReaderVtbl CommonDecoder_BlockVtbl = +{ + CommonDecoder_Block_QueryInterface, + CommonDecoder_Block_AddRef, + CommonDecoder_Block_Release, + CommonDecoder_Block_GetContainerFormat, + CommonDecoder_Block_GetCount, + CommonDecoder_Block_GetReaderByIndex, + CommonDecoder_Block_GetEnumerator, +}; + typedef struct { IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; IWICMetadataBlockReader IWICMetadataBlockReader_iface; @@ -593,8 +688,6 @@ static HRESULT WINAPI CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameD IWICMetadataQueryReader **ppIMetadataQueryReader) { CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); - IWICComponentFactory* factory; - HRESULT hr;
TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
@@ -604,18 +697,7 @@ static HRESULT WINAPI CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameD if (!(This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata)) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
- hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory); - - if (SUCCEEDED(hr)) - { - hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader); - IWICComponentFactory_Release(factory); - } - - if (FAILED(hr)) - *ppIMetadataQueryReader = NULL; - - return hr; + return common_decoder_create_query_reader(&This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader); }
static HRESULT WINAPI CommonDecoderFrame_GetColorContexts(IWICBitmapFrameDecode *iface, @@ -838,10 +920,12 @@ HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, }
This->IWICBitmapDecoder_iface.lpVtbl = &CommonDecoder_Vtbl; + This->IWICMetadataBlockReader_iface.lpVtbl = &CommonDecoder_BlockVtbl; This->ref = 1; This->stream = NULL; This->decoder = decoder; This->decoder_info = *decoder_info; + metadata_block_reader_initialize(&This->block_reader, This, ~0u); InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonDecoder.lock");
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index d9493b5607e..648ebf4305a 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -270,8 +270,12 @@ struct decoder_info CLSID clsid; };
-#define DECODER_FLAGS_CAPABILITY_MASK 0x1f -#define DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT 0x80000000 +enum decoder_flags +{ + DECODER_FLAGS_CAPABILITY_MASK = 0x1f, + DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT = 0x80000000, + DECODER_FLAGS_METADATA_AT_DECODER = 0x40000000, +};
struct decoder_stat {
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 28 ++++++++++++++++++++++---- dlls/windowscodecs/libjpeg.c | 7 +++++++ dlls/windowscodecs/libpng.c | 7 +++++++ dlls/windowscodecs/libtiff.c | 7 +++++++ dlls/windowscodecs/wincodecs_common.h | 5 +++++ dlls/windowscodecs/wincodecs_private.h | 2 ++ dlls/wmphoto/jxrlib.c | 6 ++++++ 7 files changed, 58 insertions(+), 4 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index 37ad8c10007..a287d79b8fd 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -47,6 +47,7 @@ typedef struct CommonDecoder { LONG ref; CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */ IStream *stream; + UINT frame; struct decoder *decoder; struct decoder_info decoder_info; struct decoder_stat file_info; @@ -338,8 +339,26 @@ static HRESULT WINAPI CommonDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, static HRESULT WINAPI CommonDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) { + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + WICColor colors[256]; + UINT num_colors; + HRESULT hr; + TRACE("(%p,%p)\n", iface, palette); - return WINCODEC_ERR_PALETTEUNAVAILABLE; + + if (FAILED(hr = decoder_get_decoder_palette(This->decoder, This->frame, colors, &num_colors))) + return hr; + + if (num_colors) + { + hr = IWICPalette_InitializeCustom(palette, colors, num_colors); + } + else + { + hr = WINCODEC_ERR_PALETTEUNAVAILABLE; + } + + return hr; }
static HRESULT common_decoder_create_query_reader(IWICMetadataBlockReader *block_reader, IWICMetadataQueryReader **query_reader) @@ -880,6 +899,9 @@ static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, if (SUCCEEDED(hr) && This->cache_options == WICDecodeMetadataCacheOnLoad) hr = metadata_block_reader_initialize_metadata(&result->block_reader);
+ if (SUCCEEDED(hr)) + This->frame = result->frame; + if (FAILED(hr)) free(result); } @@ -912,8 +934,7 @@ HRESULT CommonDecoder_CreateInstance(struct decoder *decoder,
TRACE("(%s,%s,%p)\n", debugstr_guid(&decoder_info->clsid), debugstr_guid(iid), ppv);
- This = malloc(sizeof(*This)); - if (!This) + if (!(This = calloc(1, sizeof(*This)))) { decoder_destroy(decoder); return E_OUTOFMEMORY; @@ -922,7 +943,6 @@ HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, This->IWICBitmapDecoder_iface.lpVtbl = &CommonDecoder_Vtbl; This->IWICMetadataBlockReader_iface.lpVtbl = &CommonDecoder_BlockVtbl; This->ref = 1; - This->stream = NULL; This->decoder = decoder; This->decoder_info = *decoder_info; metadata_block_reader_initialize(&This->block_reader, This, ~0u); diff --git a/dlls/windowscodecs/libjpeg.c b/dlls/windowscodecs/libjpeg.c index 22903ae4340..ad6f58e3f02 100644 --- a/dlls/windowscodecs/libjpeg.c +++ b/dlls/windowscodecs/libjpeg.c @@ -305,6 +305,12 @@ static HRESULT CDECL jpeg_decoder_get_frame_info(struct decoder* iface, UINT fra return S_OK; }
+static HRESULT CDECL jpeg_decoder_get_decoder_palette(struct decoder *iface, UINT frame, WICColor *colors, + UINT *num_colors) +{ + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + static HRESULT CDECL jpeg_decoder_copy_pixels(struct decoder* iface, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) { @@ -334,6 +340,7 @@ static HRESULT CDECL jpeg_decoder_get_color_context(struct decoder* This, UINT f static const struct decoder_funcs jpeg_decoder_vtable = { jpeg_decoder_initialize, jpeg_decoder_get_frame_info, + jpeg_decoder_get_decoder_palette, jpeg_decoder_copy_pixels, jpeg_decoder_get_metadata_blocks, jpeg_decoder_get_color_context, diff --git a/dlls/windowscodecs/libpng.c b/dlls/windowscodecs/libpng.c index 2c660b83e72..e4ef74f185b 100644 --- a/dlls/windowscodecs/libpng.c +++ b/dlls/windowscodecs/libpng.c @@ -349,6 +349,12 @@ static HRESULT CDECL png_decoder_get_frame_info(struct decoder *iface, UINT fram return S_OK; }
+static HRESULT CDECL png_decoder_get_decoder_palette(struct decoder *iface, UINT frame, WICColor *colors, + UINT *num_colors) +{ + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + static HRESULT CDECL png_decoder_copy_pixels(struct decoder *iface, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) { @@ -454,6 +460,7 @@ static void CDECL png_decoder_destroy(struct decoder* iface) static const struct decoder_funcs png_decoder_vtable = { png_decoder_initialize, png_decoder_get_frame_info, + png_decoder_get_decoder_palette, png_decoder_copy_pixels, png_decoder_get_metadata_blocks, png_decoder_get_color_context, diff --git a/dlls/windowscodecs/libtiff.c b/dlls/windowscodecs/libtiff.c index 16701a258f9..b88ccb68b62 100644 --- a/dlls/windowscodecs/libtiff.c +++ b/dlls/windowscodecs/libtiff.c @@ -650,6 +650,12 @@ static HRESULT CDECL tiff_decoder_get_frame_info(struct decoder* iface, UINT fra return hr; }
+static HRESULT CDECL tiff_decoder_get_decoder_palette(struct decoder *iface, UINT frame, WICColor *colors, + UINT *num_colors) +{ + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + static HRESULT tiff_decoder_read_tile(struct tiff_decoder *This, UINT tile_x, UINT tile_y) { tsize_t ret; @@ -1069,6 +1075,7 @@ static void CDECL tiff_decoder_destroy(struct decoder* iface) static const struct decoder_funcs tiff_decoder_vtable = { tiff_decoder_initialize, tiff_decoder_get_frame_info, + tiff_decoder_get_decoder_palette, tiff_decoder_copy_pixels, tiff_decoder_get_metadata_blocks, tiff_decoder_get_color_context, diff --git a/dlls/windowscodecs/wincodecs_common.h b/dlls/windowscodecs/wincodecs_common.h index dcccdc2e5f1..e369c7e6d97 100644 --- a/dlls/windowscodecs/wincodecs_common.h +++ b/dlls/windowscodecs/wincodecs_common.h @@ -26,6 +26,11 @@ HRESULT CDECL decoder_get_frame_info(struct decoder *decoder, UINT frame, struct return decoder->vtable->get_frame_info(decoder, frame, info); }
+HRESULT CDECL decoder_get_decoder_palette(struct decoder *decoder, UINT frame, WICColor *colors, UINT *num_colors) +{ + return decoder->vtable->get_decoder_palette(decoder, frame, colors, num_colors); +} + HRESULT CDECL decoder_copy_pixels(struct decoder *decoder, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) { diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 648ebf4305a..acc7909e7a8 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -319,6 +319,7 @@ struct decoder_funcs { HRESULT (CDECL *initialize)(struct decoder* This, IStream *stream, struct decoder_stat *st); HRESULT (CDECL *get_frame_info)(struct decoder* This, UINT frame, struct decoder_frame *info); + HRESULT (CDECL *get_decoder_palette)(struct decoder* This, UINT frame, WICColor *colors, UINT *num_colors); 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, @@ -336,6 +337,7 @@ HRESULT CDECL stream_write(IStream *stream, const void *buffer, ULONG write, ULO 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); HRESULT CDECL decoder_get_frame_info(struct decoder* This, UINT frame, struct decoder_frame *info); +HRESULT CDECL decoder_get_decoder_palette(struct decoder* This, UINT frame, WICColor *colors, UINT *num_colors); 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, diff --git a/dlls/wmphoto/jxrlib.c b/dlls/wmphoto/jxrlib.c index c5ce59b454e..d26a8baffca 100644 --- a/dlls/wmphoto/jxrlib.c +++ b/dlls/wmphoto/jxrlib.c @@ -249,6 +249,11 @@ static HRESULT CDECL wmp_decoder_get_frame_info(struct decoder *iface, UINT fram return S_OK; }
+static HRESULT CDECL wmp_decoder_get_decoder_palette(struct decoder *iface, UINT frame, WICColor *colors, UINT *num_colors) +{ + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + static HRESULT CDECL wmp_decoder_copy_pixels(struct decoder *iface, UINT frame, const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) { struct wmp_decoder *This = impl_from_decoder(iface); @@ -343,6 +348,7 @@ static void CDECL wmp_decoder_destroy(struct decoder* iface) static const struct decoder_funcs wmp_decoder_vtable = { wmp_decoder_initialize, wmp_decoder_get_frame_info, + wmp_decoder_get_decoder_palette, wmp_decoder_copy_pixels, wmp_decoder_get_metadata_blocks, wmp_decoder_get_color_context,
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/gifformat.c | 917 +++++++-------------------------- 1 file changed, 196 insertions(+), 721 deletions(-)
diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c index 554d4cf14fd..25403955284 100644 --- a/dlls/windowscodecs/gifformat.c +++ b/dlls/windowscodecs/gifformat.c @@ -33,6 +33,17 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+struct gif_decoder +{ + struct decoder decoder; + GifFileType *gif; +}; + +static inline struct gif_decoder *impl_from_decoder(struct decoder *iface) +{ + return CONTAINING_RECORD(iface, struct gif_decoder, decoder); +} + #include "pshpack1.h"
struct logical_screen_descriptor @@ -515,183 +526,6 @@ HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv) return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv); }
-static IStream *create_stream(const void *data, int data_size) -{ - HRESULT hr; - IStream *stream; - HGLOBAL hdata; - void *locked_data; - - hdata = GlobalAlloc(GMEM_MOVEABLE, data_size); - if (!hdata) return NULL; - - locked_data = GlobalLock(hdata); - memcpy(locked_data, data, data_size); - GlobalUnlock(hdata); - - hr = CreateStreamOnHGlobal(hdata, TRUE, &stream); - return FAILED(hr) ? NULL : stream; -} - -static HRESULT create_gif_metadata_reader(const void *data, int data_size, - class_constructor constructor, - IWICMetadataReader **reader) -{ - HRESULT hr; - IWICMetadataReader *metadata_reader; - IWICPersistStream *persist; - IStream *stream; - - /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ - - hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader); - if (FAILED(hr)) return hr; - - hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); - if (FAILED(hr)) - { - IWICMetadataReader_Release(metadata_reader); - return hr; - } - - stream = create_stream(data, data_size); - IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); - IStream_Release(stream); - - IWICPersistStream_Release(persist); - - *reader = metadata_reader; - return S_OK; -} - -typedef struct { - IWICBitmapDecoder IWICBitmapDecoder_iface; - IWICMetadataBlockReader IWICMetadataBlockReader_iface; - IStream *stream; - BYTE LSD_data[13]; /* Logical Screen Descriptor */ - LONG ref; - BOOL initialized; - GifFileType *gif; - UINT current_frame; - CRITICAL_SECTION lock; -} GifDecoder; - -typedef struct { - IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; - IWICMetadataBlockReader IWICMetadataBlockReader_iface; - LONG ref; - SavedImage *frame; - GifDecoder *parent; -} GifFrameDecode; - -static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) -{ - return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface); -} - -static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) -{ - return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface); -} - -static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) -{ - return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface); -} - -static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) -{ - return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface); -} - -static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, - void **ppv) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); - - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid) || - IsEqualIID(&IID_IWICBitmapSource, iid) || - IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) - { - *ppv = &This->IWICBitmapFrameDecode_iface; - } - else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) - { - *ppv = &This->IWICMetadataBlockReader_iface; - } - else - { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) refcount=%lu\n", iface, ref); - - return ref; -} - -static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) refcount=%lu\n", iface, ref); - - if (ref == 0) - { - IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); - free(This); - } - - return ref; -} - -static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface, - UINT *puiWidth, UINT *puiHeight) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); - - *puiWidth = This->frame->ImageDesc.Width; - *puiHeight = This->frame->ImageDesc.Height; - - return S_OK; -} - -static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, - WICPixelFormatGUID *pPixelFormat) -{ - memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); - - return S_OK; -} - -static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, - double *pDpiX, double *pDpiY) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - const GifWord aspect_word = This->parent->gif->SAspectRatio; - const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0; - TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); - - *pDpiX = 96.0 / aspect; - *pDpiY = 96.0; - - return S_OK; -} - static void copy_palette(ColorMapObject *cm, Extensions *extensions, int count, WICColor *colors) { int i; @@ -728,35 +562,6 @@ static void copy_palette(ColorMapObject *cm, Extensions *extensions, int count, } }
-static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, - IWICPalette *pIPalette) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - WICColor colors[256]; - ColorMapObject *cm = This->frame->ImageDesc.ColorMap; - int count; - - TRACE("(%p,%p)\n", iface, pIPalette); - - if (cm) - count = cm->ColorCount; - else - { - cm = This->parent->gif->SColorMap; - count = This->parent->gif->SColorTableSize; - } - - if (count > 256) - { - ERR("GIF contains %i colors???\n", count); - return E_FAIL; - } - - copy_palette(cm, &This->frame->Extensions, count, colors); - - return IWICPalette_InitializeCustom(pIPalette, colors, count); -} - static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer, UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) @@ -807,295 +612,6 @@ static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer, return S_OK; }
-static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, - const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); - - if (This->frame->ImageDesc.Interlace) - { - return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width, - This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, - prc, cbStride, cbBufferSize, pbBuffer); - } - else - { - return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width, - This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, - prc, cbStride, cbBufferSize, pbBuffer); - } -} - -static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, - IWICMetadataQueryReader **ppIMetadataQueryReader) -{ - GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - - TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); - - if (!ppIMetadataQueryReader) - return E_INVALIDARG; - - return MetadataQueryReader_CreateInstanceFromBlockReader(&This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader); -} - -static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, - UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) -{ - TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); - return WINCODEC_ERR_UNSUPPORTEDOPERATION; -} - -static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, - IWICBitmapSource **ppIThumbnail) -{ - TRACE("(%p,%p)\n", iface, ppIThumbnail); - return WINCODEC_ERR_CODECNOTHUMBNAIL; -} - -static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = { - GifFrameDecode_QueryInterface, - GifFrameDecode_AddRef, - GifFrameDecode_Release, - GifFrameDecode_GetSize, - GifFrameDecode_GetPixelFormat, - GifFrameDecode_GetResolution, - GifFrameDecode_CopyPalette, - GifFrameDecode_CopyPixels, - GifFrameDecode_GetMetadataQueryReader, - GifFrameDecode_GetColorContexts, - GifFrameDecode_GetThumbnail -}; - -static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, - REFIID iid, void **ppv) -{ - GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); - return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); -} - -static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) -{ - GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); - return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); -} - -static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface) -{ - GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); - return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); -} - -static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, - GUID *guid) -{ - TRACE("(%p,%p)\n", iface, guid); - - if (!guid) return E_INVALIDARG; - - *guid = GUID_ContainerFormatGif; - return S_OK; -} - -static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, - UINT *count) -{ - GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); - - TRACE("%p,%p\n", iface, count); - - if (!count) return E_INVALIDARG; - - *count = This->frame->Extensions.ExtensionBlockCount + 1; - return S_OK; -} - -static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader) -{ - HRESULT hr; - IWICMetadataReader *metadata_reader; - IWICPersistStream *persist; - IStream *stream; - struct image_descriptor IMD_data; - - /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ - - hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); - if (FAILED(hr)) return hr; - - hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); - if (FAILED(hr)) - { - IWICMetadataReader_Release(metadata_reader); - return hr; - } - - /* recreate IMD structure from GIF decoder data */ - IMD_data.left = This->frame->ImageDesc.Left; - IMD_data.top = This->frame->ImageDesc.Top; - IMD_data.width = This->frame->ImageDesc.Width; - IMD_data.height = This->frame->ImageDesc.Height; - IMD_data.packed = 0; - /* interlace_flag */ - IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0; - if (This->frame->ImageDesc.ColorMap) - { - /* local_color_table_flag */ - IMD_data.packed |= 1 << 7; - /* local_color_table_size */ - IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1; - /* sort_flag */ - IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0; - } - - stream = create_stream(&IMD_data, sizeof(IMD_data)); - IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); - IStream_Release(stream); - - IWICPersistStream_Release(persist); - - *reader = metadata_reader; - return S_OK; -} - -static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, - UINT index, IWICMetadataReader **reader) -{ - GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); - class_constructor constructor; - ExtensionBlock *ext; - const void *data; - int data_size; - - TRACE("(%p,%u,%p)\n", iface, index, reader); - - if (!reader) return E_INVALIDARG; - - if (index == 0) - return create_IMD_metadata_reader(This, reader); - - if (index >= This->frame->Extensions.ExtensionBlockCount + 1) - return E_INVALIDARG; - - ext = This->frame->Extensions.ExtensionBlocks + index - 1; - if (ext->Function == GRAPHICS_EXT_FUNC_CODE) - { - constructor = GCEReader_CreateInstance; - data = ext->Bytes + 3; - data_size = ext->ByteCount - 4; - } - else if (ext->Function == COMMENT_EXT_FUNC_CODE) - { - constructor = GifCommentReader_CreateInstance; - data = ext->Bytes; - data_size = ext->ByteCount; - } - else - { - constructor = UnknownMetadataReader_CreateInstance; - data = ext->Bytes; - data_size = ext->ByteCount; - } - - return create_gif_metadata_reader(data, data_size, constructor, reader); -} - -static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, - IEnumUnknown **enumerator) -{ - FIXME("(%p,%p): stub\n", iface, enumerator); - return E_NOTIMPL; -} - -static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl = -{ - GifFrameDecode_Block_QueryInterface, - GifFrameDecode_Block_AddRef, - GifFrameDecode_Block_Release, - GifFrameDecode_Block_GetContainerFormat, - GifFrameDecode_Block_GetCount, - GifFrameDecode_Block_GetReaderByIndex, - GifFrameDecode_Block_GetEnumerator -}; - -static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, - void **ppv) -{ - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); - - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid) || - IsEqualIID(&IID_IWICBitmapDecoder, iid)) - { - *ppv = &This->IWICBitmapDecoder_iface; - } - else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) - { - *ppv = &This->IWICMetadataBlockReader_iface; - } - else - { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface) -{ - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) refcount=%lu\n", iface, ref); - - return ref; -} - -static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface) -{ - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) refcount=%lu\n", iface, ref); - - if (ref == 0) - { - if (This->stream) - { - IStream_Release(This->stream); - DGifCloseFile(This->gif); - } - This->lock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->lock); - free(This); - } - - return ref; -} - -static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, - DWORD *capability) -{ - HRESULT hr; - - TRACE("(%p,%p,%p)\n", iface, stream, capability); - - if (!stream || !capability) return E_INVALIDARG; - - hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); - if (hr != S_OK) return hr; - - *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | - WICBitmapDecoderCapabilityCanDecodeSomeImages | - WICBitmapDecoderCapabilityCanEnumerateMetadata; - return S_OK; -} - static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { IStream *stream = gif->UserData; ULONG bytesread; @@ -1112,89 +628,94 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { return bytesread; }
-static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, - WICDecodeOptions cacheOptions) +static HRESULT CDECL gif_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st) { - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); + struct gif_decoder *decoder = impl_from_decoder(iface); LARGE_INTEGER seek; int ret;
- TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); - - EnterCriticalSection(&This->lock); - - if (This->initialized || This->gif) - { - WARN("already initialized\n"); - LeaveCriticalSection(&This->lock); - return WINCODEC_ERR_WRONGSTATE; - } - /* seek to start of stream */ seek.QuadPart = 0; - IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); + IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
/* read all data from the stream */ - This->gif = DGifOpen((void*)pIStream, _gif_inputfunc); - if (!This->gif) - { - LeaveCriticalSection(&This->lock); + decoder->gif = DGifOpen((void *)stream, _gif_inputfunc); + if (!decoder->gif) return E_FAIL; - }
- ret = DGifSlurp(This->gif); + ret = DGifSlurp(decoder->gif); if (ret == GIF_ERROR) - { - LeaveCriticalSection(&This->lock); return E_FAIL; - }
/* make sure we don't use the stream after this method returns */ - This->gif->UserData = NULL; - - seek.QuadPart = 0; - IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); - IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL); - - This->stream = pIStream; - IStream_AddRef(This->stream); + decoder->gif->UserData = NULL;
- This->initialized = TRUE; - - LeaveCriticalSection(&This->lock); + st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages | + WICBitmapDecoderCapabilityCanDecodeSomeImages | + WICBitmapDecoderCapabilityCanEnumerateMetadata | + DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT | + DECODER_FLAGS_METADATA_AT_DECODER; + st->frame_count = decoder->gif->ImageCount;
return S_OK; }
-static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface, - GUID *pguidContainerFormat) +static HRESULT CDECL gif_decoder_get_frame_info(struct decoder *iface, UINT frame, struct decoder_frame *info) { - memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID)); - return S_OK; -} + struct gif_decoder *decoder = impl_from_decoder(iface); + ColorMapObject *colormap; + GifWord aspect_word; + SavedImage *image; + DWORD num_colors; + double aspect;
-static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, - IWICBitmapDecoderInfo **ppIDecoderInfo) -{ - TRACE("(%p,%p)\n", iface, ppIDecoderInfo); + if (frame >= decoder->gif->ImageCount) + return WINCODEC_ERR_FRAMEMISSING; + + aspect_word = decoder->gif->SAspectRatio; + aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0; + + image = &decoder->gif->SavedImages[frame]; + + colormap = image->ImageDesc.ColorMap; + if (colormap) + { + num_colors = colormap->ColorCount; + } + else + { + colormap = decoder->gif->SColorMap; + num_colors = decoder->gif->SColorTableSize; + } + + memcpy(&info->pixel_format, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); + info->width = image->ImageDesc.Width; + info->height = image->ImageDesc.Height; + info->bpp = 8; + info->dpix = 96.0 / aspect; + info->dpiy = 96.0; + info->num_color_contexts = 0; + info->num_colors = num_colors; + copy_palette(colormap, &image->Extensions, num_colors, info->palette);
- return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo); + return S_OK; }
-static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) +static HRESULT CDECL gif_decoder_get_decoder_palette(struct decoder *iface, UINT frame, WICColor *colors, + UINT *num_colors) { - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); - WICColor colors[256]; + struct gif_decoder *decoder = impl_from_decoder(iface); ColorMapObject *cm; int count;
- TRACE("(%p,%p)\n", iface, palette); - - if (!This->gif) + if (!decoder->gif) return WINCODEC_ERR_WRONGSTATE;
- cm = This->gif->SColorMap; - count = This->gif->SColorTableSize; + if (frame >= decoder->gif->ImageCount) + return WINCODEC_ERR_FRAMEMISSING; + + cm = decoder->gif->SColorMap; + count = decoder->gif->SColorTableSize;
if (count > 256) { @@ -1202,226 +723,180 @@ static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalet return E_FAIL; }
- copy_palette(cm, &This->gif->SavedImages[This->current_frame].Extensions, count, colors); + copy_palette(cm, &decoder->gif->SavedImages[frame].Extensions, count, colors); + + *num_colors = count;
- return IWICPalette_InitializeCustom(palette, colors, count); + return S_OK; }
-static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, - IWICMetadataQueryReader **ppIMetadataQueryReader) +static HRESULT CDECL gif_decoder_copy_pixels(struct decoder *iface, UINT frame, + const WICRect *prc, UINT stride, UINT buffersize, BYTE *buffer) { - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); + struct gif_decoder *decoder = impl_from_decoder(iface); + SavedImage *image;
- TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); + if (frame >= decoder->gif->ImageCount) + return E_INVALIDARG;
- if (!ppIMetadataQueryReader) return E_INVALIDARG; + image = &decoder->gif->SavedImages[frame];
- return MetadataQueryReader_CreateInstanceFromBlockReader(&This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader); -} + if (image->ImageDesc.Interlace) + return copy_interlaced_pixels(image->RasterBits, image->ImageDesc.Width, + image->ImageDesc.Height, image->ImageDesc.Width, prc, stride, buffersize, buffer);
-static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface, - IWICBitmapSource **ppIBitmapSource) -{ - TRACE("(%p,%p)\n", iface, ppIBitmapSource); - return WINCODEC_ERR_UNSUPPORTEDOPERATION; + return copy_pixels(8, image->RasterBits, image->ImageDesc.Width, image->ImageDesc.Height, + image->ImageDesc.Width, prc, stride, buffersize, buffer); }
-static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface, - UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +static HRESULT CDECL gif_decoder_get_metadata_blocks(struct decoder *iface, + UINT frame, UINT *count, struct decoder_block **blocks) { - TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); - return WINCODEC_ERR_UNSUPPORTEDOPERATION; -} + struct gif_decoder *decoder = impl_from_decoder(iface); + struct decoder_block *result; + UINT block_count, index = 0; + ExtensionBlock *ext; + SavedImage *image;
-static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface, - IWICBitmapSource **ppIThumbnail) -{ - TRACE("(%p,%p)\n", iface, ppIThumbnail); - return WINCODEC_ERR_CODECNOTHUMBNAIL; -} + if (frame == ~0u) + { + block_count = decoder->gif->Extensions.ExtensionBlockCount + 1;
-static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface, - UINT *pCount) -{ - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); + if (!(result = calloc(block_count, sizeof(*result)))) + return E_OUTOFMEMORY;
- if (!pCount) return E_INVALIDARG; + result[index].offset = 0; + result[index].length = sizeof(struct logical_screen_descriptor); + result[index].options = DECODER_BLOCK_READER_CLSID; + result[index].reader_clsid = CLSID_WICLSDMetadataReader;
- EnterCriticalSection(&This->lock); - *pCount = This->gif ? This->gif->ImageCount : 0; - LeaveCriticalSection(&This->lock); + for (index = 1; index < block_count; ++index) + { + ext = decoder->gif->Extensions.ExtensionBlocks + index - 1;
- TRACE("(%p) <-- %d\n", iface, *pCount); + result[index].offset = (ULONG_PTR)ext->Bytes; + result[index].length = ext->ByteCount; + result[index].options = DECODER_BLOCK_OFFSET_IS_PTR;
- return S_OK; -} + if (ext->Function == APPLICATION_EXT_FUNC_CODE) + { + result[index].reader_clsid = CLSID_WICAPEMetadataReader; + result[index].options |= DECODER_BLOCK_READER_CLSID; + } + else if (ext->Function == COMMENT_EXT_FUNC_CODE) + { + result[index].reader_clsid = CLSID_WICGifCommentMetadataReader; + result[index].options |= DECODER_BLOCK_READER_CLSID; + } + else + { + result[index].options |= WICMetadataCreationAllowUnknown; + } + } + } + else if (frame < decoder->gif->ImageCount) + { + image = &decoder->gif->SavedImages[frame];
-static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface, - UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) -{ - GifDecoder *This = impl_from_IWICBitmapDecoder(iface); - GifFrameDecode *result; - TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); + block_count = image->Extensions.ExtensionBlockCount + 1;
- if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; + if (!(result = calloc(block_count, sizeof(*result)))) + return E_OUTOFMEMORY;
- if (index >= This->gif->ImageCount) return E_INVALIDARG; + result[index].offset = image->ImageDescOffset; + result[index].length = 9; + result[index].options = DECODER_BLOCK_READER_CLSID; + result[index].reader_clsid = CLSID_WICIMDMetadataReader;
- result = malloc(sizeof(GifFrameDecode)); - if (!result) return E_OUTOFMEMORY; + for (index = 1; index < block_count; ++index) + { + ext = image->Extensions.ExtensionBlocks + index - 1;
- result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl; - result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl; - result->ref = 1; - result->frame = &This->gif->SavedImages[index]; - IWICBitmapDecoder_AddRef(iface); - result->parent = This; - This->current_frame = index; + if (ext->Function == GRAPHICS_EXT_FUNC_CODE) + { + result[index].offset = (ULONG_PTR)(ext->Bytes + 3); + result[index].length = ext->ByteCount - 4; + result[index].options = DECODER_BLOCK_OFFSET_IS_PTR | DECODER_BLOCK_READER_CLSID; + result[index].reader_clsid = CLSID_WICGCEMetadataReader; + } + else if (ext->Function == COMMENT_EXT_FUNC_CODE) + { + result[index].offset = (ULONG_PTR)ext->Bytes; + result[index].length = ext->ByteCount; + result[index].options = DECODER_BLOCK_OFFSET_IS_PTR | DECODER_BLOCK_READER_CLSID; + result[index].reader_clsid = CLSID_WICGifCommentMetadataReader; + } + else + { + result[index].offset = (ULONG_PTR)ext->Bytes; + result[index].length = ext->ByteCount; + result[index].options = DECODER_BLOCK_OFFSET_IS_PTR | WICMetadataCreationAllowUnknown; + } + } + } + else + return E_INVALIDARG;
- *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; + *count = block_count; + *blocks = result;
return S_OK; }
-static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = { - GifDecoder_QueryInterface, - GifDecoder_AddRef, - GifDecoder_Release, - GifDecoder_QueryCapability, - GifDecoder_Initialize, - GifDecoder_GetContainerFormat, - GifDecoder_GetDecoderInfo, - GifDecoder_CopyPalette, - GifDecoder_GetMetadataQueryReader, - GifDecoder_GetPreview, - GifDecoder_GetColorContexts, - GifDecoder_GetThumbnail, - GifDecoder_GetFrameCount, - GifDecoder_GetFrame -}; - -static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, - REFIID iid, void **ppv) -{ - GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); -} - -static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface) -{ - GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); -} - -static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface) +static HRESULT CDECL gif_decoder_get_color_context(struct decoder *iface, UINT frame, UINT num, + BYTE **data, DWORD *datasize) { - GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); + return E_NOTIMPL; }
-static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, - GUID *guid) +static void CDECL gif_decoder_destroy(struct decoder *iface) { - TRACE("(%p,%p)\n", iface, guid); + struct gif_decoder *decoder = impl_from_decoder(iface);
- if (!guid) return E_INVALIDARG; - - *guid = GUID_ContainerFormatGif; - return S_OK; + DGifCloseFile(decoder->gif); + free(decoder); }
-static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface, - UINT *count) +static const struct decoder_funcs gif_decoder_vtable = { - GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); - - TRACE("%p,%p\n", iface, count); - - if (!count) return E_INVALIDARG; - - *count = This->gif->Extensions.ExtensionBlockCount + 1; - return S_OK; -} + gif_decoder_initialize, + gif_decoder_get_frame_info, + gif_decoder_get_decoder_palette, + gif_decoder_copy_pixels, + gif_decoder_get_metadata_blocks, + gif_decoder_get_color_context, + gif_decoder_destroy +};
-static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, - UINT index, IWICMetadataReader **reader) +HRESULT CDECL gif_decoder_create(struct decoder_info *info, struct decoder **result) { - GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); - int i; - - TRACE("(%p,%u,%p)\n", iface, index, reader); - - if (!reader) return E_INVALIDARG; - - if (index == 0) - return create_gif_metadata_reader(This->LSD_data, sizeof(This->LSD_data), - LSDReader_CreateInstance, reader); - - for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) - { - class_constructor constructor; - - if (index != i + 1) continue; + struct gif_decoder *gif_decoder;
- if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE) - constructor = APEReader_CreateInstance; - else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) - constructor = GifCommentReader_CreateInstance; - else - constructor = UnknownMetadataReader_CreateInstance; + if (!(gif_decoder = calloc(1, sizeof(*gif_decoder)))) + return E_OUTOFMEMORY;
- return create_gif_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, - This->gif->Extensions.ExtensionBlocks[i].ByteCount, - constructor, reader); - } + gif_decoder->decoder.vtable = &gif_decoder_vtable; + *result = &gif_decoder->decoder;
- return E_INVALIDARG; -} + info->container_format = GUID_ContainerFormatGif; + info->block_format = GUID_ContainerFormatGif; + info->clsid = CLSID_WICGifDecoder;
-static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, - IEnumUnknown **enumerator) -{ - FIXME("(%p,%p): stub\n", iface, enumerator); - return E_NOTIMPL; + return S_OK; }
-static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl = -{ - GifDecoder_Block_QueryInterface, - GifDecoder_Block_AddRef, - GifDecoder_Block_Release, - GifDecoder_Block_GetContainerFormat, - GifDecoder_Block_GetCount, - GifDecoder_Block_GetReaderByIndex, - GifDecoder_Block_GetEnumerator -}; - -HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv) +HRESULT GifDecoder_CreateInstance(REFIID iid, void **ppv) { - GifDecoder *This; - HRESULT ret; - - TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); + struct decoder_info decoder_info; + struct decoder *decoder; + HRESULT hr;
- *ppv = NULL; + hr = gif_decoder_create(&decoder_info, &decoder);
- This = malloc(sizeof(GifDecoder)); - if (!This) return E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + hr = CommonDecoder_CreateInstance(decoder, &decoder_info, iid, ppv);
- This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl; - This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl; - This->stream = NULL; - This->ref = 1; - This->initialized = FALSE; - This->gif = NULL; - This->current_frame = 0; - InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); - This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock"); - - ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); - IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); - - return ret; + return hr; }
typedef struct GifEncoder
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 50 +++++++++++++++++++++++++---- dlls/windowscodecs/tests/metadata.c | 3 -- 2 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index a287d79b8fd..0675fba0810 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -37,6 +37,7 @@ struct metadata_block_reader BOOL metadata_initialized; UINT metadata_count; struct decoder_block *metadata_blocks; + IWICMetadataReader **readers; UINT frame; CommonDecoder *decoder; }; @@ -64,7 +65,16 @@ static void metadata_block_reader_initialize(struct metadata_block_reader *block
static void metadata_block_reader_cleanup(struct metadata_block_reader *block_reader) { + UINT i; + + for (i = 0; i < block_reader->metadata_count && block_reader->readers; ++i) + { + if (block_reader->readers[i]) + IWICMetadataReader_Release(block_reader->readers[i]); + } + free(block_reader->readers); free(block_reader->metadata_blocks); + memset(block_reader, 0, sizeof(*block_reader)); }
static HRESULT metadata_block_reader_initialize_metadata(struct metadata_block_reader *block_reader) @@ -82,6 +92,16 @@ static HRESULT metadata_block_reader_initialize_metadata(struct metadata_block_r &block_reader->metadata_count, &block_reader->metadata_blocks); if (SUCCEEDED(hr)) block_reader->metadata_initialized = TRUE; + + if (SUCCEEDED(hr)) + { + block_reader->readers = calloc(block_reader->metadata_count, sizeof(*block_reader->readers)); + if (!block_reader->readers) + { + metadata_block_reader_cleanup(block_reader); + hr = E_OUTOFMEMORY; + } + } }
LeaveCriticalSection(&block_reader->decoder->lock); @@ -113,17 +133,27 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl UINT index, IWICMetadataReader **ret_reader) { IWICComponentFactory *factory = NULL; + IWICMetadataReader *reader; IWICStream *stream; HRESULT hr;
if (!ret_reader) return E_INVALIDARG;
+ *ret_reader = NULL; + hr = metadata_block_reader_initialize_metadata(block_reader);
if (SUCCEEDED(hr) && index >= block_reader->metadata_count) hr = E_INVALIDARG;
+ if (SUCCEEDED(hr) && block_reader->readers[index]) + { + *ret_reader = block_reader->readers[index]; + IWICMetadataReader_AddRef(*ret_reader); + return S_OK; + } + if (SUCCEEDED(hr)) hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory);
@@ -162,7 +192,6 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl
if (block_reader->metadata_blocks[index].options & DECODER_BLOCK_READER_CLSID) { - IWICMetadataReader *reader; IWICPersistStream *persist; if (SUCCEEDED(hr)) { @@ -182,10 +211,11 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl IWICPersistStream_Release(persist); }
- if (SUCCEEDED(hr)) - *ret_reader = reader; - else + if (FAILED(hr)) + { IWICMetadataReader_Release(reader); + reader = NULL; + } } } else @@ -193,7 +223,7 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, &block_reader->decoder->decoder_info.block_format, NULL, block_reader->metadata_blocks[index].options & DECODER_BLOCK_OPTION_MASK, - (IStream *)stream, ret_reader); + (IStream *)stream, &reader); }
IWICStream_Release(stream); @@ -201,8 +231,14 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl
if (factory) IWICComponentFactory_Release(factory);
- if (FAILED(hr)) - *ret_reader = NULL; + if (SUCCEEDED(hr)) + { + if (InterlockedCompareExchangePointer((void **)&block_reader->readers[index], reader, NULL)) + IWICMetadataReader_Release(reader); + + *ret_reader = block_reader->readers[index]; + IWICMetadataReader_AddRef(*ret_reader); + }
return hr; } diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 98b59a2cdb9..ccfb0fe185c 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -2213,7 +2213,6 @@ static void test_metadata_png(void) ok(hr == S_OK, "GetReaderByIndex failed, hr=%lx\n", hr); hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(reader == reader2, "Unexpected instance.\n"); IWICMetadataReader_Release(reader2);
@@ -2381,7 +2380,6 @@ static void test_metadata_gif(void)
hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader2); ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr); - todo_wine ok(reader == reader2, "Unexpected instance.\n"); IWICMetadataReader_Release(reader2);
@@ -2437,7 +2435,6 @@ static void test_metadata_gif(void) ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr); hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader2); ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr); - todo_wine ok(reader == reader2, "Unexpected instance.\n"); IWICMetadataReader_Release(reader2);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/decoder.c | 221 +++++++++++++++++++++++++++- dlls/windowscodecs/tests/metadata.c | 7 +- 2 files changed, 219 insertions(+), 9 deletions(-)
diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c index 0675fba0810..9142c1ca4e3 100644 --- a/dlls/windowscodecs/decoder.c +++ b/dlls/windowscodecs/decoder.c @@ -30,6 +30,170 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+struct object_enumerator +{ + IEnumUnknown IEnumUnknown_iface; + LONG refcount; + + IUnknown **objects; + unsigned int count; + unsigned int position; +}; + +static inline struct object_enumerator *impl_from_IEnumUnknown(IEnumUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct object_enumerator, IEnumUnknown_iface); +} + +static HRESULT WINAPI object_enumerator_QueryInterface(IEnumUnknown *iface, REFIID riid, void **obj) +{ + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IEnumUnknown) || + IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + IEnumUnknown_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI object_enumerator_AddRef(IEnumUnknown *iface) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + ULONG refcount = InterlockedIncrement(&enumerator->refcount); + + TRACE("%p refcount %lu.\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI object_enumerator_Release(IEnumUnknown *iface) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + ULONG refcount = InterlockedDecrement(&enumerator->refcount); + unsigned int i; + + TRACE("%p refcount %lu.\n", iface, refcount); + + if (!refcount) + { + for (i = 0; i < enumerator->count; ++i) + IUnknown_Release(enumerator->objects[i]); + free(enumerator->objects); + free(enumerator); + } + + return refcount; +} + +static HRESULT WINAPI object_enumerator_Next(IEnumUnknown *iface, ULONG count, IUnknown **ret, ULONG *fetched) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + ULONG tmp; + + TRACE("%p, %lu, %p, %p.\n", iface, count, ret, fetched); + + if (!fetched) fetched = &tmp; + + *fetched = 0; + + while (enumerator->position < enumerator->count && *fetched < count) + { + *ret = enumerator->objects[enumerator->position++]; + IUnknown_AddRef(*ret); + + *fetched = *fetched + 1; + ret++; + } + + return *fetched == count ? S_OK : S_FALSE; +} + +static HRESULT WINAPI object_enumerator_Skip(IEnumUnknown *iface, ULONG count) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + HRESULT hr; + + TRACE("%p, %lu.\n", iface, count); + + hr = (count > enumerator->count || enumerator->position > enumerator->count - count) ? S_FALSE : S_OK; + + count = min(count, enumerator->count - enumerator->position); + enumerator->position += count; + + return hr; +} + +static HRESULT WINAPI object_enumerator_Reset(IEnumUnknown *iface) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + + TRACE("%p.\n", iface); + + enumerator->position = 0; + return S_OK; +} + +static HRESULT create_object_enumerator(IUnknown **objects, unsigned int position, + unsigned int count, IEnumUnknown **ret); + +static HRESULT WINAPI object_enumerator_Clone(IEnumUnknown *iface, IEnumUnknown **ret) +{ + struct object_enumerator *enumerator = impl_from_IEnumUnknown(iface); + + TRACE("%p, %p.\n", iface, ret); + + if (!ret) + return E_INVALIDARG; + + return create_object_enumerator(enumerator->objects, enumerator->position, enumerator->count, ret); +} + +static const IEnumUnknownVtbl object_enumerator_vtbl = +{ + object_enumerator_QueryInterface, + object_enumerator_AddRef, + object_enumerator_Release, + object_enumerator_Next, + object_enumerator_Skip, + object_enumerator_Reset, + object_enumerator_Clone, +}; + +static HRESULT create_object_enumerator(IUnknown **objects, unsigned int position, + unsigned int count, IEnumUnknown **ret) +{ + struct object_enumerator *object; + unsigned int i; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IEnumUnknown_iface.lpVtbl = &object_enumerator_vtbl; + object->refcount = 1; + if (!(object->objects = calloc(count, sizeof(*object->objects)))) + { + free(object); + return E_OUTOFMEMORY; + } + object->position = position; + object->count = count; + + for (i = 0; i < count; ++i) + { + object->objects[i] = objects[i]; + IUnknown_AddRef(object->objects[i]); + } + + *ret = &object->IEnumUnknown_iface; + + return S_OK; +} + typedef struct CommonDecoder CommonDecoder;
struct metadata_block_reader @@ -243,6 +407,45 @@ static HRESULT metadata_block_reader_get_reader(struct metadata_block_reader *bl return hr; }
+static HRESULT metadata_block_reader_get_enumerator(struct metadata_block_reader *block_reader, + IEnumUnknown **enumerator) +{ + IUnknown **objects; + HRESULT hr = S_OK; + UINT count, i; + + if (!enumerator) + return E_INVALIDARG; + + *enumerator = NULL; + + if (FAILED(hr = metadata_block_reader_initialize_metadata(block_reader))) + return hr; + + count = block_reader->metadata_count; + + if (!(objects = calloc(count, sizeof(*objects)))) + return E_OUTOFMEMORY; + + for (i = 0; i < count; ++i) + { + hr = metadata_block_reader_get_reader(block_reader, i, (IWICMetadataReader **)&objects[i]); + if (FAILED(hr)) + break; + } + + if (SUCCEEDED(hr)) + hr = create_object_enumerator(objects, 0, count, enumerator); + + for (i = 0; i < count; ++i) + { + if (objects[i]) + IUnknown_Release(objects[i]); + } + + return hr; +} + static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) { return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface); @@ -537,10 +740,13 @@ static HRESULT WINAPI CommonDecoder_Block_GetReaderByIndex(IWICMetadataBlockRead }
static HRESULT WINAPI CommonDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, - IEnumUnknown **ppIEnumMetadata) + IEnumUnknown **enumerator) { - FIXME("%p,%p\n", iface, ppIEnumMetadata); - return E_NOTIMPL; + CommonDecoder *decoder = impl_decoder_from_IWICMetadataBlockReader(iface); + + TRACE("%p,%p\n", iface, enumerator); + + return metadata_block_reader_get_enumerator(&decoder->block_reader, enumerator); }
static const IWICMetadataBlockReaderVtbl CommonDecoder_BlockVtbl = @@ -881,10 +1087,13 @@ static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBloc }
static HRESULT WINAPI CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader *iface, - IEnumUnknown **ppIEnumMetadata) + IEnumUnknown **enumerator) { - FIXME("%p,%p\n", iface, ppIEnumMetadata); - return E_NOTIMPL; + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + + TRACE("%p,%p\n", iface, enumerator); + + return metadata_block_reader_get_enumerator(&This->block_reader, enumerator); }
static const IWICMetadataBlockReaderVtbl CommonDecoderFrame_BlockVtbl = { diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index ccfb0fe185c..039bbdb6079 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -114,13 +114,10 @@ static void test_block_reader_enumerator(IWICMetadataBlockReader *block_reader) HRESULT hr;
hr = IWICMetadataBlockReader_GetEnumerator(block_reader, NULL); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IWICMetadataBlockReader_GetEnumerator(block_reader, &block_enum); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) return;
hr = IWICMetadataBlockReader_GetEnumerator(block_reader, &block_enum2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -187,6 +184,8 @@ static void test_block_reader_enumerator(IWICMetadataBlockReader *block_reader) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IEnumUnknown_Skip(block_enum, block_count + 1); ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); + hr = IEnumUnknown_Skip(block_enum, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); fetched = 0; hr = IEnumUnknown_Next(block_enum, 1, &object2, &fetched); ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); @@ -2416,6 +2415,8 @@ static void test_metadata_gif(void)
if (SUCCEEDED(hr)) { + test_block_reader_enumerator(blockreader); + hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL); ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
Esme Povirk (@madewokherd) commented about dlls/windowscodecs/decoder.c:
+{
- IUnknown **objects;
- HRESULT hr = S_OK;
- UINT count, i;
- if (!enumerator)
return E_INVALIDARG;
- *enumerator = NULL;
- if (FAILED(hr = metadata_block_reader_initialize_metadata(block_reader)))
return hr;
- count = block_reader->metadata_count;
- if (!(objects = calloc(count, sizeof(*objects))))
`objects` is never freed.