From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/imgfactory.c | 81 +++++++++++++++++++++++------ dlls/windowscodecs/tests/metadata.c | 32 ++++++++++++ 2 files changed, 97 insertions(+), 16 deletions(-)
diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index 9316beedb04..0608be76c08 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -1622,8 +1622,59 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriter(IWICComponentFactory return create_metadata_writer(format, vendor, options, writer); }
-static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICComponentFactory *iface, - IWICMetadataReader *reader, const GUID *vendor, IWICMetadataWriter **out_writer) +static HRESULT create_metadata_writer_from_reader(IWICMetadataReader *reader, const GUID *vendor, + IWICMetadataWriter **out_writer); + +static HRESULT metadata_writer_copy_items_from_reader(IWICMetadataWriter *writer, const GUID *vendor, IWICMetadataReader *reader) +{ + IWICMetadataReader *sub_reader; + IWICMetadataWriter *sub_writer; + PROPVARIANT schema, id, value; + UINT i, count; + HRESULT hr; + + if (FAILED(hr = IWICMetadataReader_GetCount(reader, &count))) + return hr; + + for (i = 0; i < count; ++i) + { + PropVariantInit(&schema); + PropVariantInit(&id); + PropVariantInit(&value); + if (FAILED(hr = IWICMetadataReader_GetValueByIndex(reader, i, &schema, &id, &value))) + break; + + /* Recursively create writers from the nested readers. */ + if (value.vt == VT_UNKNOWN) + { + if (SUCCEEDED(IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataReader, (void **)&sub_reader))) + { + hr = create_metadata_writer_from_reader(sub_reader, vendor, &sub_writer); + if (SUCCEEDED(hr)) + { + IUnknown_Release(value.punkVal); + value.punkVal = (IUnknown *)sub_writer; + } + + IWICMetadataReader_Release(sub_reader); + } + } + + if (SUCCEEDED(hr)) + hr = IWICMetadataWriter_SetValue(writer, &schema, &id, &value); + + PropVariantClear(&schema); + PropVariantClear(&id); + PropVariantClear(&value); + if (FAILED(hr)) + break; + } + + return hr; +} + +static HRESULT create_metadata_writer_from_reader(IWICMetadataReader *reader, const GUID *vendor, + IWICMetadataWriter **out_writer) { IWICStreamProvider *stream_provider = NULL; IWICMetadataWriter *writer = NULL; @@ -1632,11 +1683,6 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICCompon 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)) @@ -1683,15 +1729,7 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICCompon } else { - UINT count; - - hr = IWICMetadataReader_GetCount(reader, &count); - - if (SUCCEEDED(hr)) - { - if (count) - FIXME("Copy metadata items to the writer.\n"); - } + hr = metadata_writer_copy_items_from_reader(writer, vendor, reader); } }
@@ -1712,6 +1750,17 @@ static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICCompon return hr; }
+static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICComponentFactory *iface, + IWICMetadataReader *reader, const GUID *vendor, IWICMetadataWriter **writer) +{ + TRACE("%p,%p,%s,%p\n", iface, reader, debugstr_guid(vendor), writer); + + if (!reader || !writer) + return E_INVALIDARG; + + return create_metadata_writer_from_reader(reader, vendor, writer); +} + static HRESULT WINAPI ComponentFactory_CreateQueryReaderFromBlockReader(IWICComponentFactory *iface, IWICMetadataBlockReader *block_reader, IWICMetadataQueryReader **query_reader) { diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 922e1738b7a..db16a67f1aa 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4417,6 +4417,38 @@ static void test_CreateMetadataWriterFromReader(void) IWICMetadataReader_Release(reader); IStream_Release(stream);
+ /* App1, reader without stream caching. */ + stream = create_stream((const char *)&app1_data, sizeof(app1_data)); + hr = IWICComponentFactory_CreateMetadataReader(factory, &GUID_MetadataFormatApp1, + NULL, WICPersistOptionNoCacheStream, stream, &reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_persist_options(reader, WICPersistOptionNoCacheStream); + + hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, reader, NULL, &writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataReader_GetMetadataFormat(reader, &format); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatApp1), "Unexpected format %s.\n", wine_dbgstr_guid(&format)); + + hr = IWICMetadataWriter_GetCount(writer, &count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(count == 1, "Unexpected count %u.\n", count); + + PropVariantInit(&id); + PropVariantInit(&value); + hr = IWICMetadataWriter_GetValueByIndex(writer, 0, NULL, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(id.vt == VT_UI2, "Unexpected id type %u.\n", id.vt); + ok(value.vt == VT_UNKNOWN, "Unexpected value type %u.\n", value.vt); + check_interface(value.punkVal, &IID_IWICMetadataReader, TRUE); + check_interface(value.punkVal, &IID_IWICMetadataWriter, TRUE); + PropVariantClear(&value); + + IWICMetadataWriter_Release(writer); + IWICMetadataReader_Release(reader); + IStream_Release(stream); + /* Big-endian IFD */ data = malloc(sizeof(IFD_data)); memcpy(data, &IFD_data, sizeof(IFD_data));
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/tests/metadata.c | 349 ++++++++++++++++++++-------- 1 file changed, 255 insertions(+), 94 deletions(-)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index db16a67f1aa..d3ffd0f276d 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -31,9 +31,6 @@ #include "propvarutil.h" #include "wine/test.h"
-#include "initguid.h" -DEFINE_GUID(IID_MdbrUnknown, 0x00240e6f,0x3f23,0x4432,0xb0,0xcc,0x48,0xd5,0xbb,0xff,0x6c,0x36); - #define expect_ref(obj,ref) expect_ref_((IUnknown *)obj, ref, __LINE__) static void expect_ref_(IUnknown *obj, ULONG ref, int line) { @@ -3360,18 +3357,29 @@ struct metadata const struct metadata_block *block; };
-static const struct metadata *current_metadata; -static const struct metadata_block *current_metadata_block; - static char the_best[] = "The Best"; static char the_worst[] = "The Worst";
-static HRESULT WINAPI mdr_QueryInterface(IWICMetadataReader *iface, REFIID iid, void **out) +struct test_writer +{ + IWICMetadataWriter IWICMetadataWriter_iface; + LONG refcount; + const struct metadata_block *block; +}; + +static inline struct test_writer *impl_from_IWICMetadataWriter(IWICMetadataWriter *iface) +{ + return CONTAINING_RECORD(iface, struct test_writer, IWICMetadataWriter_iface); +} + +static HRESULT WINAPI test_writer_QueryInterface(IWICMetadataWriter *iface, REFIID iid, void **out) { if (IsEqualIID(iid, &IID_IUnknown) || - IsEqualIID(iid, &IID_IWICMetadataReader)) + IsEqualIID(iid, &IID_IWICMetadataReader) || + IsEqualIID(iid, &IID_IWICMetadataWriter)) { *out = iface; + IWICMetadataWriter_AddRef(iface); return S_OK; }
@@ -3381,41 +3389,47 @@ static HRESULT WINAPI mdr_QueryInterface(IWICMetadataReader *iface, REFIID iid, return E_NOINTERFACE; }
-static ULONG WINAPI mdr_AddRef(IWICMetadataReader *iface) +static ULONG WINAPI test_writer_AddRef(IWICMetadataWriter *iface) { - return 2; + struct test_writer *writer = impl_from_IWICMetadataWriter(iface); + return InterlockedIncrement(&writer->refcount); }
-static ULONG WINAPI mdr_Release(IWICMetadataReader *iface) +static ULONG WINAPI test_writer_Release(IWICMetadataWriter *iface) { - return 1; + struct test_writer *writer = impl_from_IWICMetadataWriter(iface); + ULONG refcount = InterlockedDecrement(&writer->refcount); + + if (!refcount) + free(writer); + + return refcount; }
-static HRESULT WINAPI mdr_GetMetadataFormat(IWICMetadataReader *iface, GUID *format) +static HRESULT WINAPI test_writer_GetMetadataFormat(IWICMetadataWriter *iface, GUID *format) { - ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n"); - if (!current_metadata_block) return E_POINTER; + struct test_writer *writer = impl_from_IWICMetadataWriter(iface);
- *format = *current_metadata_block->metadata_format; + *format = *writer->block->metadata_format; return S_OK; }
-static HRESULT WINAPI mdr_GetMetadataHandlerInfo(IWICMetadataReader *iface, IWICMetadataHandlerInfo **handler) +static HRESULT WINAPI test_writer_GetMetadataHandlerInfo(IWICMetadataWriter *iface, IWICMetadataHandlerInfo **handler) { ok(0, "not implemented\n"); return E_NOTIMPL; }
-static HRESULT WINAPI mdr_GetCount(IWICMetadataReader *iface, UINT *count) +static HRESULT WINAPI test_writer_GetCount(IWICMetadataWriter *iface, UINT *count) { - ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n"); - if (!current_metadata_block) return E_POINTER; + struct test_writer *writer = impl_from_IWICMetadataWriter(iface);
- *count = current_metadata_block->count; + *count = writer->block->count; return S_OK; }
-static HRESULT WINAPI mdr_GetValueByIndex(IWICMetadataReader *iface, UINT index, PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value) +static HRESULT WINAPI test_writer_GetValueByIndex(IWICMetadataWriter *iface, UINT index, + PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value) { ok(0, "not implemented\n"); return E_NOTIMPL; @@ -3432,26 +3446,24 @@ static int propvar_cmp(const PROPVARIANT *v1, LONGLONG value2) return 0; }
-static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value) +static HRESULT WINAPI test_writer_GetValue(IWICMetadataWriter *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value) { + struct test_writer *writer = impl_from_IWICMetadataWriter(iface); UINT i;
- ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n"); - if (!current_metadata_block) return E_POINTER; - ok(schema != NULL && id != NULL && value != NULL, "%p, %p, %p should not be NULL\n", schema, id, value);
- for (i = 0; i < current_metadata_block->count; i++) + for (i = 0; i < writer->block->count; i++) { if (schema->vt != VT_EMPTY) { - if (!current_metadata_block->item[i].schema) + if (!writer->block->item[i].schema) continue;
switch (schema->vt) { case VT_LPSTR: - if (lstrcmpA(schema->pszVal, current_metadata_block->item[i].schema) != 0) + if (lstrcmpA(schema->pszVal, writer->block->item[i].schema) != 0) continue; break;
@@ -3459,7 +3471,7 @@ static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT { char schemaA[256]; WideCharToMultiByte(CP_ACP, 0, schema->pwszVal, -1, schemaA, sizeof(schemaA), NULL, NULL); - if (lstrcmpA(schemaA, current_metadata_block->item[i].schema) != 0) + if (lstrcmpA(schemaA, writer->block->item[i].schema) != 0) continue; break; } @@ -3469,15 +3481,15 @@ static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT continue; } } - else if (current_metadata_block->item[i].schema) + else if (writer->block->item[i].schema) continue;
switch (id->vt) { case VT_LPSTR: - if (current_metadata_block->item[i].id_str) + if (writer->block->item[i].id_str) { - if (!lstrcmpA(id->pszVal, current_metadata_block->item[i].id_str)) + if (!lstrcmpA(id->pszVal, writer->block->item[i].id_str)) { value->vt = VT_LPSTR; value->pszVal = the_best; @@ -3488,11 +3500,11 @@ static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT break;
case VT_LPWSTR: - if (current_metadata_block->item[i].id_str) + if (writer->block->item[i].id_str) { char idA[256]; WideCharToMultiByte(CP_ACP, 0, id->pwszVal, -1, idA, sizeof(idA), NULL, NULL); - if (!lstrcmpA(idA, current_metadata_block->item[i].id_str)) + if (!lstrcmpA(idA, writer->block->item[i].id_str)) { value->vt = VT_LPSTR; value->pszVal = the_worst; @@ -3513,10 +3525,10 @@ static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT break;
default: - if (!propvar_cmp(id, current_metadata_block->item[i].id)) + if (!propvar_cmp(id, writer->block->item[i].id)) { - value->vt = current_metadata_block->item[i].type; - value->uiVal = current_metadata_block->item[i].value; + value->vt = writer->block->item[i].type; + value->uiVal = writer->block->item[i].value; return S_OK; } break; @@ -3526,108 +3538,227 @@ static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT return 0xdeadbeef; }
-static HRESULT WINAPI mdr_GetEnumerator(IWICMetadataReader *iface, IWICEnumMetadataItem **enumerator) +static HRESULT WINAPI test_writer_GetEnumerator(IWICMetadataWriter *iface, IWICEnumMetadataItem **enumerator) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_writer_SetValue(IWICMetadataWriter *iface, const PROPVARIANT *schema, + const PROPVARIANT *id, const PROPVARIANT *value) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_writer_SetValueByIndex(IWICMetadataWriter *iface, UINT index, + const PROPVARIANT *schema, const PROPVARIANT *id, const PROPVARIANT *value) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_writer_RemoveValue(IWICMetadataWriter *iface, const PROPVARIANT *schema, + const PROPVARIANT *id) { ok(0, "not implemented\n"); return E_NOTIMPL; }
-static const IWICMetadataReaderVtbl mdr_vtbl = +static HRESULT WINAPI test_writer_RemoveValueByIndex(IWICMetadataWriter *iface, UINT index) { - mdr_QueryInterface, - mdr_AddRef, - mdr_Release, - mdr_GetMetadataFormat, - mdr_GetMetadataHandlerInfo, - mdr_GetCount, - mdr_GetValueByIndex, - mdr_GetValue, - mdr_GetEnumerator + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static const IWICMetadataWriterVtbl test_writer_vtbl = +{ + test_writer_QueryInterface, + test_writer_AddRef, + test_writer_Release, + test_writer_GetMetadataFormat, + test_writer_GetMetadataHandlerInfo, + test_writer_GetCount, + test_writer_GetValueByIndex, + test_writer_GetValue, + test_writer_GetEnumerator, + test_writer_SetValue, + test_writer_SetValueByIndex, + test_writer_RemoveValue, + test_writer_RemoveValueByIndex, };
-static IWICMetadataReader mdr = { &mdr_vtbl }; +static IWICMetadataWriter *create_test_writer(const struct metadata_block *block) +{ + struct test_writer *writer; + + writer = calloc(1, sizeof(*writer)); + writer->IWICMetadataWriter_iface.lpVtbl = &test_writer_vtbl; + writer->refcount = 1; + writer->block = block; + + return &writer->IWICMetadataWriter_iface; +} + +struct test_block_writer +{ + IWICMetadataBlockWriter IWICMetadataBlockWriter_iface; + LONG refcount; + + IWICMetadataWriter **writers; + unsigned int count; + + GUID container_format; +};
-static HRESULT WINAPI mdbr_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, void **out) +static inline struct test_block_writer *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface) +{ + return CONTAINING_RECORD(iface, struct test_block_writer, IWICMetadataBlockWriter_iface); +} + +static HRESULT WINAPI test_block_writer_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **out) { if (IsEqualIID(iid, &IID_IUnknown) || - IsEqualIID(iid, &IID_IWICMetadataBlockReader)) + IsEqualIID(iid, &IID_IWICMetadataBlockReader) || + IsEqualIID(iid, &IID_IWICMetadataBlockWriter)) { *out = iface; + IWICMetadataBlockWriter_AddRef(iface); return S_OK; }
- /* Windows 8/10 query for some undocumented IID */ - if (!IsEqualIID(iid, &IID_MdbrUnknown)) - ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid)); - *out = NULL; return E_NOINTERFACE; }
-static ULONG WINAPI mdbr_AddRef(IWICMetadataBlockReader *iface) +static ULONG WINAPI test_block_writer_AddRef(IWICMetadataBlockWriter *iface) { - return 2; + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + return InterlockedIncrement(&writer->refcount); }
-static ULONG WINAPI mdbr_Release(IWICMetadataBlockReader *iface) +static ULONG WINAPI test_block_writer_Release(IWICMetadataBlockWriter *iface) { - return 1; + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + ULONG refcount = InterlockedDecrement(&writer->refcount); + unsigned int i; + + if (!refcount) + { + for (i = 0; i < writer->count; ++i) + IWICMetadataWriter_Release(writer->writers[i]); + free(writer->writers); + free(writer); + } + + return refcount; }
-static HRESULT WINAPI mdbr_GetContainerFormat(IWICMetadataBlockReader *iface, GUID *format) +static HRESULT WINAPI test_block_writer_GetContainerFormat(IWICMetadataBlockWriter *iface, GUID *format) { - ok(current_metadata != NULL, "current_metadata can't be NULL\n"); - if (!current_metadata) return E_POINTER; + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface);
- *format = *current_metadata->container_format; + *format = writer->container_format; return S_OK; }
-static HRESULT WINAPI mdbr_GetCount(IWICMetadataBlockReader *iface, UINT *count) +static HRESULT WINAPI test_block_writer_GetCount(IWICMetadataBlockWriter *iface, UINT *count) { - ok(current_metadata != NULL, "current_metadata can't be NULL\n"); - if (!current_metadata) return E_POINTER; + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface);
- *count = current_metadata->count; + *count = writer->count; return S_OK; }
-static HRESULT WINAPI mdbr_GetReaderByIndex(IWICMetadataBlockReader *iface, UINT index, IWICMetadataReader **out) +static HRESULT WINAPI test_block_writer_GetReaderByIndex(IWICMetadataBlockWriter *iface, UINT index, IWICMetadataReader **out) { + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + *out = NULL;
- ok(current_metadata != NULL, "current_metadata can't be NULL\n"); - if (!current_metadata) return E_POINTER; + if (index >= writer->count) + return E_INVALIDARG;
- if (index < current_metadata->count) - { - current_metadata_block = ¤t_metadata->block[index]; - *out = &mdr; - return S_OK; - } + *out = (IWICMetadataReader *)writer->writers[index]; + IWICMetadataReader_AddRef(*out);
- current_metadata_block = NULL; - return E_INVALIDARG; + return S_OK; +} + +static HRESULT WINAPI test_block_writer_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enumerator) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_block_writer_InitializeFromBlockReader(IWICMetadataBlockWriter *iface, + IWICMetadataBlockReader *reader) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_block_writer_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index, + IWICMetadataWriter **writer) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_block_writer_AddWriter(IWICMetadataBlockWriter *iface, + IWICMetadataWriter *_writer) +{ + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + + writer->writers = realloc(writer->writers, (writer->count + 1) * sizeof(*writer->writers)); + writer->writers[writer->count++] = _writer; + IWICMetadataWriter_AddRef(_writer); + + return S_OK; +} + +static HRESULT WINAPI test_block_writer_SetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index, + IWICMetadataWriter *writer) +{ + ok(0, "not implemented\n"); + return E_NOTIMPL; }
-static HRESULT WINAPI mdbr_GetEnumerator(IWICMetadataBlockReader *iface, IEnumUnknown **enumerator) +static HRESULT WINAPI test_block_writer_RemoveWriterByIndex(IWICMetadataBlockWriter *iface, UINT index) { ok(0, "not implemented\n"); return E_NOTIMPL; }
-static const IWICMetadataBlockReaderVtbl mdbr_vtbl = +static const IWICMetadataBlockWriterVtbl test_block_writer_vtbl = { - mdbr_QueryInterface, - mdbr_AddRef, - mdbr_Release, - mdbr_GetContainerFormat, - mdbr_GetCount, - mdbr_GetReaderByIndex, - mdbr_GetEnumerator + test_block_writer_QueryInterface, + test_block_writer_AddRef, + test_block_writer_Release, + test_block_writer_GetContainerFormat, + test_block_writer_GetCount, + test_block_writer_GetReaderByIndex, + test_block_writer_GetEnumerator, + test_block_writer_InitializeFromBlockReader, + test_block_writer_GetWriterByIndex, + test_block_writer_AddWriter, + test_block_writer_SetWriterByIndex, + test_block_writer_RemoveWriterByIndex, };
-static IWICMetadataBlockReader mdbr = { &mdbr_vtbl }; +static HRESULT create_test_block_writer(const GUID *container_format, IWICMetadataBlockWriter **writer) +{ + struct test_block_writer *object; + + object = calloc(1, sizeof(*object)); + object->IWICMetadataBlockWriter_iface.lpVtbl = &test_block_writer_vtbl; + object->refcount = 1; + object->container_format = *container_format; + + *writer = &object->IWICMetadataBlockWriter_iface; + + return S_OK; +}
static const char xmp[] = "http://ns.adobe.com/xap/1.0/"; static const char dc[] = "http://purl.org/dc/elements/1.1/"; @@ -3702,6 +3833,37 @@ static const struct metadata data3 = 5, block3 };
+static HRESULT create_query_reader(IWICComponentFactory *factory, const struct metadata *data, + IWICMetadataQueryReader **reader) +{ + IWICMetadataBlockWriter *block_writer; + IWICMetadataWriter *writer; + unsigned int i; + HRESULT hr; + + hr = create_test_block_writer(data->container_format, &block_writer); + if (SUCCEEDED(hr)) + { + for (i = 0; i < data->count; ++i) + { + writer = create_test_writer(&data->block[i]); + ok(!!writer, "Failed to create a writer.\n"); + hr = IWICMetadataBlockWriter_AddWriter(block_writer, writer); + ok(hr == S_OK, "Failed to add a writer, hr %#lx.\n", hr); + IWICMetadataWriter_Release(writer); + } + } + + if (SUCCEEDED(hr)) + { + hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, + (IWICMetadataBlockReader *)block_writer, reader); + IWICMetadataBlockWriter_Release(block_writer); + } + + return hr; +} + static void test_queryreader(void) { static const struct @@ -3761,14 +3923,12 @@ static void test_queryreader(void) &IID_IWICComponentFactory, (void **)&factory); ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
- hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &mdbr, &reader); - ok(hr == S_OK, "CreateQueryReaderFromBlockReader error %#lx\n", hr); - for (i = 0; i < ARRAY_SIZE(test_data); i++) { winetest_push_context("%u", i);
- current_metadata = test_data[i].data; + hr = create_query_reader(factory, test_data[i].data, &reader); + ok(hr == S_OK, "Failed to create a query reader, hr %#lx.\n", hr);
hr = IWICMetadataQueryReader_GetContainerFormat(reader, &format); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -3846,10 +4006,11 @@ static void test_queryreader(void) */ }
+ IWICMetadataQueryReader_Release(reader); + winetest_pop_context(); }
- IWICMetadataQueryReader_Release(reader); IWICComponentFactory_Release(factory); }
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/tests/metadata.c | 220 ++++++++++++++++++++++++---- 1 file changed, 193 insertions(+), 27 deletions(-)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index d3ffd0f276d..9cdabca8674 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -3446,6 +3446,13 @@ static int propvar_cmp(const PROPVARIANT *v1, LONGLONG value2) return 0; }
+static char *co_strdup(const char *str) +{ + char *out = CoTaskMemAlloc(strlen(str) + 1); + strcpy(out, str); + return out; +} + static HRESULT WINAPI test_writer_GetValue(IWICMetadataWriter *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value) { struct test_writer *writer = impl_from_IWICMetadataWriter(iface); @@ -3492,7 +3499,7 @@ static HRESULT WINAPI test_writer_GetValue(IWICMetadataWriter *iface, const PROP if (!lstrcmpA(id->pszVal, writer->block->item[i].id_str)) { value->vt = VT_LPSTR; - value->pszVal = the_best; + value->pszVal = co_strdup(the_best); return S_OK; } break; @@ -3507,7 +3514,7 @@ static HRESULT WINAPI test_writer_GetValue(IWICMetadataWriter *iface, const PROP if (!lstrcmpA(idA, writer->block->item[i].id_str)) { value->vt = VT_LPSTR; - value->pszVal = the_worst; + value->pszVal = co_strdup(the_worst); return S_OK; } break; @@ -3520,6 +3527,7 @@ static HRESULT WINAPI test_writer_GetValue(IWICMetadataWriter *iface, const PROP { value->vt = VT_UNKNOWN; value->punkVal = (IUnknown *)iface; + IUnknown_AddRef(value->punkVal); return S_OK; } break; @@ -3766,33 +3774,33 @@ static const char tiff[] = "http://ns.adobe.com/tiff/1.0/";
static const struct metadata_item item1[] = { - { NULL, NULL, 1, 2, 3 } + { NULL, NULL, 1, VT_I2, 3 } };
static const struct metadata_item item2[] = { - { NULL, NULL, 1, 2, 3 }, - { "xmp", "Rating", 4, 5, 6 }, - { NULL, "Rating", 7, 8, 9 } + { NULL, NULL, 1, VT_I2, 3 }, + { "xmp", "Rating", 4, VT_I4, 6 }, + { NULL, "Rating", 7, VT_UI2, 9 } };
static const struct metadata_item item3[] = { - { NULL, NULL, 1, 2, 3 }, - { NULL, NULL, 4, 5, 6 }, - { NULL, NULL, 7, 8, 9 }, - { NULL, NULL, 10, 11, 12 } + { NULL, NULL, 1, VT_I2, 3 }, + { NULL, NULL, 4, VT_I4, 6 }, + { NULL, NULL, 7, VT_UI4, 9 }, + { NULL, NULL, 10, VT_BOOL, 12 } };
static const struct metadata_item item4[] = { - { NULL, NULL, 1, 2, 3 }, - { xmp, "Rating", 4, 5, 6 }, - { dc, NULL, 7, 8, 9 }, - { tiff, NULL, 10, 11, 12 }, - { NULL, "RATING", 13, 14, 15 }, - { NULL, "R}ATING", 16, 17, 18 }, - { NULL, "xmp", 19, 20, 21 } + { NULL, NULL, 1, VT_I2, 3 }, + { xmp, "Rating", 4, VT_I4, 6 }, + { dc, NULL, 7, VT_UI4, 9 }, + { tiff, NULL, 10, VT_BOOL, 12 }, + { NULL, "RATING", 13, VT_I4, 15 }, + { NULL, "R}ATING", 16, VT_I2, 18 }, + { NULL, "xmp", 19, VT_UI4, 21 } };
static const struct metadata_block block1[] = @@ -3833,6 +3841,33 @@ static const struct metadata data3 = 5, block3 };
+static HRESULT create_query_reader_from_metadata_reader(IWICComponentFactory *factory, IWICMetadataReader *metadata_reader, + const GUID *container_format, IWICMetadataQueryReader **reader) +{ + IWICMetadataBlockWriter *block_writer = NULL; + IWICMetadataWriter *writer; + HRESULT hr; + + hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, metadata_reader, NULL, &writer); + + if (SUCCEEDED(hr)) + hr = create_test_block_writer(container_format, &block_writer); + + if (SUCCEEDED(hr)) + hr = IWICMetadataBlockWriter_AddWriter(block_writer, writer); + + if (SUCCEEDED(hr)) + hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, + (IWICMetadataBlockReader *)block_writer, reader); + + if (writer) + IWICMetadataWriter_Release(writer); + if (block_writer) + IWICMetadataBlockWriter_Release(block_writer); + + return hr; +} + static HRESULT create_query_reader(IWICComponentFactory *factory, const struct metadata *data, IWICMetadataQueryReader **reader) { @@ -3877,14 +3912,14 @@ static void test_queryreader(void) } test_data[] = { { FALSE, &data1, L"/ifd/{uchar=1}", S_OK, 2, 3, NULL }, - { FALSE, &data2, L"/ifd/xmp:{long=4}", S_OK, 5, 6, NULL }, - { FALSE, &data2, L"/ifd/{str=xmp}:{uint=4}", S_OK, 5, 6, NULL }, + { FALSE, &data2, L"/ifd/xmp:{long=4}", S_OK, VT_I4, 6, NULL }, + { FALSE, &data2, L"/ifd/{str=xmp}:{uint=4}", S_OK, VT_I4, 6, NULL }, { FALSE, &data3, L"/xmp/{char=7}", 0xdeadbeef }, - { FALSE, &data3, L"/[1]xmp/{short=7}", S_OK, 8, 9, NULL }, + { FALSE, &data3, L"/[1]xmp/{short=7}", S_OK, VT_UI4, 9, NULL }, { FALSE, &data3, L"/[1]ifd/{str=dc}:{uint=7}", 0xdeadbeef }, - { FALSE, &data3, L"/[1]ifd/{str=http://purl.org/dc/elements/1.1/%7D:%7Blonglong=7%7D", S_OK, 8, 9, NULL }, + { FALSE, &data3, L"/[1]ifd/{str=http://purl.org/dc/elements/1.1/%7D:%7Blonglong=7%7D", S_OK, VT_UI4, 9, NULL }, { FALSE, &data3, L"/[1]ifd/{str=http://ns.adobe.com/tiff/1.0/%7D:%7Bint=10%7D", S_OK, 11, 12, NULL }, - { FALSE, &data3, L"/[2]xmp/xmp:{ulong=4}", S_OK, 5, 6, NULL }, + { FALSE, &data3, L"/[2]xmp/xmp:{ulong=4}", S_OK, VT_I4, 6, NULL }, { FALSE, &data3, L"/[2]xmp/{str=xmp}:{ulong=4}", 0xdeadbeef },
{ FALSE, &data3, L"/xmp", S_OK, VT_UNKNOWN, 0, NULL }, @@ -3991,7 +4026,6 @@ static void test_queryreader(void) ok(hr == E_INVALIDARG, "got %#lx\n", hr);
IWICMetadataQueryReader_Release(new_reader); - PropVariantClear(&value); } else if (value.vt == VT_LPSTR) ok(!lstrcmpA(value.pszVal, test_data[i].str_value), "Expected %s, got %s.\n", @@ -4001,9 +4035,7 @@ static void test_queryreader(void) test_data[i].value, value.uiVal); }
- /* - * Do NOT call PropVariantClear(&value) for fake value types. - */ + PropVariantClear(&value); }
IWICMetadataQueryReader_Release(reader); @@ -4208,14 +4240,21 @@ app1_data = static void test_metadata_App1(void) { IWICMetadataReader *reader, *ifd_reader, *exif_reader, *gps_reader; + IWICMetadataQueryReader *query_reader, *query_reader2; IWICEnumMetadataItem *enumerator; IStream *app1_stream, *stream2; + IWICComponentFactory *factory; IWICMetadataWriter *writer; PROPVARIANT id, value; + UINT length, count; + WCHAR path[64]; ULONG fetched; GUID format; HRESULT hr; - UINT count; + + hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICComponentFactory, (void **)&factory); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
hr = CoCreateInstance(&CLSID_WICApp1MetadataReader, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataReader, (void **)&reader); @@ -4406,6 +4445,131 @@ static void test_metadata_App1(void) IWICMetadataReader_Release(ifd_reader);
IStream_Release(app1_stream); + + /* Query reader. */ + hr = create_query_reader_from_metadata_reader(factory, reader, &GUID_ContainerFormatJpeg, &query_reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataQueryReader_GetLocation(query_reader, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1", &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value); + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/gps", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/gps"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/exif", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/exif"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/exif/{ushort=512}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 444, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/gps/{ushort=768}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 555, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=256}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI4, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 222, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=34665}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=34853}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + PropVariantClear(&value); + } + + IWICMetadataQueryReader_Release(query_reader); IWICMetadataReader_Release(reader);
hr = CoCreateInstance(&CLSID_WICApp1MetadataWriter, NULL, CLSCTX_INPROC_SERVER, @@ -4420,6 +4584,8 @@ static void test_metadata_App1(void) check_interface(writer, &IID_IWICStreamProvider, TRUE);
IWICMetadataWriter_Release(writer); + + IWICComponentFactory_Release(factory); }
static void test_CreateMetadataWriterFromReader(void)
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/tests/metadata.c | 163 +++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 5 deletions(-)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 9cdabca8674..a1dd95c732b 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -3707,10 +3707,19 @@ static HRESULT WINAPI test_block_writer_InitializeFromBlockReader(IWICMetadataBl }
static HRESULT WINAPI test_block_writer_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index, - IWICMetadataWriter **writer) + IWICMetadataWriter **out) { - ok(0, "not implemented\n"); - return E_NOTIMPL; + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + + *out = NULL; + + if (index >= writer->count) + return E_INVALIDARG; + + *out = writer->writers[index]; + IWICMetadataWriter_AddRef(*out); + + return S_OK; }
static HRESULT WINAPI test_block_writer_AddWriter(IWICMetadataBlockWriter *iface, @@ -3842,7 +3851,7 @@ static const struct metadata data3 = };
static HRESULT create_query_reader_from_metadata_reader(IWICComponentFactory *factory, IWICMetadataReader *metadata_reader, - const GUID *container_format, IWICMetadataQueryReader **reader) + const GUID *container_format, IWICMetadataQueryReader **query_reader) { IWICMetadataBlockWriter *block_writer = NULL; IWICMetadataWriter *writer; @@ -3858,7 +3867,33 @@ static HRESULT create_query_reader_from_metadata_reader(IWICComponentFactory *fa
if (SUCCEEDED(hr)) hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, - (IWICMetadataBlockReader *)block_writer, reader); + (IWICMetadataBlockReader *)block_writer, query_reader); + + if (writer) + IWICMetadataWriter_Release(writer); + if (block_writer) + IWICMetadataBlockWriter_Release(block_writer); + + return hr; +} + +static HRESULT create_query_writer_from_metadata_reader(IWICComponentFactory *factory, IWICMetadataReader *metadata_reader, + const GUID *container_format, IWICMetadataQueryWriter **query_writer) +{ + IWICMetadataBlockWriter *block_writer = NULL; + IWICMetadataWriter *writer; + HRESULT hr; + + hr = IWICComponentFactory_CreateMetadataWriterFromReader(factory, metadata_reader, NULL, &writer); + + if (SUCCEEDED(hr)) + hr = create_test_block_writer(container_format, &block_writer); + + if (SUCCEEDED(hr)) + hr = IWICMetadataBlockWriter_AddWriter(block_writer, writer); + + if (SUCCEEDED(hr)) + hr = IWICComponentFactory_CreateQueryWriterFromBlockWriter(factory, block_writer, query_writer);
if (writer) IWICMetadataWriter_Release(writer); @@ -4241,6 +4276,7 @@ static void test_metadata_App1(void) { IWICMetadataReader *reader, *ifd_reader, *exif_reader, *gps_reader; IWICMetadataQueryReader *query_reader, *query_reader2; + IWICMetadataQueryWriter *query_writer, *query_writer2; IWICEnumMetadataItem *enumerator; IStream *app1_stream, *stream2; IWICComponentFactory *factory; @@ -4570,6 +4606,123 @@ static void test_metadata_App1(void) }
IWICMetadataQueryReader_Release(query_reader); + + /* Same queries using the query writer API. */ + hr = create_query_writer_from_metadata_reader(factory, reader, &GUID_ContainerFormatJpeg, &query_writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + check_interface(value.punkVal, &IID_IWICMetadataQueryWriter, TRUE); + + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryWriter, (void **)&query_writer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryWriter_GetLocation(query_writer2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryWriter_Release(query_writer2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryWriter, (void **)&query_writer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryWriter_GetLocation(query_writer2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryWriter_Release(query_writer2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/gps", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryWriter, (void **)&query_writer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryWriter_GetLocation(query_writer2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/gps"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryWriter_Release(query_writer2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/exif", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryWriter, (void **)&query_writer2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryWriter_GetLocation(query_writer2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/exif"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryWriter_Release(query_writer2); + PropVariantClear(&value); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/exif/{ushort=512}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 444, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/gps/{ushort=768}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 555, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/{ushort=256}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UI4, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 222, "Unexpected value %lu.\n", value.ulVal); + } + + PropVariantInit(&value); + hr = IWICMetadataQueryWriter_GetMetadataByName(query_writer, L"/app1/ifd/{ushort=34665}", &value); + todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + check_interface(value.punkVal, &IID_IWICMetadataQueryWriter, TRUE); + PropVariantClear(&value); + } + + IWICMetadataQueryWriter_Release(query_writer); + IWICMetadataReader_Release(reader);
hr = CoCreateInstance(&CLSID_WICApp1MetadataWriter, NULL, CLSCTX_INPROC_SERVER,
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/metadatahandler.c | 30 +++++++ dlls/windowscodecs/tests/metadata.c | 121 ++++++++++++--------------- 2 files changed, 82 insertions(+), 69 deletions(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index 18ef6419eb4..a7c5612b447 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -230,8 +230,38 @@ static HRESULT WINAPI MetadataHandler_GetValueByIndex(IWICMetadataWriter *iface, static MetadataItem *metadatahandler_get_item(MetadataHandler *handler, const PROPVARIANT *schema, const PROPVARIANT *id) { + PROPVARIANT index; + GUID format; + HRESULT hr; UINT i;
+ PropVariantInit(&index); + if (id->vt == VT_CLSID && SUCCEEDED(PropVariantChangeType(&index, schema, 0, VT_UI4))) + { + for (i = 0; i < handler->item_count; i++) + { + PROPVARIANT *value = &handler->items[i].value; + IWICMetadataReader *reader; + + if (value->vt != VT_UNKNOWN) continue; + + if (SUCCEEDED(IUnknown_QueryInterface(value->punkVal, &IID_IWICMetadataReader, (void **)&reader))) + { + hr = IWICMetadataReader_GetMetadataFormat(reader, &format); + IWICMetadataReader_Release(reader); + + if (SUCCEEDED(hr)) + { + if (IsEqualGUID(&format, id->puuid)) + { + if (!index.ulVal) return &handler->items[i]; + --index.ulVal; + } + } + } + } + } + for (i = 0; i < handler->item_count; i++) { if (schema && handler->items[i].schema.vt != VT_EMPTY) diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index a1dd95c732b..fe4dc41255e 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -4280,8 +4280,8 @@ static void test_metadata_App1(void) IWICEnumMetadataItem *enumerator; IStream *app1_stream, *stream2; IWICComponentFactory *factory; + PROPVARIANT schema, id, value; IWICMetadataWriter *writer; - PROPVARIANT id, value; UINT length, count; WCHAR path[64]; ULONG fetched; @@ -4400,6 +4400,19 @@ static void test_metadata_App1(void) ok(value.vt == VT_UI4, "Unexpected value type: %u.\n", value.vt); ok(value.ulVal == 333, "Unexpected value %lu.\n", value.ulVal);
+ /* Nested handlers are accessible by format GUIDs. */ + PropVariantInit(&schema); + PropVariantInit(&id); + PropVariantInit(&value); + InitPropVariantFromCLSID(&GUID_MetadataFormatExif, &id); + hr = IWICMetadataReader_GetValue(ifd_reader, &schema, &id, &value); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataReader, (void **)&exif_reader); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + PropVariantClear(&value); + PropVariantClear(&id); + PropVariantInit(&id); PropVariantInit(&value); hr = IWICMetadataReader_GetValueByIndex(ifd_reader, 2, NULL, &id, &value); @@ -4507,103 +4520,73 @@ static void test_metadata_App1(void)
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); - hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!lstrcmpW(path, L"/app1/ifd"), "Unexpected path %s.\n", wine_dbgstr_w(path)); - IWICMetadataQueryReader_Release(query_reader2); - PropVariantClear(&value); - } + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/gps", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); - hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!lstrcmpW(path, L"/app1/ifd/gps"), "Unexpected path %s.\n", wine_dbgstr_w(path)); - IWICMetadataQueryReader_Release(query_reader2); - PropVariantClear(&value); - } + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/gps"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/exif", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); - hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(!lstrcmpW(path, L"/app1/ifd/exif"), "Unexpected path %s.\n", wine_dbgstr_w(path)); - IWICMetadataQueryReader_Release(query_reader2); - PropVariantClear(&value); - } + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&query_reader2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IWICMetadataQueryReader_GetLocation(query_reader2, ARRAY_SIZE(path), path, &length); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(path, L"/app1/ifd/exif"), "Unexpected path %s.\n", wine_dbgstr_w(path)); + IWICMetadataQueryReader_Release(query_reader2); + PropVariantClear(&value);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/exif/{ushort=512}", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); - ok(value.ulVal == 444, "Unexpected value %lu.\n", value.ulVal); - } + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 444, "Unexpected value %lu.\n", value.ulVal);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/gps/{ushort=768}", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); - ok(value.ulVal == 555, "Unexpected value %lu.\n", value.ulVal); - } + ok(value.vt == VT_UI2, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 555, "Unexpected value %lu.\n", value.ulVal);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=256}", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UI4, "Unexpected value type: %u.\n", value.vt); - ok(value.ulVal == 222, "Unexpected value %lu.\n", value.ulVal); - } + ok(value.vt == VT_UI4, "Unexpected value type: %u.\n", value.vt); + ok(value.ulVal == 222, "Unexpected value %lu.\n", value.ulVal);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=34665}", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); - check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); - PropVariantClear(&value); - } + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + todo_wine + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + PropVariantClear(&value);
PropVariantInit(&value); hr = IWICMetadataQueryReader_GetMetadataByName(query_reader, L"/app1/ifd/{ushort=34853}", &value); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - if (hr == S_OK) - { - ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); - check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); - PropVariantClear(&value); - } + ok(value.vt == VT_UNKNOWN, "Unexpected value type: %u.\n", value.vt); + todo_wine + check_interface(value.punkVal, &IID_IWICMetadataQueryReader, TRUE); + PropVariantClear(&value);
IWICMetadataQueryReader_Release(query_reader);
From: Nikolay Sivov nsivov@codeweavers.com
--- dlls/windowscodecs/tests/metadata.c | 200 +++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 3 deletions(-)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index fe4dc41255e..70d6d29888b 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -3619,11 +3619,26 @@ struct test_block_writer GUID container_format; };
+struct test_block_enumerator +{ + IEnumUnknown IEnumUnknown_iface; + LONG refcount; + + IUnknown **objects; + unsigned int count; + unsigned int pos; +}; + static inline struct test_block_writer *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface) { return CONTAINING_RECORD(iface, struct test_block_writer, IWICMetadataBlockWriter_iface); }
+static inline struct test_block_enumerator *impl_from_IEnumUnknown(IEnumUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct test_block_enumerator, IEnumUnknown_iface); +} + static HRESULT WINAPI test_block_writer_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **out) { if (IsEqualIID(iid, &IID_IUnknown) || @@ -3693,12 +3708,116 @@ static HRESULT WINAPI test_block_writer_GetReaderByIndex(IWICMetadataBlockWriter return S_OK; }
-static HRESULT WINAPI test_block_writer_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enumerator) +static HRESULT WINAPI test_block_enumerator_QueryInterface(IEnumUnknown *iface, REFIID riid, void **obj) { - ok(0, "not implemented\n"); + 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 test_block_enumerator_AddRef(IEnumUnknown *iface) +{ + struct test_block_enumerator *enumerator = impl_from_IEnumUnknown(iface); + return InterlockedIncrement(&enumerator->refcount); +} + +static ULONG WINAPI test_block_enumerator_Release(IEnumUnknown *iface) +{ + struct test_block_enumerator *enumerator = impl_from_IEnumUnknown(iface); + ULONG refcount = InterlockedDecrement(&enumerator->refcount); + + if (!refcount) + { + for (int i = 0; i < enumerator->count; ++i) + IUnknown_Release(enumerator->objects[i]); + free(enumerator->objects); + free(enumerator); + } + + return refcount; +} + +static HRESULT WINAPI test_block_enumerator_Next(IEnumUnknown *iface, ULONG count, IUnknown **ret, ULONG *fetched) +{ + struct test_block_enumerator *enumerator = impl_from_IEnumUnknown(iface); + ULONG tmp; + + if (!fetched) fetched = &tmp; + + *fetched = 0; + + while (enumerator->pos < enumerator->count && *fetched < count) + { + *ret = enumerator->objects[enumerator->pos++]; + IUnknown_AddRef(*ret); + + *fetched = *fetched + 1; + ret++; + } + + return *fetched == count ? S_OK : S_FALSE; +} + +static HRESULT WINAPI test_block_enumerator_Skip(IEnumUnknown *iface, ULONG count) +{ + ok(0, "%s\n", __FUNCTION__); + return E_NOTIMPL; +} + +static HRESULT WINAPI test_block_enumerator_Reset(IEnumUnknown *iface) +{ + ok(0, "%s\n", __FUNCTION__); return E_NOTIMPL; }
+static HRESULT WINAPI test_block_enumerator_Clone(IEnumUnknown *iface, IEnumUnknown **ret) +{ + ok(0, "%s\n", __FUNCTION__); + return E_NOTIMPL; +} + +static const IEnumUnknownVtbl test_block_enumerator_vtbl = +{ + test_block_enumerator_QueryInterface, + test_block_enumerator_AddRef, + test_block_enumerator_Release, + test_block_enumerator_Next, + test_block_enumerator_Skip, + test_block_enumerator_Reset, + test_block_enumerator_Clone, +}; + +static HRESULT WINAPI test_block_writer_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enumerator) +{ + struct test_block_writer *writer = impl_from_IWICMetadataBlockWriter(iface); + struct test_block_enumerator *object; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IEnumUnknown_iface.lpVtbl = &test_block_enumerator_vtbl; + object->refcount = 1; + object->objects = calloc(writer->count, sizeof(*object->objects)); + object->count = writer->count; + + for (int i = 0; i < writer->count; ++i) + { + object->objects[i] = (IUnknown *)writer->writers[i]; + IUnknown_AddRef(object->objects[i]); + } + + *enumerator = &object->IEnumUnknown_iface; + + return S_OK; +} + static HRESULT WINAPI test_block_writer_InitializeFromBlockReader(IWICMetadataBlockWriter *iface, IWICMetadataBlockReader *reader) { @@ -4102,14 +4221,20 @@ static void test_metadata_query_writer(void)
IWICMetadataQueryWriter *querywriter, *querywriter2; IWICMetadataBlockWriter *blockwriter; + IWICMetadataWriter *metadata_writer; IWICBitmapFrameEncode *frameencode; + IWICMetadataWriter *app1_writer; IWICComponentFactory *factory; IWICBitmapEncoder *encoder; + ULONG ref, count, fetched; + IEnumUnknown *block_enum; IEnumString *enumstring; + IUnknown *objects[1]; LPOLESTR olestring; - ULONG ref, count; + UINT block_count; IStream *stream; unsigned int i; + GUID format; HRESULT hr;
for (i = 0; i < ARRAY_SIZE(tests); ++i) @@ -4215,6 +4340,75 @@ static void test_metadata_query_writer(void)
winetest_pop_context(); } + + /* Block enumerator behavior. */ + hr = CoCreateInstance(&CLSID_WICJpegEncoder, NULL, CLSCTX_INPROC_SERVER, &IID_IWICBitmapEncoder, (void **)&encoder); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICBitmapFrameEncode_QueryInterface(frameencode, &IID_IWICMetadataBlockWriter, (void **)&blockwriter); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICBitmapFrameEncode_Initialize(frameencode, NULL); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = IWICMetadataBlockWriter_GetEnumerator(blockwriter, &block_enum); + todo_wine + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + +if (SUCCEEDED(hr)) +{ + hr = IEnumUnknown_Next(block_enum, 1, objects, &fetched); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + IUnknown_Release(*objects); + + hr = IWICMetadataBlockWriter_GetCount(blockwriter, &block_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(block_count == 1, "Unexpected block count %u.\n", block_count); + hr = IWICMetadataBlockWriter_GetWriterByIndex(blockwriter, 0, &metadata_writer); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICMetadataWriter_GetMetadataFormat(metadata_writer, &format); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(IsEqualGUID(&format, &GUID_MetadataFormatApp0), "Unexpected format %s.\n", debugstr_guid(&format)); + IWICMetadataWriter_Release(metadata_writer); + + hr = CoCreateInstance(&CLSID_WICApp1MetadataWriter, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICMetadataWriter, (void **)&app1_writer); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IWICMetadataBlockWriter_AddWriter(blockwriter, app1_writer); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IWICMetadataBlockWriter_GetCount(blockwriter, &block_count); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(block_count == 2, "Unexpected block count %u.\n", block_count); + + /* Newly added object is not picked up. */ + hr = IEnumUnknown_Next(block_enum, 1, objects, &fetched); + ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr); + ok(!fetched, "Unexpected count %lu.\n", fetched); + + hr = IEnumUnknown_Reset(block_enum); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IEnumUnknown_Next(block_enum, 1, objects, &fetched); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + IUnknown_Release(*objects); + hr = IEnumUnknown_Next(block_enum, 1, objects, &fetched); + ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr); + + IEnumUnknown_Release(block_enum); + IWICMetadataWriter_Release(app1_writer); +} + IWICMetadataBlockWriter_Release(blockwriter); + + IWICBitmapFrameEncode_Release(frameencode); + IWICBitmapEncoder_Release(encoder); + IStream_Release(stream); }
#include "pshpack2.h"
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/tests/metadata.c | 125 +++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 70d6d29888b..ee9750eb96c 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -102,6 +102,107 @@ static void compare_blob_(unsigned int line, const PROPVARIANT *propvar, const c } }
+static void test_block_reader_enumerator(IWICMetadataBlockReader *block_reader) +{ + IEnumUnknown *block_enum, *block_enum2; + IUnknown *object, *object2; + UINT block_count; + ULONG fetched; + 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); + ok(block_enum != block_enum2, "Unexpected instance.\n"); + + hr = IWICMetadataBlockReader_GetCount(block_reader, &block_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(block_count > 0, "Unexpected block count %u.\n", block_count); + + fetched = 0; + hr = IEnumUnknown_Next(block_enum, 1, &object, &fetched); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + + fetched = 0; + hr = IEnumUnknown_Next(block_enum2, 1, &object2, &fetched); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + ok(object == object2, "Unexpected instance.\n"); + IUnknown_Release(object2); + + hr = IEnumUnknown_Reset(block_enum2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + fetched = 0; + hr = IEnumUnknown_Next(block_enum2, 1, &object2, &fetched); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + ok(object == object2, "Unexpected instance.\n"); + IUnknown_Release(object2); + + IEnumUnknown_Release(block_enum2); + + /* Cloning. */ + hr = IEnumUnknown_Clone(block_enum, NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = IEnumUnknown_Clone(block_enum, &block_enum2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* The cloned object inherits cursor value. */ + fetched = 0; + hr = IEnumUnknown_Next(block_enum2, 1, &object2, &fetched); + ok(SUCCEEDED(hr), "Unexpected hr %#lx.\n", hr); + if (hr == S_OK) + { + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + ok(object != object2, "Unexpected instance.\n"); + IUnknown_Release(object2); + } + else + { + ok(!fetched, "Unexpected count %lu.\n", fetched); + } + IEnumUnknown_Release(block_enum2); + + /* Skipping. */ + hr = IEnumUnknown_Skip(block_enum, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IEnumUnknown_Reset(block_enum); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IEnumUnknown_Skip(block_enum, block_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IEnumUnknown_Reset(block_enum); + 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); + fetched = 0; + hr = IEnumUnknown_Next(block_enum, 1, &object2, &fetched); + ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr); + ok(!fetched, "Unexpected count %lu.\n", fetched); + hr = IEnumUnknown_Reset(block_enum); + ok(hr == S_OK, "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_OK, "Unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + ok(object == object2, "Unexpected instance.\n"); + IUnknown_Release(object2); + + IUnknown_Release(object); + IEnumUnknown_Release(block_enum); +} + enum ifd_entry_type { IFD_BYTE = 1, @@ -1853,6 +1954,10 @@ static void test_metadata_png(void)
if (SUCCEEDED(hr)) { + winetest_push_context("png"); + test_block_reader_enumerator(blockreader); + winetest_pop_context(); + hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL); ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%lx\n", hr);
@@ -2038,6 +2143,10 @@ static void test_metadata_gif(void)
if (SUCCEEDED(hr)) { + winetest_push_context("gif"); + test_block_reader_enumerator(blockreader); + winetest_pop_context(); + hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format); ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr); ok(IsEqualGUID(&format, &GUID_ContainerFormatGif), @@ -4220,6 +4329,7 @@ static void test_metadata_query_writer(void) };
IWICMetadataQueryWriter *querywriter, *querywriter2; + IEnumUnknown *block_enum, *block_enum2; IWICMetadataBlockWriter *blockwriter; IWICMetadataWriter *metadata_writer; IWICBitmapFrameEncode *frameencode; @@ -4227,7 +4337,6 @@ static void test_metadata_query_writer(void) IWICComponentFactory *factory; IWICBitmapEncoder *encoder; ULONG ref, count, fetched; - IEnumUnknown *block_enum; IEnumString *enumstring; IUnknown *objects[1]; LPOLESTR olestring; @@ -4401,7 +4510,21 @@ if (SUCCEEDED(hr)) hr = IEnumUnknown_Next(block_enum, 1, objects, &fetched); ok(hr == S_FALSE, "Got unexpected hr %#lx.\n", hr);
+ /* Cloning. */ + hr = IEnumUnknown_Clone(block_enum, NULL); + ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr); + + hr = IEnumUnknown_Clone(block_enum, &block_enum2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + fetched = 0; + hr = IEnumUnknown_Next(block_enum2, 1, objects, &fetched); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + ok(fetched == 1, "Unexpected count %lu.\n", fetched); + IUnknown_Release(*objects); + IEnumUnknown_Release(block_enum); + IEnumUnknown_Release(block_enum2); IWICMetadataWriter_Release(app1_writer); } IWICMetadataBlockWriter_Release(blockwriter);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/windowscodecs/metadatahandler.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c index a7c5612b447..1fd2730390f 100644 --- a/dlls/windowscodecs/metadatahandler.c +++ b/dlls/windowscodecs/metadatahandler.c @@ -698,7 +698,7 @@ static HRESULT WINAPI MetadataHandlerEnum_Next(IWICEnumMetadataItem *iface, ULONG i; ULONG fetched;
- TRACE("(%p,%li)\n", iface, celt); + TRACE("%p, %lu, %p, %p, %p, %p.\n", iface, celt, rgeltSchema, rgeltId, rgeltValue, pceltFetched);
if (!pceltFetched) pceltFetched = &fetched; @@ -745,6 +745,8 @@ static HRESULT WINAPI MetadataHandlerEnum_Skip(IWICEnumMetadataItem *iface, { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
+ TRACE("%p, %lu.\n", iface, celt); + EnterCriticalSection(&This->parent->lock);
This->index += celt; @@ -758,6 +760,8 @@ static HRESULT WINAPI MetadataHandlerEnum_Reset(IWICEnumMetadataItem *iface) { MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface);
+ TRACE("%p.\n", iface); + EnterCriticalSection(&This->parent->lock);
This->index = 0; @@ -773,6 +777,8 @@ static HRESULT WINAPI MetadataHandlerEnum_Clone(IWICEnumMetadataItem *iface, MetadataHandlerEnum *This = impl_from_IWICEnumMetadataItem(iface); HRESULT hr;
+ TRACE("%p, %p.\n", iface, ppIEnumMetadataItem); + EnterCriticalSection(&This->parent->lock);
hr = MetadataHandlerEnum_Create(This->parent, This->index, ppIEnumMetadataItem);
This merge request was approved by Esme Povirk.