Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
-- v2: windowscodecs/metadata: Implement SetValue(). windowscodecs/tests: Add an item enumeration test for the App1 reader. windowscodecs/metadata: Add initial implementation of CreateMetadataWriterFromReader(). windowscodecs: Filter options in CreateMetadataWriter(). windowscodecs/metadata: Add a stub for WICApp1MetadataWriter. windowscodecs/metadata: Create nested writer instances when loading IFD data. windowscodecs: Implement CreateMetadataWriter().
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/imgfactory.c | 84 ++++++++++++++++++++++++++++- dlls/windowscodecs/tests/metadata.c | 7 +-- 2 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index 7c9fe6a8920..3813843544f 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1399,6 +1399,50 @@ static enum iterator_result create_metadata_reader_iterator(IUnknown *item, return ITER_SKIP; }
+static enum iterator_result create_metadata_writer_iterator(IUnknown *item, + struct iterator_context *context) +{ + IWICMetadataWriterInfo *writerinfo; + IWICMetadataWriter *writer = NULL; + HRESULT hr; + GUID guid; + + if (FAILED(IUnknown_QueryInterface(item, &IID_IWICMetadataWriterInfo, (void **)&writerinfo))) + return ITER_SKIP; + + if (context->vendor) + { + hr = IWICMetadataWriterInfo_GetVendorGUID(writerinfo, &guid); + + if (FAILED(hr) || !IsEqualIID(context->vendor, &guid)) + { + IWICMetadataWriterInfo_Release(writerinfo); + return ITER_SKIP; + } + } + + hr = IWICMetadataWriterInfo_GetMetadataFormat(writerinfo, &guid); + + if (FAILED(hr) || !IsEqualIID(context->format, &guid)) + { + IWICMetadataWriterInfo_Release(writerinfo); + return ITER_SKIP; + } + + if (SUCCEEDED(hr)) + hr = IWICMetadataWriterInfo_CreateInstance(writerinfo, &writer); + + IWICMetadataWriterInfo_Release(writerinfo); + + if (SUCCEEDED(hr)) + { + *context->result = writer; + return ITER_DONE; + } + + return ITER_SKIP; +} + static HRESULT foreach_component(DWORD mask, iterator_func func, struct iterator_context *context) { enum iterator_result ret; @@ -1532,11 +1576,47 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataReaderFromContainer(IWICCom return *reader ? S_OK : WINCODEC_ERR_COMPONENTNOTFOUND; }
+static HRESULT create_metadata_writer(REFGUID format, const GUID *vendor, DWORD options, + IWICMetadataWriter **writer) +{ + struct iterator_context context = { 0 }; + IWICMetadataWriter *object = NULL; + HRESULT hr; + + context.format = format; + context.vendor = vendor; + context.options = options; + context.result = (void **)&object; + + hr = foreach_component(WICMetadataWriter, create_metadata_writer_iterator, &context); + + if (FAILED(hr) && vendor) + { + context.vendor = NULL; + hr = foreach_component(WICMetadataWriter, create_metadata_writer_iterator, &context); + } + + if (FAILED(hr)) + WARN("Failed to create a metadata writer instance, hr %#lx.\n", hr); + + if (!object && !(options & WICMetadataCreationFailUnknown)) + hr = UnknownMetadataWriter_CreateInstance(&IID_IWICMetadataWriter, (void **)&object); + + if (SUCCEEDED(hr)) + *writer = object; + + return object ? S_OK : WINCODEC_ERR_COMPONENTNOTFOUND; +} + static HRESULT WINAPI ComponentFactory_CreateMetadataWriter(IWICComponentFactory *iface, REFGUID format, const GUID *vendor, DWORD options, IWICMetadataWriter **writer) { - FIXME("%p,%s,%s,%lx,%p: stub\n", iface, debugstr_guid(format), debugstr_guid(vendor), options, writer); - return E_NOTIMPL; + TRACE("%p,%s,%s,%lx,%p\n", iface, debugstr_guid(format), debugstr_guid(vendor), options, writer); + + if (!format || !writer) + return E_INVALIDARG; + + return create_metadata_writer(format, vendor, options, writer); }
static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICComponentFactory *iface, diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 1ff564d2e80..3141eb412c7 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4448,13 +4448,7 @@ static void test_CreateMetadataWriter(void) }
hr = IWICComponentFactory_CreateMetadataWriter(factory, &GUID_MetadataFormatChunktEXt, NULL, 0, &writer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) - { - IWICComponentFactory_Release(factory); - return; - } check_persist_options(writer, 0);
hr = IWICMetadataWriter_QueryInterface(writer, &IID_IWICStreamProvider, (void **)&stream_provider); @@ -4469,6 +4463,7 @@ static void test_CreateMetadataWriter(void)
hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "Unexpected format %s.\n", wine_dbgstr_guid(&format));
IWICMetadataWriter_Release(writer);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/imgfactory.c | 2 +- dlls/windowscodecs/metadatahandler.c | 35 +++++++++++++++++++++----- dlls/windowscodecs/tests/metadata.c | 7 ++++++ dlls/windowscodecs/wincodecs_private.h | 2 ++ 4 files changed, 39 insertions(+), 7 deletions(-)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index 3813843544f..c941344f1aa 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1576,7 +1576,7 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataReaderFromContainer(IWICCom return *reader ? S_OK : WINCODEC_ERR_COMPONENTNOTFOUND; }
-static HRESULT create_metadata_writer(REFGUID format, const GUID *vendor, DWORD options, +HRESULT create_metadata_writer(REFGUID format, const GUID *vendor, DWORD options, IWICMetadataWriter **writer) { struct iterator_context context = { 0 }; diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 469fdf9b8ca..9b6b22d447a 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -871,11 +871,10 @@ static HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wra }
static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, const struct IFD_entry *entry, - MetadataItem *item, BOOL resolve_pointer_tags) + MetadataItem *item, bool resolve_pointer_tags, bool is_writer) { BOOL native_byte_order = !(options & WICPersistOptionBigEndian); ULONG count, value, i, bytesread; - IWICMetadataReader *sub_reader; IStream *sub_stream; SHORT type; LARGE_INTEGER pos; @@ -1154,6 +1153,9 @@ static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, { case IFD_EXIF_TAG: case IFD_GPS_TAG: + { + IWICPersistStream *persist_stream = NULL; + IWICMetadataReader *sub_reader = NULL;
if (!resolve_pointer_tags) break; @@ -1168,19 +1170,40 @@ static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, 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); + { + const GUID *format = item->id.uiVal == IFD_EXIF_TAG ? &GUID_MetadataFormatExif : &GUID_MetadataFormatGps; + + if (is_writer) + hr = create_metadata_writer(format, vendor, options | WICMetadataCreationFailUnknown, + (IWICMetadataWriter **)&sub_reader); + else + hr = create_metadata_reader(format, vendor, options | WICMetadataCreationFailUnknown, + NULL, &sub_reader); + } + + if (SUCCEEDED(hr)) + hr = IWICMetadataReader_QueryInterface(sub_reader, &IID_IWICPersistStream, (void **)&persist_stream); + + if (SUCCEEDED(hr)) + hr = IWICPersistStream_LoadEx(persist_stream, sub_stream, vendor, options); + + if (persist_stream) + IWICPersistStream_Release(persist_stream);
if (SUCCEEDED(hr)) { item->value.vt = VT_UNKNOWN; item->value.punkVal = (IUnknown *)sub_reader; + IUnknown_AddRef(item->value.punkVal); }
if (sub_stream) IStream_Release(sub_stream); + if (sub_reader) + IWICMetadataReader_Release(sub_reader);
break; + } default: break; } @@ -1189,7 +1212,7 @@ static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, }
static HRESULT load_ifd_metadata_internal(IStream *input, const GUID *vendor, - DWORD persist_options, bool resolve_pointer_tags, bool writer, MetadataItem **items, DWORD *item_count) + DWORD persist_options, bool resolve_pointer_tags, bool is_writer, MetadataItem **items, DWORD *item_count) { HRESULT hr; MetadataItem *result; @@ -1268,7 +1291,7 @@ static HRESULT load_ifd_metadata_internal(IStream *input, const GUID *vendor,
for (i = 0; i < count; i++) { - hr = load_IFD_entry(input, vendor, persist_options, &entry[i], &result[i], resolve_pointer_tags); + hr = load_IFD_entry(input, vendor, persist_options, &entry[i], &result[i], resolve_pointer_tags, is_writer); if (FAILED(hr)) { free(entry); diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 3141eb412c7..736923b8146 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4485,12 +4485,19 @@ static void test_CreateMetadataWriter(void) hr = IWICComponentFactory_CreateMetadataWriter(factory, &GUID_MetadataFormatApp1, NULL, 0, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); check_persist_options(writer, 0); + hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(IsEqualGUID(&format, &GUID_MetadataFormatApp1), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); IWICMetadataWriter_Release(writer);
/* Ifd */ hr = IWICComponentFactory_CreateMetadataWriter(factory, &GUID_MetadataFormatIfd, NULL, 0, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); check_persist_options(writer, 0); + hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); IWICMetadataWriter_Release(writer);
IWICComponentFactory_Release(factory); diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index f23ec9a85ee..028c167687d 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -326,6 +326,8 @@ void CDECL decoder_destroy(struct decoder *This);
HRESULT create_metadata_reader(REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader); +HRESULT create_metadata_writer(REFGUID format, const GUID *vendor, DWORD options, + IWICMetadataWriter **writer);
struct encoder_funcs;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/clsfactory.c | 1 + dlls/windowscodecs/metadatahandler.c | 91 ++++++++++++++----- dlls/windowscodecs/regsvr.c | 9 ++ dlls/windowscodecs/tests/metadata.c | 3 - dlls/windowscodecs/wincodecs_private.h | 1 + dlls/windowscodecs/windowscodecs_wincodec.idl | 7 ++ 6 files changed, 86 insertions(+), 26 deletions(-)
diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c index 5e8912db26a..a306d4fc7d6 100644 --- a/dlls/windowscodecs/clsfactory.c +++ b/dlls/windowscodecs/clsfactory.c @@ -70,6 +70,7 @@ static const classinfo wic_classes[] = { {&CLSID_WICExifMetadataReader, ExifMetadataReader_CreateInstance}, {&CLSID_WICExifMetadataWriter, ExifMetadataWriter_CreateInstance}, {&CLSID_WICApp1MetadataReader, App1MetadataReader_CreateInstance}, + {&CLSID_WICApp1MetadataWriter, App1MetadataWriter_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 9b6b22d447a..7e00f678e4e 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -870,6 +870,41 @@ static HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wra return hr; }
+static HRESULT create_metadata_handler(IStream *stream, const GUID *format, const GUID *vendor, + DWORD options, bool is_writer, IWICMetadataReader **handler) +{ + IWICPersistStream *persist_stream = NULL; + IWICMetadataReader *reader = NULL; + HRESULT hr; + + if (is_writer) + hr = create_metadata_writer(format, vendor, options | WICMetadataCreationFailUnknown, + (IWICMetadataWriter **)&reader); + else + hr = create_metadata_reader(format, vendor, options | WICMetadataCreationFailUnknown, + NULL, &reader); + + if (SUCCEEDED(hr)) + hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist_stream); + + if (SUCCEEDED(hr)) + hr = IWICPersistStream_LoadEx(persist_stream, stream, vendor, options); + + if (persist_stream) + IWICPersistStream_Release(persist_stream); + + if (SUCCEEDED(hr)) + { + *handler = reader; + IWICMetadataReader_AddRef(*handler); + } + + if (reader) + IWICMetadataReader_Release(reader); + + 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 is_writer) { @@ -1154,7 +1189,6 @@ static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, case IFD_EXIF_TAG: case IFD_GPS_TAG: { - IWICPersistStream *persist_stream = NULL; IWICMetadataReader *sub_reader = NULL;
if (!resolve_pointer_tags) @@ -1173,34 +1207,18 @@ static HRESULT load_IFD_entry(IStream *input, const GUID *vendor, DWORD options, { const GUID *format = item->id.uiVal == IFD_EXIF_TAG ? &GUID_MetadataFormatExif : &GUID_MetadataFormatGps;
- if (is_writer) - hr = create_metadata_writer(format, vendor, options | WICMetadataCreationFailUnknown, - (IWICMetadataWriter **)&sub_reader); - else - hr = create_metadata_reader(format, vendor, options | WICMetadataCreationFailUnknown, - NULL, &sub_reader); + hr = create_metadata_handler(sub_stream, format, vendor, options | WICMetadataCreationFailUnknown, + is_writer, &sub_reader); }
- if (SUCCEEDED(hr)) - hr = IWICMetadataReader_QueryInterface(sub_reader, &IID_IWICPersistStream, (void **)&persist_stream); - - if (SUCCEEDED(hr)) - hr = IWICPersistStream_LoadEx(persist_stream, sub_stream, vendor, options); - - if (persist_stream) - IWICPersistStream_Release(persist_stream); - if (SUCCEEDED(hr)) { item->value.vt = VT_UNKNOWN; item->value.punkVal = (IUnknown *)sub_reader; - IUnknown_AddRef(item->value.punkVal); }
if (sub_stream) IStream_Release(sub_stream); - if (sub_reader) - IWICMetadataReader_Release(sub_reader);
break; } @@ -1354,10 +1372,11 @@ static HRESULT LoadGpsMetadataWriter(IStream *input, const GUID *vendor, return load_ifd_metadata_internal(input, vendor, options, false, true, items, item_count); }
-static HRESULT LoadApp1Metadata(IStream *input, const GUID *vendor, DWORD options, MetadataItem **items, DWORD *item_count) +static HRESULT load_app1_metadata_internal(IStream *input, const GUID *vendor, DWORD options, + bool is_writer, MetadataItem **items, DWORD *item_count) { static const char exif_header[] = {'E','x','i','f',0,0}; - IWICMetadataReader *ifd_reader; + IWICMetadataReader *ifd_reader = NULL; BOOL native_byte_order; LARGE_INTEGER move;
@@ -1414,7 +1433,9 @@ static HRESULT LoadApp1Metadata(IStream *input, const GUID *vendor, DWORD option return hr; }
- hr = create_metadata_reader(&GUID_MetadataFormatIfd, vendor, options, ifd_stream, &ifd_reader); + if (SUCCEEDED(hr)) + hr = create_metadata_handler(ifd_stream, &GUID_MetadataFormatIfd, vendor, options, is_writer, &ifd_reader); + IStream_Release(ifd_stream);
if (FAILED(hr)) @@ -1438,6 +1459,18 @@ static HRESULT LoadApp1Metadata(IStream *input, const GUID *vendor, DWORD option return S_OK; }
+static HRESULT LoadApp1MetadataReader(IStream *input, const GUID *vendor, DWORD options, + MetadataItem **items, DWORD *item_count) +{ + return load_app1_metadata_internal(input, vendor, options, false, items, item_count); +} + +static HRESULT LoadApp1MetadataWriter(IStream *input, const GUID *vendor, DWORD options, + MetadataItem **items, DWORD *item_count) +{ + return load_app1_metadata_internal(input, vendor, options, true, items, item_count); +} + static const MetadataHandlerVtbl IfdMetadataReader_Vtbl = { 0, &CLSID_WICIfdMetadataReader, @@ -1513,10 +1546,22 @@ static const MetadataHandlerVtbl App1MetadataReader_Vtbl = { 0, &CLSID_WICApp1MetadataReader, - LoadApp1Metadata + LoadApp1MetadataReader };
HRESULT App1MetadataReader_CreateInstance(REFIID iid, void **ppv) { return MetadataReader_Create(&App1MetadataReader_Vtbl, iid, ppv); } + +static const MetadataHandlerVtbl App1MetadataWriter_Vtbl = +{ + .is_writer = true, + &CLSID_WICApp1MetadataWriter, + LoadApp1MetadataWriter +}; + +HRESULT App1MetadataWriter_CreateInstance(REFIID iid, void **ppv) +{ + return MetadataReader_Create(&App1MetadataWriter_Vtbl, iid, ppv); +} diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c index 03e1cd19c47..94a1fb7d070 100644 --- a/dlls/windowscodecs/regsvr.c +++ b/dlls/windowscodecs/regsvr.c @@ -2119,6 +2119,15 @@ static struct regsvr_metadatawriter const metadatawriters_list[] = &GUID_VendorMicrosoft, &GUID_MetadataFormatIfd, }, + { + &CLSID_WICApp1MetadataWriter, + "The Wine Project", + "App1 Metadata Writer", + "1.0.0.0", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_MetadataFormatApp1, + }, { NULL } /* list terminator */ };
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 736923b8146..61a3fb42a96 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4221,9 +4221,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;
check_interface(writer, &IID_IWICMetadataWriter, TRUE); check_interface(writer, &IID_IWICMetadataReader, TRUE); @@ -4487,7 +4485,6 @@ static void test_CreateMetadataWriter(void) check_persist_options(writer, 0); hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(IsEqualGUID(&format, &GUID_MetadataFormatApp1), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); IWICMetadataWriter_Release(writer);
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 028c167687d..bbdb4c36f73 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -226,6 +226,7 @@ extern HRESULT GpsMetadataWriter_CreateInstance(REFIID iid, void **ppv); extern HRESULT ExifMetadataReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT ExifMetadataWriter_CreateInstance(REFIID iid, void **ppv); extern HRESULT App1MetadataReader_CreateInstance(REFIID iid, void **ppv); +extern HRESULT App1MetadataWriter_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 438a39fd2be..84bc2d73f79 100644 --- a/dlls/windowscodecs/windowscodecs_wincodec.idl +++ b/dlls/windowscodecs/windowscodecs_wincodec.idl @@ -209,6 +209,13 @@ coclass WICExifMetadataWriter { interface IWICMetadataWriter; } ] coclass WICApp1MetadataReader { interface IWICMetadataReader; }
+[ + helpstring("WIC App1 Metadata Writer"), + threading(both), + uuid(ee366069-1832-420f-b381-0479ad066f19) +] +coclass WICApp1MetadataWriter { interface IWICMetadataWriter; } + [ helpstring("WIC Png cHRM Metadata Reader"), threading(both),
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/imgfactory.c | 3 +++ dlls/windowscodecs/tests/metadata.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index c941344f1aa..e0b863f5cd4 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1616,6 +1616,9 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriter(IWICComponentFactory if (!format || !writer) return E_INVALIDARG;
+ if (options & WICPersistOptionMask) + return E_INVALIDARG; + return create_metadata_writer(format, vendor, options, writer); }
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 61a3fb42a96..9ad9e38372c 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4423,6 +4423,7 @@ static void test_CreateMetadataWriter(void) { &GUID_MetadataFormatIfd, WICPersistOptionNoCacheStream }, { &GUID_MetadataFormatChunktEXt, WICPersistOptionNoCacheStream }, { &GUID_MetadataFormatApp1, 0x100 }, + { &GUID_MetadataFormatApp1, 0x1000 }, }; IWICStreamProvider *stream_provider; IWICComponentFactory *factory; @@ -4440,9 +4441,10 @@ static void test_CreateMetadataWriter(void) { const struct options_test *test = &options_tests[i];
+ writer = (void *)0xdeadbeef; hr = IWICComponentFactory_CreateMetadataWriter(factory, test->clsid, NULL, test->options, &writer); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(writer == (void *)0xdeadbeef, "Unexpected value %p.\n", writer); }
hr = IWICComponentFactory_CreateMetadataWriter(factory, &GUID_MetadataFormatChunktEXt, NULL, 0, &writer);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/imgfactory.c | 89 +++++++++++++++++++++++++- dlls/windowscodecs/metadatahandler.c | 2 +- dlls/windowscodecs/tests/metadata.c | 37 ++++++++--- dlls/windowscodecs/wincodecs_private.h | 2 + 4 files changed, 116 insertions(+), 14 deletions(-)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index e0b863f5cd4..9316beedb04 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1623,10 +1623,93 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriter(IWICComponentFactory }
static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICComponentFactory *iface, - IWICMetadataReader *reader, const GUID *vendor, IWICMetadataWriter **writer) + IWICMetadataReader *reader, const GUID *vendor, IWICMetadataWriter **out_writer) { - FIXME("%p,%p,%s,%p: stub\n", iface, reader, debugstr_guid(vendor), writer); - return E_NOTIMPL; + IWICStreamProvider *stream_provider = NULL; + IWICMetadataWriter *writer = NULL; + IStream *stream = NULL; + DWORD options = 0; + GUID format; + HRESULT hr; + + TRACE("%p,%p,%s,%p\n", iface, reader, debugstr_guid(vendor), out_writer); + + if (!reader || !out_writer) + return E_INVALIDARG; + + hr = IWICMetadataReader_GetMetadataFormat(reader, &format); + + if (SUCCEEDED(hr)) + hr = create_metadata_writer(&format, vendor, 0, &writer); + + if (SUCCEEDED(hr)) + hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICStreamProvider, (void **)&stream_provider); + + if (SUCCEEDED(hr)) + { + IStream *cached_stream = NULL; + + hr = IWICStreamProvider_GetStream(stream_provider, &cached_stream); + + /* Reader does not have to provide a stream. */ + if (hr == WINCODEC_ERR_STREAMNOTAVAILABLE) + { + hr = S_OK; + } + + if (cached_stream) + { + hr = create_stream_wrapper(cached_stream, 0, &stream); + IStream_Release(cached_stream); + } + } + + if (SUCCEEDED(hr)) + hr = IWICStreamProvider_GetPersistOptions(stream_provider, &options); + + if (SUCCEEDED(hr)) + { + if (stream) + { + IWICPersistStream *persist_stream; + + /* TODO: probably need to check for a dirty stream */ + + if (SUCCEEDED(hr = IWICMetadataWriter_QueryInterface(writer, &IID_IWICPersistStream, (void **)&persist_stream))) + { + hr = IWICPersistStream_LoadEx(persist_stream, stream, vendor, options); + IWICPersistStream_Release(persist_stream); + } + } + else + { + UINT count; + + hr = IWICMetadataReader_GetCount(reader, &count); + + if (SUCCEEDED(hr)) + { + if (count) + FIXME("Copy metadata items to the writer.\n"); + } + } + } + + if (stream_provider) + IWICStreamProvider_Release(stream_provider); + + if (SUCCEEDED(hr)) + { + *out_writer = writer; + IWICMetadataWriter_AddRef(*out_writer); + } + + if (writer) + IWICMetadataWriter_Release(writer); + if (stream) + IStream_Release(stream); + + return hr; }
static HRESULT WINAPI ComponentFactory_CreateQueryReaderFromBlockReader(IWICComponentFactory *iface, diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 7e00f678e4e..71f81900395 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -847,7 +847,7 @@ static int tag_to_vt(SHORT tag) return (tag > 0 && tag <= 13) ? tag2vt[tag] : VT_BLOB; }
-static HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wrapper) +HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wrapper) { ULARGE_INTEGER start, maxsize; IWICStream *wic_stream = NULL; diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 9ad9e38372c..7904547114b 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4111,6 +4111,7 @@ static void test_metadata_App1(void)
hr = get_persist_stream(ifd_reader, &stream2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(stream2, &IID_IWICStream, TRUE); ok(!!stream2 && app1_stream != stream2, "Unexpected stream.\n"); IStream_Release(stream2);
@@ -4158,6 +4159,7 @@ static void test_metadata_App1(void)
hr = get_persist_stream(exif_reader, &stream2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(stream2, &IID_IWICStream, TRUE); ok(!!stream2 && stream2 != app1_stream, "Unexpected stream.\n"); IStream_Release(stream2);
@@ -4195,6 +4197,7 @@ static void test_metadata_App1(void)
hr = get_persist_stream(gps_reader, &stream2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_interface(stream2, &IID_IWICStream, TRUE); ok(!!stream2 && stream2 != app1_stream, "Unexpected stream.\n"); IStream_Release(stream2);
@@ -4256,14 +4259,7 @@ static void test_CreateMetadataWriterFromReader(void) check_persist_options(reader, 0);
hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, reader, NULL, &writer); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (FAILED(hr)) - { - IWICMetadataReader_Release(reader); - IWICComponentFactory_Release(factory); - return; - }
IWICMetadataReader_Release(reader);
@@ -4276,7 +4272,6 @@ static void test_CreateMetadataWriterFromReader(void) NULL, 0, stream, &reader); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); check_persist_options(reader, 0); - IStream_Release(stream);
hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, NULL, NULL, NULL); ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); @@ -4309,6 +4304,7 @@ static void test_CreateMetadataWriterFromReader(void)
hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "Unexpected format %s.\n", wine_dbgstr_guid(&format));
hr = IWICMetadataWriter_GetCount(writer, &count); @@ -4319,15 +4315,26 @@ static void test_CreateMetadataWriterFromReader(void) PropVariantInit(&value); hr = IWICMetadataWriter_GetValueByIndex(writer, 0, NULL, &id, &value); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(id.vt == VT_LPSTR, "Unexpected id type %u.\n", id.vt); - ok(!strcmp(id.pszVal, "winetest"), "Unexpected id %s.\n", wine_dbgstr_a(id.pszVal)); + if (id.vt == VT_LPSTR) + ok(!strcmp(id.pszVal, "winetest"), "Unexpected id %s.\n", wine_dbgstr_a(id.pszVal)); + todo_wine ok(value.vt == VT_LPSTR, "Unexpected value type %u.\n", value.vt); - ok(!strcmp(value.pszVal, "value"), "Unexpected value %s.\n", wine_dbgstr_a(value.pszVal)); + if (value.vt == VT_LPSTR) + ok(!strcmp(value.pszVal, "value"), "Unexpected value %s.\n", wine_dbgstr_a(value.pszVal)); PropVariantClear(&id); PropVariantClear(&value);
+ hr = get_persist_stream(writer, &stream2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(stream2 != stream, "Unexpected stream.\n"); + check_interface(stream2, &IID_IWICStream, TRUE); + IStream_Release(stream2); + IWICMetadataWriter_Release(writer); IWICMetadataReader_Release(reader); + IStream_Release(stream);
/* App1 reader */ stream = create_stream((const char *)&app1_data, sizeof(app1_data)); @@ -4378,6 +4385,7 @@ static void test_CreateMetadataWriterFromReader(void) hr = get_persist_stream(writer, &stream2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(stream2 != stream, "Unexpected stream.\n"); + check_interface(stream2, &IID_IWICStream, TRUE); IStream_Release(stream2);
IWICMetadataWriter_Release(writer); @@ -4397,9 +4405,18 @@ static void test_CreateMetadataWriterFromReader(void) check_persist_options(reader, WICPersistOptionBigEndian); free(data);
+ hr = IWICMetadataReader_GetMetadataFormat(reader, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); + hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, reader, NULL, &writer); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); check_persist_options(writer, WICPersistOptionBigEndian); + + hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); + IWICMetadataWriter_Release(writer);
IWICMetadataReader_Release(reader); diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index bbdb4c36f73..9858a1fdebb 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -164,6 +164,8 @@ extern HRESULT ColorContext_Create(IWICColorContext **context); extern HRESULT ColorTransform_Create(IWICColorTransform **transform); extern HRESULT BitmapClipper_Create(IWICBitmapClipper **clipper);
+extern HRESULT create_stream_wrapper(IStream *input, ULONG offset, IStream **wrapper); + extern HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer, UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc, UINT dststride, UINT dstbuffersize, BYTE *dstbuffer);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/tests/metadata.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 7904547114b..253a525c5c9 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4047,9 +4047,11 @@ app1_data = static void test_metadata_App1(void) { IWICMetadataReader *reader, *ifd_reader, *exif_reader, *gps_reader; + IWICEnumMetadataItem *enumerator; IStream *app1_stream, *stream2; IWICMetadataWriter *writer; PROPVARIANT id, value; + ULONG fetched; GUID format; HRESULT hr; UINT count; @@ -4088,6 +4090,29 @@ static void test_metadata_App1(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(count == 1, "Unexpected count %u.\n", count);
+ /* Enumerator returns top level item. */ + hr = IWICMetadataReader_GetEnumerator(reader, &enumerator); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &fetched); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + ok(id.vt == VT_UI2, "Unexpected id type: %u.\n", id.vt); + ok(id.uiVal == 0, "Unexpected id %u.\n", id.uiVal); + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + ok(!!value.punkVal, "Unexpected value.\n"); + PropVariantClear(&value); + + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICEnumMetadataItem_Next(enumerator, 1, NULL, &id, &value, &fetched); + ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); + ok(!fetched, "Unexpected count %lu.\n", fetched); + + IWICEnumMetadataItem_Release(enumerator); + PropVariantInit(&id); PropVariantInit(&value); hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, &value);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/metadatahandler.c | 103 +++++++++++++++++++++----- dlls/windowscodecs/tests/metadata.c | 106 ++++++++++++++++++++++++++- 2 files changed, 187 insertions(+), 22 deletions(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 71f81900395..18ef6419eb4 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -61,16 +61,19 @@ static inline MetadataHandler *impl_from_IWICStreamProvider(IWICStreamProvider * return CONTAINING_RECORD(iface, MetadataHandler, IWICStreamProvider_iface); }
+static void clear_metadata_item(MetadataItem *item) +{ + PropVariantClear(&item->schema); + PropVariantClear(&item->id); + PropVariantClear(&item->value); +} + static void MetadataHandler_FreeItems(MetadataHandler *This) { DWORD i;
for (i=0; i<This->item_count; i++) - { - PropVariantClear(&This->items[i].schema); - PropVariantClear(&This->items[i].id); - PropVariantClear(&This->items[i].value); - } + clear_metadata_item(&This->items[i]);
free(This->items); This->items = NULL; @@ -224,12 +227,32 @@ static HRESULT WINAPI MetadataHandler_GetValueByIndex(IWICMetadataWriter *iface, return hr; }
+static MetadataItem *metadatahandler_get_item(MetadataHandler *handler, const PROPVARIANT *schema, + const PROPVARIANT *id) +{ + UINT i; + + for (i = 0; i < handler->item_count; i++) + { + if (schema && handler->items[i].schema.vt != VT_EMPTY) + { + if (PropVariantCompareEx(schema, &handler->items[i].schema, 0, PVCF_USESTRCMPI) != 0) continue; + } + + if (PropVariantCompareEx(id, &handler->items[i].id, 0, PVCF_USESTRCMPI) != 0) continue; + + return &handler->items[i]; + } + + return NULL; +} + static HRESULT WINAPI MetadataHandler_GetValue(IWICMetadataWriter *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value) { - UINT i; - HRESULT hr = WINCODEC_ERR_PROPERTYNOTFOUND; MetadataHandler *This = impl_from_IWICMetadataWriter(iface); + HRESULT hr = WINCODEC_ERR_PROPERTYNOTFOUND; + MetadataItem *item;
TRACE("(%p,%s,%s,%p)\n", iface, wine_dbgstr_variant((const VARIANT *)schema), wine_dbgstr_variant((const VARIANT *)id), value);
@@ -237,17 +260,9 @@ static HRESULT WINAPI MetadataHandler_GetValue(IWICMetadataWriter *iface,
EnterCriticalSection(&This->lock);
- for (i = 0; i < This->item_count; i++) + if ((item = metadatahandler_get_item(This, schema, id))) { - if (schema && This->items[i].schema.vt != VT_EMPTY) - { - if (PropVariantCompareEx(schema, &This->items[i].schema, 0, PVCF_USESTRCMPI) != 0) continue; - } - - if (PropVariantCompareEx(id, &This->items[i].id, 0, PVCF_USESTRCMPI) != 0) continue; - - hr = value ? PropVariantCopy(value, &This->items[i].value) : S_OK; - break; + hr = value ? PropVariantCopy(value, &item->value) : S_OK; }
LeaveCriticalSection(&This->lock); @@ -263,10 +278,58 @@ static HRESULT WINAPI MetadataHandler_GetEnumerator(IWICMetadataWriter *iface, }
static HRESULT WINAPI MetadataHandler_SetValue(IWICMetadataWriter *iface, - const PROPVARIANT *pvarSchema, const PROPVARIANT *pvarId, const PROPVARIANT *pvarValue) + const PROPVARIANT *schema, const PROPVARIANT *id, const PROPVARIANT *value) { - FIXME("(%p,%p,%p,%p): stub\n", iface, pvarSchema, pvarId, pvarValue); - return E_NOTIMPL; + MetadataHandler *This = impl_from_IWICMetadataWriter(iface); + MetadataItem *item, *new_items; + HRESULT hr; + + TRACE("(%p,%p,%p,%p)\n", iface, schema, id, value); + + if (!id || !value) + return E_INVALIDARG; + + /* Replace value of an existing item, or append a new one. */ + + EnterCriticalSection(&This->lock); + + if ((item = metadatahandler_get_item(This, schema, id))) + { + PropVariantClear(&item->value); + hr = PropVariantCopy(&item->value, value); + } + else + { + new_items = realloc(This->items, (This->item_count + 1) * sizeof(*new_items)); + if (new_items) + { + This->items = new_items; + + item = &This->items[This->item_count]; + + PropVariantInit(&item->schema); + PropVariantInit(&item->id); + PropVariantInit(&item->value); + + /* Skip setting the schema value, it's probably format-dependent. */ + hr = PropVariantCopy(&item->id, id); + if (SUCCEEDED(hr)) + hr = PropVariantCopy(&item->value, value); + + if (SUCCEEDED(hr)) + ++This->item_count; + else + clear_metadata_item(item); + } + else + { + hr = E_OUTOFMEMORY; + } + } + + LeaveCriticalSection(&This->lock); + + return hr; }
static HRESULT WINAPI MetadataHandler_SetValueByIndex(IWICMetadataWriter *iface, diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 253a525c5c9..922e1738b7a 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -3853,7 +3853,7 @@ static void test_queryreader(void) IWICComponentFactory_Release(factory); }
-static void test_metadata_writer(void) +static void test_metadata_query_writer(void) { static struct { @@ -4544,6 +4544,107 @@ static void test_CreateMetadataWriter(void) IWICComponentFactory_Release(factory); }
+static void test_metadata_writer(void) +{ + IWICComponentFactory *factory; + IWICMetadataWriter *writer; + GUID format; + HRESULT hr; + UINT count; + PROPVARIANT schema, id, value; + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICComponentFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICComponentFactory_CreateMetadataWriter(factory, &GUID_MetadataFormatIfd, NULL, 0, &writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_GetMetadataFormat(writer, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); + + hr = IWICMetadataWriter_GetCount(writer, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!count, "Unexpected count %u.\n", count); + + schema.vt = VT_I4; + schema.lVal = 100; + id.vt = VT_UI2; + id.uiVal = 200; + value.vt = VT_UI4; + value.ulVal = 300; + hr = IWICMetadataWriter_SetValueByIndex(writer, 0, &schema, &id, &value); + todo_wine + ok(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_SetValue(writer, &schema, &id, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_SetValue(writer, &schema, NULL, &value); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_SetValue(writer, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_GetCount(writer, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 1, "Unexpected count %u.\n", count); + + id.vt = VT_UI2; + id.uiVal = 201; + hr = IWICMetadataWriter_SetValue(writer, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_GetCount(writer, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 2, "Unexpected count %u.\n", count); + + /* Same id with differing schema does not add a new item. */ + schema.vt = VT_I4; + schema.lVal = 101; + hr = IWICMetadataWriter_SetValue(writer, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataWriter_GetCount(writer, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 2, "Unexpected count %u.\n", count); + + PropVariantInit(&schema); + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICMetadataWriter_GetValueByIndex(writer, 0, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(schema.vt == VT_EMPTY, "Unexpected type %u.\n", schema.vt); + ok(!schema.lVal, "Unexpected value %lu.\n", schema.lVal); + ok(id.vt == VT_UI2, "Unexpected type %u.\n", id.vt); + ok(id.uiVal == 200, "Unexpected value %u.\n", id.uiVal); + ok(value.vt == VT_UI4, "Unexpected type %u.\n", value.vt); + ok(value.uiVal == 300, "Unexpected value %lu.\n", value.ulVal); + + PropVariantInit(&schema); + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICMetadataWriter_GetValueByIndex(writer, 1, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(schema.vt == VT_EMPTY, "Unexpected type %u.\n", schema.vt); + ok(!schema.lVal, "Unexpected value %lu.\n", schema.lVal); + ok(id.vt == VT_UI2, "Unexpected type %u.\n", id.vt); + ok(id.uiVal == 201, "Unexpected value %u.\n", id.uiVal); + ok(value.vt == VT_UI4, "Unexpected type %u.\n", value.vt); + ok(value.uiVal == 300, "Unexpected value %lu.\n", value.ulVal); + + value.vt = VT_UI4; + value.ulVal = 301; + hr = IWICMetadataWriter_SetValueByIndex(writer, 1, &schema, &id, &value); + todo_wine + ok(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION, "Unexpected hr %#lx.\n", hr); + + IWICMetadataWriter_Release(writer); + + IWICComponentFactory_Release(factory); +} + START_TEST(metadata) { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); @@ -4570,10 +4671,11 @@ START_TEST(metadata) test_metadata_GCE(); test_metadata_APE(); test_metadata_GIF_comment(); - test_metadata_writer(); + test_metadata_query_writer(); test_metadata_App1(); test_CreateMetadataWriterFromReader(); test_CreateMetadataWriter(); + test_metadata_writer();
CoUninitialize(); }
v2: addressed both error path cleanups, and 'id' null check.
This merge request was approved by Esme Povirk.