Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: windowscodecs/metadata: Add initial implementation of the App1 reader. windowscodecs/metadata: Add registration information for the Exif reader. windowscodecs/metadata: Add registration information for the Gps reader. windowscodecs/metadatahandler: Implement GetStream(). windowscodecs/metadatahandler: Implement GetPersistOptions().
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/metadatahandler.c | 18 +++++++++++++----- dlls/windowscodecs/tests/metadata.c | 13 ------------- 2 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 7618d8cd6aa..d399e31bc9b 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -41,6 +41,7 @@ typedef struct MetadataHandler { const MetadataHandlerVtbl *vtable; MetadataItem *items; DWORD item_count; + DWORD persist_options; CRITICAL_SECTION lock; } MetadataHandler;
@@ -379,6 +380,8 @@ static HRESULT WINAPI MetadataHandler_LoadEx(IWICPersistStream *iface, MetadataHandler_FreeItems(This); This->items = new_items; This->item_count = item_count; + + This->persist_options = dwPersistOptions & WICPersistOptionMask; }
LeaveCriticalSection(&This->lock); @@ -433,9 +436,16 @@ static HRESULT WINAPI metadatahandler_stream_provider_GetStream(IWICStreamProvid
static HRESULT WINAPI metadatahandler_stream_provider_GetPersistOptions(IWICStreamProvider *iface, DWORD *options) { - FIXME("%p, %p stub\n", iface, options); + MetadataHandler *handler = impl_from_IWICStreamProvider(iface);
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, options); + + if (!options) + return E_INVALIDARG; + + *options = handler->persist_options; + + return S_OK; }
static HRESULT WINAPI metadatahandler_stream_provider_GetPreferredVendorGUID(IWICStreamProvider *iface, GUID *guid) @@ -472,7 +482,7 @@ HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID iid, voi
*ppv = NULL;
- This = malloc(sizeof(MetadataHandler)); + This = calloc(1, sizeof(*This)); if (!This) return E_OUTOFMEMORY;
This->IWICMetadataWriter_iface.lpVtbl = &MetadataHandler_Vtbl; @@ -480,8 +490,6 @@ HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID iid, voi This->IWICStreamProvider_iface.lpVtbl = &MetadataHandler_StreamProvider_Vtbl; This->ref = 1; This->vtable = vtable; - This->items = NULL; - This->item_count = 0;
InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MetadataHandler.lock"); diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 238acd7cd65..6fd307b26c7 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -346,14 +346,11 @@ static void load_stream(void *iface_ptr, const char *data, int data_size, DWORD ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
hr = IWICStreamProvider_GetPersistOptions(stream_provider, NULL); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
flags = 123; hr = IWICStreamProvider_GetPersistOptions(stream_provider, &flags); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(!flags, "Unexpected options %#lx.\n", flags);
stream2 = (void *)0xdeadbeef; @@ -374,9 +371,7 @@ static void load_stream(void *iface_ptr, const char *data, int data_size, DWORD
flags = ~persist_options; hr = IWICStreamProvider_GetPersistOptions(stream_provider, &flags); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(flags == persist_options, "Unexpected options %#lx.\n", flags);
if (persist_options & WICPersistOptionNoCacheStream) @@ -1281,7 +1276,6 @@ static void test_ifd_content(IWICMetadataReader *reader) memcpy(IFD_data_swapped, &IFD_data, sizeof(IFD_data)); byte_swap_ifd_data(IFD_data_swapped); load_stream(reader, IFD_data_swapped, sizeof(IFD_data), WICPersistOptionBigEndian); - todo_wine check_persist_options(reader, WICPersistOptionBigEndian); hr = IWICMetadataReader_GetCount(reader, &count); ok(hr == S_OK, "GetCount error %#lx\n", hr); @@ -1760,7 +1754,6 @@ static void test_CreateMetadataReader(void) hr = get_persist_stream(reader, &stream2); todo_wine ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); - todo_wine check_persist_options(reader, WICPersistOptionNoCacheStream);
IWICPersistStream_Release(persist_stream); @@ -2563,7 +2556,6 @@ static void test_metadata_LSD(void)
hr = IWICPersistStream_Load(persist, stream); ok(hr == S_OK, "Load error %#lx\n", hr); - todo_wine check_persist_options(reader, 0);
IWICPersistStream_Release(persist); @@ -2664,7 +2656,6 @@ static void test_metadata_IMD(void)
hr = IWICPersistStream_Load(persist, stream); ok(hr == S_OK, "Load error %#lx\n", hr); - todo_wine check_persist_options(reader, 0);
IWICPersistStream_Release(persist); @@ -2762,7 +2753,6 @@ static void test_metadata_GCE(void)
hr = IWICPersistStream_Load(persist, stream); ok(hr == S_OK, "Load error %#lx\n", hr); - todo_wine check_persist_options(reader, 0);
IWICPersistStream_Release(persist); @@ -2858,7 +2848,6 @@ static void test_metadata_APE(void)
hr = IWICPersistStream_Load(persist, stream); ok(hr == S_OK, "Load error %#lx\n", hr); - todo_wine check_persist_options(reader, 0);
IWICPersistStream_Release(persist); @@ -2965,7 +2954,6 @@ static void test_metadata_GIF_comment(void)
hr = IWICPersistStream_Load(persist, stream); ok(hr == S_OK, "Load error %#lx\n", hr); - todo_wine check_persist_options(reader, 0);
IWICPersistStream_Release(persist); @@ -4220,7 +4208,6 @@ static void test_CreateMetadataWriterFromReader(void) hr = IWICComponentFactory_CreateMetadataReader(factory, &GUID_MetadataFormatChunktEXt, NULL, 0, NULL, &reader); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine check_persist_options(reader, 0);
hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, reader, NULL, &writer);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/metadatahandler.c | 43 ++++++++++++++++++++++++---- dlls/windowscodecs/tests/metadata.c | 40 +++++++++++++------------- 2 files changed, 58 insertions(+), 25 deletions(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index d399e31bc9b..06cc21123e0 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -42,6 +42,7 @@ typedef struct MetadataHandler { MetadataItem *items; DWORD item_count; DWORD persist_options; + IStream *stream; CRITICAL_SECTION lock; } MetadataHandler;
@@ -132,6 +133,8 @@ static ULONG WINAPI MetadataHandler_Release(IWICMetadataWriter *iface)
if (ref == 0) { + if (This->stream) + IStream_Release(This->stream); MetadataHandler_FreeItems(This); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); @@ -375,13 +378,23 @@ static HRESULT WINAPI MetadataHandler_LoadEx(IWICPersistStream *iface, &new_items, &item_count); }
- if (SUCCEEDED(hr)) + if (This->stream) + IStream_Release(This->stream); + This->stream = NULL; + + if (!(dwPersistOptions & WICPersistOptionNoCacheStream)) + { + This->stream = stream; + if (This->stream) + IStream_AddRef(This->stream); + } + This->persist_options = dwPersistOptions & WICPersistOptionMask; + + if (new_items) { MetadataHandler_FreeItems(This); This->items = new_items; This->item_count = item_count; - - This->persist_options = dwPersistOptions & WICPersistOptionMask; }
LeaveCriticalSection(&This->lock); @@ -429,9 +442,29 @@ static ULONG WINAPI metadatahandler_stream_provider_Release(IWICStreamProvider *
static HRESULT WINAPI metadatahandler_stream_provider_GetStream(IWICStreamProvider *iface, IStream **stream) { - FIXME("%p, %p stub\n", iface, stream); + MetadataHandler *handler = impl_from_IWICStreamProvider(iface); + HRESULT hr = S_OK;
- return E_NOTIMPL; + TRACE("%p, %p.\n", iface, stream); + + if (!stream) + return E_INVALIDARG; + + EnterCriticalSection(&handler->lock); + + if (handler->stream) + { + *stream = handler->stream; + IStream_AddRef(*stream); + } + else + { + hr = WINCODEC_ERR_STREAMNOTAVAILABLE; + } + + LeaveCriticalSection(&handler->lock); + + return hr; }
static HRESULT WINAPI metadatahandler_stream_provider_GetPersistOptions(IWICStreamProvider *iface, DWORD *options) diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 6fd307b26c7..f28982ca46b 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -353,9 +353,11 @@ static void load_stream(void *iface_ptr, const char *data, int data_size, DWORD ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!flags, "Unexpected options %#lx.\n", flags);
+ hr = IWICStreamProvider_GetStream(stream_provider, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + stream2 = (void *)0xdeadbeef; hr = IWICStreamProvider_GetStream(stream_provider, &stream2); - todo_wine ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); ok(stream2 == (void *)0xdeadbeef, "Unexpected stream pointer.\n");
@@ -386,9 +388,7 @@ static void load_stream(void *iface_ptr, const char *data, int data_size, DWORD { stream2 = NULL; hr = IWICStreamProvider_GetStream(stream_provider, &stream2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(stream2 == stream, "Unexpected stream pointer.\n"); if (stream2) IStream_Release(stream2); @@ -568,6 +568,7 @@ static void test_metadata_unknown(void) IWICMetadataWriter *writer; IWICPersistStream *persist; ULONG items_returned; + IStream *stream; UINT count;
hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER, @@ -635,11 +636,21 @@ static void test_metadata_unknown(void) hr = IWICMetadataReader_GetCount(reader, &count); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(count == 1, "Unexpected count %u.\n", count); + hr = get_persist_stream(reader, &stream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + IStream_Release(stream); + hr = IWICPersistStream_LoadEx(persist, NULL, NULL, 0); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = get_persist_stream(reader, &stream); + ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); + check_persist_options(reader, 0); + + hr = IWICPersistStream_LoadEx(persist, NULL, NULL, WICPersistOptionNoCacheStream); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_persist_options(reader, WICPersistOptionNoCacheStream); hr = IWICMetadataReader_GetCount(reader, &count); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(count == 1, "Unexpected count %u.\n", count); IWICPersistStream_Release(persist);
@@ -1629,13 +1640,9 @@ static void test_CreateMetadataReader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = get_persist_stream(reader, &stream2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - { - ok(stream == stream2, "Unexpected stream.\n"); - IStream_Release(stream2); - } + ok(stream == stream2, "Unexpected stream.\n"); + IStream_Release(stream2);
hr = IWICMetadataReader_GetMetadataFormat(reader, &format); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -1651,7 +1658,6 @@ static void test_CreateMetadataReader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = get_persist_stream(reader, &stream2); - todo_wine ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr);
hr = IWICMetadataReader_GetMetadataFormat(reader, &format); @@ -1726,7 +1732,6 @@ static void test_CreateMetadataReader(void) ok(count == 1, "Unexpected count %u.\n", count);
hr = get_persist_stream(reader, &stream2); - todo_wine ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr);
hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist_stream); @@ -1737,13 +1742,9 @@ static void test_CreateMetadataReader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = get_persist_stream(reader, &stream2); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (SUCCEEDED(hr)) - { - ok(stream == stream2, "Unexpected stream.\n"); - IStream_Release(stream2); - } + ok(stream == stream2, "Unexpected stream.\n"); + IStream_Release(stream2);
/* Going from caching to no caching. */ hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL); @@ -1752,7 +1753,6 @@ static void test_CreateMetadataReader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = get_persist_stream(reader, &stream2); - todo_wine ok(hr == WINCODEC_ERR_STREAMNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); check_persist_options(reader, WICPersistOptionNoCacheStream);
@@ -4065,7 +4065,7 @@ static void test_metadata_App1(void)
hr = get_persist_stream(ifd_reader, &stream2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!!stream2 && stream2 != app1_stream, "Unexpected stream %p.\n", stream2); + ok(!!stream2 && app1_stream != stream2, "Unexpected stream.\n"); IStream_Release(stream2);
hr = IWICMetadataReader_GetCount(ifd_reader, &count);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/clsfactory.c | 1 + dlls/windowscodecs/metadatahandler.c | 12 ++++++++++++ dlls/windowscodecs/regsvr.c | 18 ++++++++++++++++++ dlls/windowscodecs/tests/metadata.c | 4 ++-- dlls/windowscodecs/wincodecs_private.h | 1 + dlls/windowscodecs/windowscodecs_wincodec.idl | 7 +++++++ 6 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c index 87b77c9c089..bbc21ce154b 100644 --- a/dlls/windowscodecs/clsfactory.c +++ b/dlls/windowscodecs/clsfactory.c @@ -63,6 +63,7 @@ static const classinfo wic_classes[] = { {&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance}, {&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance}, {&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance}, + {&CLSID_WICGpsMetadataReader, GpsMetadataReader_CreateInstance}, {&CLSID_WICPngChrmMetadataReader, PngChrmReader_CreateInstance}, {&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance}, {&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance}, diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 06cc21123e0..d92722fdf41 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -1215,3 +1215,15 @@ HRESULT IfdMetadataReader_CreateInstance(REFIID iid, void **ppv) { return MetadataReader_Create(&IfdMetadataReader_Vtbl, iid, ppv); } + +static const MetadataHandlerVtbl GpsMetadataReader_Vtbl = +{ + 0, + &CLSID_WICGpsMetadataReader, + LoadIfdMetadata +}; + +HRESULT GpsMetadataReader_CreateInstance(REFIID iid, void **ppv) +{ + return MetadataReader_Create(&GpsMetadataReader_Vtbl, iid, ppv); +} diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c index c74fcecb3a2..b86e0d42396 100644 --- a/dlls/windowscodecs/regsvr.c +++ b/dlls/windowscodecs/regsvr.c @@ -1575,6 +1575,14 @@ static const struct reader_containers ifd_containers[] = { { NULL } /* list terminator */ };
+static const struct reader_containers gps_containers[] = { + { + &GUID_MetadataFormatIfd, + ifd_metadata_pattern + }, + { NULL } /* list terminator */ +}; + static const BYTE tEXt[] = "tEXt";
static const struct metadata_pattern pngtext_metadata_pattern[] = { @@ -1745,6 +1753,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = { 1, 1, 0, ifd_containers }, + { &CLSID_WICGpsMetadataReader, + "The Wine Project", + "Gps Reader", + "1.0.0.0", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_MetadataFormatGps, + 1, 1, 0, + gps_containers + }, { &CLSID_WICPngChrmMetadataReader, "The Wine Project", "Chunk cHRM Reader", diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index f28982ca46b..0e77891edba 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -1490,8 +1490,7 @@ static void test_metadata_Gps(void)
hr = CoCreateInstance(&CLSID_WICGpsMetadataReader, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataReader, (void **)&reader); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) return; + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_interface(reader, &IID_IWICMetadataReader, TRUE); check_interface(reader, &IID_IPersist, TRUE); @@ -1518,6 +1517,7 @@ static void test_metadata_Gps(void)
hr = CoCreateInstance(&CLSID_WICGpsMetadataWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataWriter, (void **)&writer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (FAILED(hr)) return;
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 9da717fc345..e4a56b5ec93 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -217,6 +217,7 @@ extern HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID i
extern HRESULT UnknownMetadataReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT IfdMetadataReader_CreateInstance(REFIID iid, void **ppv); +extern HRESULT GpsMetadataReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv); diff --git a/dlls/windowscodecs/windowscodecs_wincodec.idl b/dlls/windowscodecs/windowscodecs_wincodec.idl index f47684890c1..2ffc883fc2e 100644 --- a/dlls/windowscodecs/windowscodecs_wincodec.idl +++ b/dlls/windowscodecs/windowscodecs_wincodec.idl @@ -160,6 +160,13 @@ coclass WICUnknownMetadataReader { interface IWICMetadataReader; } ] coclass WICIfdMetadataReader { interface IWICMetadataReader; }
+[ + helpstring("WIC Gps Metadata Reader"), + threading(both), + uuid(3697790b-223b-484e-9925-c4869218f17a) +] +coclass WICGpsMetadataReader { interface IWICMetadataReader; } + [ helpstring("WIC Png cHRM Metadata Reader"), threading(both),
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/clsfactory.c | 1 + dlls/windowscodecs/gifformat.c | 8 +- dlls/windowscodecs/imgfactory.c | 38 +++- dlls/windowscodecs/metadatahandler.c | 204 +++++++++++++++++- dlls/windowscodecs/regsvr.c | 18 ++ dlls/windowscodecs/tests/metadata.c | 44 +++- dlls/windowscodecs/wincodecs_private.h | 4 + dlls/windowscodecs/windowscodecs_wincodec.idl | 7 + 8 files changed, 298 insertions(+), 26 deletions(-)
diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c index 1deb6d722d5..90309314d6d 100644 --- a/dlls/windowscodecs/clsfactory.c +++ b/dlls/windowscodecs/clsfactory.c @@ -65,6 +65,7 @@ static const classinfo wic_classes[] = { {&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance}, {&CLSID_WICGpsMetadataReader, GpsMetadataReader_CreateInstance}, {&CLSID_WICExifMetadataReader, ExifMetadataReader_CreateInstance}, + {&CLSID_WICApp1MetadataReader, App1MetadataReader_CreateInstance}, {&CLSID_WICPngChrmMetadataReader, PngChrmReader_CreateInstance}, {&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance}, {&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance}, diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c index 0aa2d9420dd..0b32f0ddfa7 100644 --- a/dlls/windowscodecs/gifformat.c +++ b/dlls/windowscodecs/gifformat.c @@ -533,7 +533,7 @@ static IStream *create_stream(const void *data, int data_size) return FAILED(hr) ? NULL : stream; }
-static HRESULT create_metadata_reader(const void *data, int data_size, +static HRESULT create_gif_metadata_reader(const void *data, int data_size, class_constructor constructor, IWICMetadataReader **reader) { @@ -998,7 +998,7 @@ static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockRea data_size = ext->ByteCount; }
- return create_metadata_reader(data, data_size, constructor, reader); + return create_gif_metadata_reader(data, data_size, constructor, reader); }
static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, @@ -1354,7 +1354,7 @@ static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader if (!reader) return E_INVALIDARG;
if (index == 0) - return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data), + return create_gif_metadata_reader(This->LSD_data, sizeof(This->LSD_data), LSDReader_CreateInstance, reader);
for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) @@ -1370,7 +1370,7 @@ static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader else constructor = UnknownMetadataReader_CreateInstance;
- return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, + return create_gif_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, This->gif->Extensions.ExtensionBlocks[i].ByteCount, constructor, reader); } diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index 2f5617cedc1..7c9fe6a8920 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1328,7 +1328,8 @@ static enum iterator_result create_metadata_reader_iterator(IUnknown *item, IWICPersistStream *persist_stream = NULL; IWICMetadataReaderInfo *readerinfo; IWICMetadataReader *reader = NULL; - LARGE_INTEGER zero = {{0}}; + LARGE_INTEGER move = {{0}}; + ULARGE_INTEGER pos; HRESULT hr; GUID guid;
@@ -1361,8 +1362,13 @@ static enum iterator_result create_metadata_reader_iterator(IUnknown *item,
if (context->stream) { + BOOL restore = FALSE; + if (SUCCEEDED(hr)) - hr = IStream_Seek(context->stream, zero, STREAM_SEEK_SET, NULL); + { + move.QuadPart = 0; + restore = SUCCEEDED(hr = IStream_Seek(context->stream, move, STREAM_SEEK_CUR, &pos)); + }
if (SUCCEEDED(hr)) hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist_stream); @@ -1371,6 +1377,12 @@ static enum iterator_result create_metadata_reader_iterator(IUnknown *item, hr = IWICPersistStream_LoadEx(persist_stream, context->stream, context->vendor, context->options & WICPersistOptionMask);
+ if (restore) + { + memcpy(&move, &pos, sizeof(pos)); + hr = IStream_Seek(context->stream, move, STREAM_SEEK_SET, NULL); + } + if (persist_stream) IWICPersistStream_Release(persist_stream); } @@ -1444,18 +1456,12 @@ static HRESULT create_unknown_metadata_reader(IStream *stream, DWORD options, IW return hr; }
-static HRESULT WINAPI ComponentFactory_CreateMetadataReader(IWICComponentFactory *iface, - REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader) +HRESULT create_metadata_reader(REFGUID format, const GUID *vendor, DWORD options, IStream *stream, + IWICMetadataReader **reader) { struct iterator_context context = { 0 }; HRESULT hr;
- TRACE("%p,%s,%s,%lx,%p,%p\n", iface, debugstr_guid(format), debugstr_guid(vendor), - options, stream, reader); - - if (!format || !reader) - return E_INVALIDARG; - context.format = format; context.vendor = vendor; context.options = options; @@ -1479,6 +1485,18 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataReader(IWICComponentFactory return *reader ? S_OK : WINCODEC_ERR_COMPONENTNOTFOUND; }
+static HRESULT WINAPI ComponentFactory_CreateMetadataReader(IWICComponentFactory *iface, + REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader) +{ + TRACE("%p,%s,%s,%lx,%p,%p\n", iface, debugstr_guid(format), debugstr_guid(vendor), + options, stream, reader); + + if (!format || !reader) + return E_INVALIDARG; + + return create_metadata_reader(format, vendor, options, stream, reader); +} + static HRESULT WINAPI ComponentFactory_CreateMetadataReaderFromContainer(IWICComponentFactory *iface, REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader) { diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 115e68afe3f..7b1588d9125 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -807,6 +807,12 @@ struct IFD_entry #define IFD_DOUBLE 12 #define IFD_IFD 13
+enum ifd_tags +{ + IFD_EXIF_TAG = 0x8769, + IFD_GPS_TAG = 0x8825, +}; + static int tag_to_vt(SHORT tag) { static const int tag2vt[] = @@ -829,13 +835,38 @@ static int tag_to_vt(SHORT tag) return (tag > 0 && tag <= 13) ? tag2vt[tag] : VT_BLOB; }
-static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, - MetadataItem *item, BOOL native_byte_order) +static HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wrapper) { + ULARGE_INTEGER start, maxsize = {{~0UL}}; + IWICStream *wic_stream = NULL; + HRESULT hr; + + *wrapper = NULL; + + start.QuadPart = offset; + + hr = StreamImpl_Create(&wic_stream); + if (SUCCEEDED(hr)) + hr = IWICStream_InitializeFromIStreamRegion(wic_stream, input, start, maxsize); + + if (SUCCEEDED(hr)) + hr = IWICStream_QueryInterface(wic_stream, &IID_IStream, (void **)wrapper); + if (wic_stream) + IWICStream_Release(wic_stream); + + return hr; +} + +static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, const struct IFD_entry *entry, + MetadataItem *item, BOOL resolve_pointer_tags) +{ + BOOL native_byte_order = !(options & WICPersistOptionBigEndian); ULONG count, value, i, bytesread; + IWICMetadataReader *sub_reader; + IStream *sub_stream; SHORT type; LARGE_INTEGER pos; - HRESULT hr; + HRESULT hr = S_OK;
item->schema.vt = VT_EMPTY; item->id.vt = VT_UI2; @@ -1105,11 +1136,47 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, FIXME("loading field of type %d, count %lu is not implemented\n", type, count); break; } - return S_OK; + + switch (item->id.uiVal) + { + case IFD_EXIF_TAG: + case IFD_GPS_TAG: + + if (!resolve_pointer_tags) + break; + + if (item->value.vt != VT_UI4) + break; + + hr = create_stream_wrapper(input, 0, &sub_stream); + + pos.QuadPart = item->value.ulVal; + if (SUCCEEDED(hr)) + hr = IStream_Seek(sub_stream, pos, STREAM_SEEK_SET, NULL); + + if (SUCCEEDED(hr)) + hr = create_metadata_reader(item->id.uiVal == IFD_EXIF_TAG ? &GUID_MetadataFormatExif : &GUID_MetadataFormatGps, + vendor, options | WICMetadataCreationFailUnknown, sub_stream, &sub_reader); + + if (SUCCEEDED(hr)) + { + item->value.vt = VT_UNKNOWN; + item->value.punkVal = (IUnknown *)sub_reader; + } + + if (sub_stream) + IStream_Release(sub_stream); + + break; + default: + break; + } + + return hr; }
-static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor, - DWORD persist_options, MetadataItem **items, DWORD *item_count) +static HRESULT load_ifd_metadata_internal(IStream *input, const GUID *vendor, + DWORD persist_options, BOOL resolve_pointer_tags, MetadataItem **items, DWORD *item_count) { HRESULT hr; MetadataItem *result; @@ -1188,7 +1255,7 @@ static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor,
for (i = 0; i < count; i++) { - hr = load_IFD_entry(input, &entry[i], &result[i], native_byte_order); + hr = load_IFD_entry(input, vendor, persist_options, &entry[i], &result[i], resolve_pointer_tags); if (FAILED(hr)) { free(entry); @@ -1205,6 +1272,113 @@ static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor, return S_OK; }
+static HRESULT LoadIfdMetadata(IStream *input, const GUID *vendor, + DWORD options, MetadataItem **items, DWORD *item_count) +{ + TRACE("%p, %#lx.\n", input, options); + return load_ifd_metadata_internal(input, vendor, options, TRUE, items, item_count); +} + +static HRESULT LoadExifMetadata(IStream *input, const GUID *vendor, + DWORD options, MetadataItem **items, DWORD *item_count) +{ + TRACE("%p, %#lx.\n", input, options); + + return load_ifd_metadata_internal(input, vendor, options, FALSE, items, item_count); +} + +static HRESULT LoadGpsMetadata(IStream *input, const GUID *vendor, + DWORD options, MetadataItem **items, DWORD *item_count) +{ + TRACE("%p, %#lx.\n", input, options); + + return load_ifd_metadata_internal(input, vendor, options, FALSE, items, item_count); +} + +static HRESULT LoadApp1Metadata(IStream *input, const GUID *vendor, DWORD options, MetadataItem **items, DWORD *item_count) +{ + static const char exif_header[] = {'E','x','i','f',0,0}; + IWICMetadataReader *ifd_reader; + BOOL native_byte_order; + LARGE_INTEGER move; + +#include "pshpack2.h" + struct app1_header + { + BYTE exif_header[6]; + BYTE bom[2]; + USHORT marker; + ULONG ifd0_offset; + } header; +#include "poppack.h" + + IStream *ifd_stream; + ULONG length; + HRESULT hr; + + if (FAILED(hr = IStream_Read(input, &header, sizeof(header), &length))) + return hr; + if (length != sizeof(header)) + return WINCODEC_ERR_BADMETADATAHEADER; + + if (memcmp(header.exif_header, exif_header, sizeof(exif_header))) + return WINCODEC_ERR_BADMETADATAHEADER; + + options &= ~(WICPersistOptionLittleEndian | WICPersistOptionBigEndian); + options |= WICMetadataCreationFailUnknown; + if (!memcmp(header.bom, "II", 2)) + options |= WICPersistOptionLittleEndian; + else if (!memcmp(header.bom, "MM", 2)) + options |= WICPersistOptionBigEndian; + else + { + WARN("Unrecognized bom marker %#x%#x.\n", header.bom[0], header.bom[1]); + return WINCODEC_ERR_BADMETADATAHEADER; + } + native_byte_order = !(options & WICPersistOptionBigEndian); + + SWAP_USHORT(header.marker); + SWAP_ULONG(header.ifd0_offset); + + if (header.marker != 0x002a) + { + WARN("Unrecognized marker %#x.\n", header.marker); + return WINCODEC_ERR_BADMETADATAHEADER; + } + + if (FAILED(hr = create_stream_wrapper(input, sizeof(exif_header), &ifd_stream))) + return hr; + move.QuadPart = header.ifd0_offset; + if (FAILED(hr = IStream_Seek(ifd_stream, move, STREAM_SEEK_SET, NULL))) + { + IStream_Release(ifd_stream); + return hr; + } + + hr = create_metadata_reader(&GUID_MetadataFormatIfd, vendor, options, ifd_stream, &ifd_reader); + IStream_Release(ifd_stream); + + if (FAILED(hr)) + { + WARN("Failed to create IFD0 reader.\n"); + return hr; + } + + if (!(*items = calloc(1, sizeof(**items)))) + { + IWICMetadataReader_Release(ifd_reader); + return E_OUTOFMEMORY; + } + + (*items)[0].id.vt = VT_UI2; + (*items)[0].id.uiVal = 0; + (*items)[0].value.vt = VT_UNKNOWN; + (*items)[0].value.punkVal = (IUnknown *)ifd_reader; + *item_count = 1; + + return S_OK; +} + static const MetadataHandlerVtbl IfdMetadataReader_Vtbl = { 0, &CLSID_WICIfdMetadataReader, @@ -1220,7 +1394,7 @@ static const MetadataHandlerVtbl GpsMetadataReader_Vtbl = { 0, &CLSID_WICGpsMetadataReader, - LoadIfdMetadata + LoadGpsMetadata };
HRESULT GpsMetadataReader_CreateInstance(REFIID iid, void **ppv) @@ -1232,10 +1406,22 @@ static const MetadataHandlerVtbl ExifMetadataReader_Vtbl = { 0, &CLSID_WICExifMetadataReader, - LoadIfdMetadata + LoadExifMetadata };
HRESULT ExifMetadataReader_CreateInstance(REFIID iid, void **ppv) { return MetadataReader_Create(&ExifMetadataReader_Vtbl, iid, ppv); } + +static const MetadataHandlerVtbl App1MetadataReader_Vtbl = +{ + 0, + &CLSID_WICApp1MetadataReader, + LoadApp1Metadata +}; + +HRESULT App1MetadataReader_CreateInstance(REFIID iid, void **ppv) +{ + return MetadataReader_Create(&App1MetadataReader_Vtbl, iid, ppv); +} diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c index d8886c3c888..f9ba2b083eb 100644 --- a/dlls/windowscodecs/regsvr.c +++ b/dlls/windowscodecs/regsvr.c @@ -1591,6 +1591,14 @@ static const struct reader_containers exif_containers[] = { { NULL } /* list terminator */ };
+static const struct reader_containers app1_containers[] = { + { + &GUID_ContainerFormatJpeg, + ifd_metadata_pattern + }, + { NULL } /* list terminator */ +}; + static const BYTE tEXt[] = "tEXt";
static const struct metadata_pattern pngtext_metadata_pattern[] = { @@ -1781,6 +1789,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = { 1, 1, 0, exif_containers }, + { &CLSID_WICApp1MetadataReader, + "The Wine Project", + "App1 Reader", + "1.0.0.0", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_MetadataFormatApp1, + 1, 1, 0, + app1_containers + }, { &CLSID_WICPngChrmMetadataReader, "The Wine Project", "Chunk cHRM Reader", diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 240ea234227..b458dede3c8 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -1369,8 +1369,28 @@ static void test_ifd_content(IWICMetadataReader *reader)
static void test_metadata_Ifd(void) { +#include "pshpack2.h" + static const struct ifd0_data + { + USHORT count; + struct IFD_entry ifd0[2]; + ULONG next_IFD; + } + ifd0_data = + { + 2, + { + /* Exif IFD pointer */ + { 0x8769, IFD_LONG, 1, 0 }, + /* GPS IFD pointer */ + { 0x8825, IFD_LONG, 1, 0 }, + }, + }; +#include "poppack.h" + IWICMetadataReader *reader; IWICMetadataWriter *writer; + PROPVARIANT id, value; GUID format; UINT count; HRESULT hr; @@ -1404,6 +1424,26 @@ static void test_metadata_Ifd(void) hr = IWICMetadataReader_GetMetadataFormat(reader, NULL); ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
+ /* IFD contains pointer tags. */ + load_stream(reader, (const char *)&ifd0_data, sizeof(ifd0_data), 0); + hr = IWICMetadataReader_GetCount(reader, &count); + ok(hr == S_OK, "GetCount error %#lx\n", hr); + ok(count == 2, "unexpected count %u\n", count); + + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "Unexpected value type %u.\n", value.vt); + PropVariantClear(&value); + + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "Unexpected value type %u.\n", value.vt); + PropVariantClear(&value); + IWICMetadataReader_Release(reader);
hr = CoCreateInstance(&CLSID_WICIfdMetadataWriter, NULL, CLSCTX_INPROC_SERVER, @@ -1738,7 +1778,6 @@ static void test_CreateMetadataReader(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = IWICPersistStream_LoadEx(persist_stream, stream, NULL, 0); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = get_persist_stream(reader, &stream2); @@ -4008,9 +4047,7 @@ static void test_metadata_App1(void)
hr = CoCreateInstance(&CLSID_WICApp1MetadataReader, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataReader, (void **)&reader); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) return;
check_interface(reader, &IID_IWICMetadataReader, TRUE); check_interface(reader, &IID_IPersist, TRUE); @@ -4175,6 +4212,7 @@ static void test_metadata_App1(void)
hr = CoCreateInstance(&CLSID_WICApp1MetadataWriter, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataWriter, (void **)&writer); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (FAILED(hr)) return;
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 541ea13923e..e714163b660 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -219,6 +219,7 @@ extern HRESULT UnknownMetadataReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT IfdMetadataReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT GpsMetadataReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT ExifMetadataReader_CreateInstance(REFIID iid, void **ppv); +extern HRESULT App1MetadataReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv); @@ -317,6 +318,9 @@ HRESULT CDECL decoder_get_color_context(struct decoder* This, UINT frame, UINT n BYTE **data, DWORD *datasize); void CDECL decoder_destroy(struct decoder *This);
+HRESULT create_metadata_reader(REFGUID format, const GUID *vendor, DWORD options, IStream *stream, + IWICMetadataReader **reader); + struct encoder_funcs;
/* sync with encoder_option_properties */ diff --git a/dlls/windowscodecs/windowscodecs_wincodec.idl b/dlls/windowscodecs/windowscodecs_wincodec.idl index 1e119c132f2..122f6d0e007 100644 --- a/dlls/windowscodecs/windowscodecs_wincodec.idl +++ b/dlls/windowscodecs/windowscodecs_wincodec.idl @@ -174,6 +174,13 @@ coclass WICGpsMetadataReader { interface IWICMetadataReader; } ] coclass WICExifMetadataReader { interface IWICMetadataReader; }
+[ + helpstring("WIC App1 Metadata Reader"), + threading(both), + uuid(dde33513-774e-4bcd-ae79-02f4adfe62fc) +] +coclass WICApp1MetadataReader { interface IWICMetadataReader; } + [ helpstring("WIC Png cHRM Metadata Reader"), threading(both),
Thank you, pushed both changes.
This merge request was approved by Esme Povirk.