Author: akhaldi
Date: Sun Sep 24 11:19:20 2017
New Revision: 75954
URL:
http://svn.reactos.org/svn/reactos?rev=75954&view=rev
Log:
[WINDOWSCODECS_WINETEST] Sync with Wine Staging 2.16. CORE-13762
Modified:
trunk/rostests/winetests/windowscodecs/CMakeLists.txt
trunk/rostests/winetests/windowscodecs/converter.c
trunk/rostests/winetests/windowscodecs/metadata.c
Modified: trunk/rostests/winetests/windowscodecs/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/windowscodecs/C…
==============================================================================
--- trunk/rostests/winetests/windowscodecs/CMakeLists.txt [iso-8859-1] (original)
+++ trunk/rostests/winetests/windowscodecs/CMakeLists.txt [iso-8859-1] Sun Sep 24 11:19:20
2017
@@ -18,7 +18,7 @@
add_executable(windowscodecs_winetest ${SOURCE})
set_module_type(windowscodecs_winetest win32cui)
-add_importlibs(windowscodecs_winetest windowscodecs oleaut32 ole32 user32 gdi32 shlwapi
msvcrt kernel32)
+add_importlibs(windowscodecs_winetest windowscodecs oleaut32 ole32 propsys user32 gdi32
shlwapi msvcrt kernel32)
if(MSVC)
add_importlibs(windowscodecs_winetest ntdll)
Modified: trunk/rostests/winetests/windowscodecs/converter.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/windowscodecs/c…
==============================================================================
--- trunk/rostests/winetests/windowscodecs/converter.c [iso-8859-1] (original)
+++ trunk/rostests/winetests/windowscodecs/converter.c [iso-8859-1] Sun Sep 24 11:19:20
2017
@@ -54,6 +54,9 @@
const bitmap_data *data;
} BitmapTestSrc;
+extern HRESULT STDMETHODCALLTYPE
IWICBitmapFrameEncode_WriteSource_Proxy(IWICBitmapFrameEncode* This,
+ IWICBitmapSource *pIBitmapSource, WICRect *prc);
+
static BOOL near_equal(float a, float b)
{
return fabsf(a - b) < 0.001;
@@ -631,6 +634,12 @@
static const WCHAR wszCompressionQuality[] =
{'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
static const WCHAR wszInterlaceOption[] =
{'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
static const WCHAR wszFilterOption[] =
{'F','i','l','t','e','r','O','p','t','i','o','n',0};
+static const WCHAR wszImageQuality[] =
{'I','m','a','g','e','Q','u','a','l','i','t','y',0};
+static const WCHAR wszBitmapTransform[] =
{'B','i','t','m','a','p','T','r','a','n','s','f','o','r','m',0};
+static const WCHAR wszLuminance[] =
{'L','u','m','i','n','a','n','c','e',0};
+static const WCHAR wszChrominance[] =
{'C','h','r','o','m','i','n','a','n','c','e',0};
+static const WCHAR wszJpegYCrCbSubsampling[] =
{'J','p','e','g','Y','C','r','C','b','S','u','b','s','a','m','p','l','i','n','g',0};
+static const WCHAR wszSuppressApp0[] =
{'S','u','p','p','r','e','s','s','A','p','p','0',0};
static const struct property_opt_test_data testdata_tiff_props[] = {
{ wszTiffCompressionMethod, VT_UI1, VT_UI1, WICTiffCompressionDontCare },
@@ -641,6 +650,16 @@
static const struct property_opt_test_data testdata_png_props[] = {
{ wszInterlaceOption, VT_BOOL, VT_BOOL, 0 },
{ wszFilterOption, VT_UI1, VT_UI1, WICPngFilterUnspecified, 0.0f, TRUE /* not
supported on XP/2k3 */},
+ { NULL }
+};
+
+static const struct property_opt_test_data testdata_jpeg_props[] = {
+ { wszImageQuality, VT_R4, VT_EMPTY },
+ { wszBitmapTransform, VT_UI1, VT_UI1, WICBitmapTransformRotate0 },
+ { wszLuminance, VT_I4|VT_ARRAY, VT_EMPTY },
+ { wszChrominance, VT_I4|VT_ARRAY, VT_EMPTY },
+ { wszJpegYCrCbSubsampling, VT_UI1, VT_UI1, WICJpegYCrCbSubsamplingDefault,
0.0f, TRUE }, /* not supported on XP/2k3 */
+ { wszSuppressApp0, VT_BOOL, VT_BOOL, FALSE },
{ NULL }
};
@@ -768,6 +787,8 @@
test_specific_encoder_properties(options, testdata_tiff_props, all_props,
cProperties2);
else if (IsEqualCLSID(clsid_encoder, &CLSID_WICPngEncoder))
test_specific_encoder_properties(options, testdata_png_props, all_props,
cProperties2);
+ else if (IsEqualCLSID(clsid_encoder, &CLSID_WICJpegEncoder))
+ test_specific_encoder_properties(options, testdata_jpeg_props, all_props,
cProperties2);
for (i=0; i < cProperties2; i++)
{
@@ -1367,6 +1388,13 @@
DeleteTestBitmap(src_obj);
i++;
+ }
+
+ if (clsid_decoder == NULL)
+ {
+ IStream_Release(stream);
+ IWICBitmapEncoder_Release(encoder);
+ return;
}
if (SUCCEEDED(hr))
@@ -1869,6 +1897,9 @@
test_encoder(&testdata_24bppBGR, &CLSID_WICTiffEncoder,
&testdata_24bppBGR, &CLSID_WICTiffDecoder, "TIFF encoder
24bppBGR");
+ test_encoder(&testdata_24bppBGR, &CLSID_WICJpegEncoder,
+ &testdata_24bppBGR, NULL, "JPEG encoder 24bppBGR");
+
test_multi_encoder(multiple_frames, &CLSID_WICTiffEncoder,
multiple_frames, &CLSID_WICTiffDecoder, NULL, NULL, "TIFF
encoder multi-frame", NULL);
Modified: trunk/rostests/winetests/windowscodecs/metadata.c
URL:
http://svn.reactos.org/svn/reactos/trunk/rostests/winetests/windowscodecs/m…
==============================================================================
--- trunk/rostests/winetests/windowscodecs/metadata.c [iso-8859-1] (original)
+++ trunk/rostests/winetests/windowscodecs/metadata.c [iso-8859-1] Sun Sep 24 11:19:20
2017
@@ -30,10 +30,16 @@
#include <windef.h>
#include <winbase.h>
+#include <winnls.h>
+#include <winreg.h>
#include <ole2.h>
//#include "wincodec.h"
#include <wincodecsdk.h>
+#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_blob(propvar, data, length) do { \
ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
@@ -1552,13 +1558,207 @@
IWICMetadataBlockReader_Release(blockreader);
}
+ hr = IWICBitmapDecoder_GetMetadataQueryReader(decoder, &queryreader);
+ ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
+ "GetMetadataQueryReader error %#x\n", hr);
+ if (SUCCEEDED(hr))
+ {
+ static const struct
+ {
+ const char *query;
+ HRESULT hr;
+ UINT vt;
+ } decoder_data[] =
+ {
+ { "/logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
+ { "/[0]logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
+ { "/logscrdesc/\\Signature", S_OK, VT_UI1 | VT_VECTOR },
+ { "/Logscrdesc/\\signature", S_OK, VT_UI1 | VT_VECTOR },
+ { "/logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/[0]logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/[0]logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/appext/Application", S_OK, VT_UI1 | VT_VECTOR },
+ { "/appext/{STR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/appext/{WSTR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
+ { "/LogSCRdesC", S_OK, VT_UNKNOWN },
+ { "/[0]LogSCRdesC", S_OK, VT_UNKNOWN },
+ { "/appEXT", S_OK, VT_UNKNOWN },
+ { "/[0]appEXT", S_OK, VT_UNKNOWN },
+ { "grctlext", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
+ { "/imgdesc", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
+ };
+ static const WCHAR rootW[] = {'/',0};
+ WCHAR name[256];
+ UINT len, i, j;
+ PROPVARIANT value;
+ IWICMetadataQueryReader *meta_reader;
+
+ hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+
+ name[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == 2, "expected 2, got %u\n", len);
+ ok(!lstrcmpW(name, rootW), "expected '/', got %s\n",
wine_dbgstr_w(name));
+
+ for (i = 0; i < sizeof(decoder_data)/sizeof(decoder_data[0]); i++)
+ {
+ WCHAR queryW[256];
+
+ if (winetest_debug > 1)
+ trace("query: %s\n", decoder_data[i].query);
+ MultiByteToWideChar(CP_ACP, 0, decoder_data[i].query, -1, queryW, 256);
+ PropVariantInit(&value);
+ hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW,
&value);
+ ok(hr == decoder_data[i].hr, "GetMetadataByName(%s) returned %#x,
expected %#x\n", wine_dbgstr_w(queryW), hr, decoder_data[i].hr);
+ ok(value.vt == decoder_data[i].vt, "expected %#x, got %#x\n",
decoder_data[i].vt, value.vt);
+ if (hr == S_OK && value.vt == VT_UNKNOWN)
+ {
+ hr = IUnknown_QueryInterface(value.punkVal,
&IID_IWICMetadataQueryReader, (void **)&meta_reader);
+ ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+ name[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name,
&len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n",
lstrlenW(queryW) + 1, len);
+ ok(!lstrcmpW(name, queryW), "expected %s, got %s\n",
wine_dbgstr_w(queryW), wine_dbgstr_w(name));
+
+ for (j = 0; j < sizeof(decoder_data)/sizeof(decoder_data[0]); j++)
+ {
+ MultiByteToWideChar(CP_ACP, 0, decoder_data[j].query, -1, queryW,
256);
+
+ if (CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, queryW, len-1,
name, len-1) == CSTR_EQUAL && decoder_data[j].query[len - 1] != 0)
+ {
+ if (winetest_debug > 1)
+ trace("query: %s\n", wine_dbgstr_w(queryW + len -
1));
+ PropVariantClear(&value);
+ hr = IWICMetadataQueryReader_GetMetadataByName(meta_reader,
queryW + len - 1, &value);
+ ok(hr == decoder_data[j].hr, "GetMetadataByName(%s) returned
%#x, expected %#x\n", wine_dbgstr_w(queryW + len - 1), hr, decoder_data[j].hr);
+ ok(value.vt == decoder_data[j].vt, "expected %#x, got
%#x\n", decoder_data[j].vt, value.vt);
+ }
+ }
+
+ IWICMetadataQueryReader_Release(meta_reader);
+ }
+
+ PropVariantClear(&value);
+ }
+
+ IWICMetadataQueryReader_Release(queryreader);
+ }
+
hr = IWICBitmapFrameDecode_GetMetadataQueryReader(frame, &queryreader);
- ok(hr == S_OK ||
- broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
- "GetMetadataQueryReader failed: %08x\n", hr);
-
+ ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
+ "GetMetadataQueryReader error %#x\n", hr);
if (SUCCEEDED(hr))
{
+ static const struct
+ {
+ const char *query;
+ HRESULT hr;
+ UINT vt;
+ } frame_data[] =
+ {
+ { "/grctlext/Delay", S_OK, VT_UI2 },
+ { "/[0]grctlext/Delay", S_OK, VT_UI2 },
+ { "/grctlext/{str=delay}", S_OK, VT_UI2 },
+ { "/[0]grctlext/{str=delay}", S_OK, VT_UI2 },
+ { "/grctlext/{wstr=delay}", S_OK, VT_UI2 },
+ { "/[0]grctlext/{wstr=delay}", S_OK, VT_UI2 },
+ { "/imgdesc/InterlaceFlag", S_OK, VT_BOOL },
+ { "/imgdesc/{STR=interlaceFLAG}", S_OK, VT_BOOL },
+ { "/imgdesc/{WSTR=interlaceFLAG}", S_OK, VT_BOOL },
+ { "/grctlext", S_OK, VT_UNKNOWN },
+ { "/[0]grctlext", S_OK, VT_UNKNOWN },
+ { "/imgdesc", S_OK, VT_UNKNOWN },
+ { "/[0]imgdesc", S_OK, VT_UNKNOWN },
+ { "/LogSCRdesC", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
+ { "/appEXT", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
+ { "/grctlext/{\\str=delay}", WINCODEC_ERR_WRONGSTATE, 0 },
+ { "/grctlext/{str=\\delay}", S_OK, VT_UI2 },
+ { "grctlext/Delay", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
+ };
+ static const WCHAR rootW[] = {'/',0};
+ static const WCHAR guidW[] =
{'/','{','g','u','i','d','=','\\',0};
+ static const WCHAR imgdescW[] =
{'i','m','g','d','e','s','c',0};
+ static const WCHAR ImgDescW[] =
{'I','m','g','D','e','s','c',0};
+ WCHAR name[256], queryW[256];
+ UINT len, i;
+ PROPVARIANT value;
+ IWICMetadataQueryReader *meta_reader;
+
+ hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
+ ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
+ "wrong container format %s\n", wine_dbgstr_guid(&format));
+
+ name[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == 2, "expected 2, got %u\n", len);
+ ok(!lstrcmpW(name, rootW), "expected '/', got %s\n",
wine_dbgstr_w(name));
+
+ for (i = 0; i < sizeof(frame_data)/sizeof(frame_data[0]); i++)
+ {
+ if (winetest_debug > 1)
+ trace("query: %s\n", frame_data[i].query);
+ MultiByteToWideChar(CP_ACP, 0, frame_data[i].query, -1, queryW, 256);
+ PropVariantInit(&value);
+ hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW,
&value);
+ ok(hr == frame_data[i].hr, "GetMetadataByName(%s) returned %#x, expected
%#x\n", wine_dbgstr_w(queryW), hr, frame_data[i].hr);
+ ok(value.vt == frame_data[i].vt, "expected %#x, got %#x\n",
frame_data[i].vt, value.vt);
+ if (hr == S_OK && value.vt == VT_UNKNOWN)
+ {
+ hr = IUnknown_QueryInterface(value.punkVal,
&IID_IWICMetadataQueryReader, (void **)&meta_reader);
+ ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+ name[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name,
&len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n",
lstrlenW(queryW) + 1, len);
+ ok(!lstrcmpW(name, queryW), "expected %s, got %s\n",
wine_dbgstr_w(queryW), wine_dbgstr_w(name));
+
+ IWICMetadataQueryReader_Release(meta_reader);
+ }
+
+ PropVariantClear(&value);
+ }
+
+ name[0] = 0;
+ len = 0xdeadbeef;
+ hr = WICMapGuidToShortName(&GUID_MetadataFormatIMD, 256, name, &len);
+ ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
+ ok(!lstrcmpW(name, imgdescW), "wrong short name %s\n",
wine_dbgstr_w(name));
+
+ format = GUID_NULL;
+ hr = WICMapShortNameToGuid(imgdescW, &format);
+ ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid
%s\n", wine_dbgstr_guid(&format));
+
+ format = GUID_NULL;
+ hr = WICMapShortNameToGuid(ImgDescW, &format);
+ ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
+ ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid
%s\n", wine_dbgstr_guid(&format));
+
+ lstrcpyW(queryW, guidW);
+ StringFromGUID2(&GUID_MetadataFormatIMD, queryW + lstrlenW(queryW) - 1, 39);
+ memcpy(queryW, guidW, sizeof(guidW) - 2);
+ if (winetest_debug > 1)
+ trace("query: %s\n", wine_dbgstr_w(queryW));
+ PropVariantInit(&value);
+ hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
+ ok(hr == S_OK, "GetMetadataByName(%s) error %#x\n",
wine_dbgstr_w(queryW), hr);
+ ok(value.vt == VT_UNKNOWN, "expected VT_UNKNOWN, got %#x\n",
value.vt);
+ PropVariantClear(&value);
+
IWICMetadataQueryReader_Release(queryreader);
}
@@ -2252,10 +2452,610 @@
}
}
+struct metadata_item
+{
+ const char *schema, *id_str;
+ UINT id, type, value;
+};
+
+struct metadata_block
+{
+ const GUID *metadata_format;
+ UINT count;
+ const struct metadata_item *item;
+};
+
+struct metadata
+{
+ const GUID *container_format;
+ UINT count;
+ 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)
+{
+ trace("%p,%s,%p\n", iface, wine_dbgstr_guid(iid), out);
+
+ if (IsEqualIID(iid, &IID_IUnknown) ||
+ IsEqualIID(iid, &IID_IWICMetadataReader))
+ {
+ *out = iface;
+ return S_OK;
+ }
+
+ ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid));
+
+ *out = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI mdr_AddRef(IWICMetadataReader *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI mdr_Release(IWICMetadataReader *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI mdr_GetMetadataFormat(IWICMetadataReader *iface, GUID *format)
+{
+ trace("%p,%p\n", iface, format);
+
+ ok(current_metadata_block != NULL, "current_metadata_block can't be
NULL\n");
+ if (!current_metadata_block) return E_POINTER;
+
+ *format = *current_metadata_block->metadata_format;
+ return S_OK;
+}
+
+static HRESULT WINAPI mdr_GetMetadataHandlerInfo(IWICMetadataReader *iface,
IWICMetadataHandlerInfo **handler)
+{
+ ok(0, "not implemented\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI mdr_GetCount(IWICMetadataReader *iface, UINT *count)
+{
+ trace("%p,%p\n", iface, count);
+
+ ok(current_metadata_block != NULL, "current_metadata_block can't be
NULL\n");
+ if (!current_metadata_block) return E_POINTER;
+
+ *count = current_metadata_block->count;
+ return S_OK;
+}
+
+static HRESULT WINAPI mdr_GetValueByIndex(IWICMetadataReader *iface, UINT index,
PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value)
+{
+ ok(0, "not implemented\n");
+ return E_NOTIMPL;
+}
+
+static char *get_temp_buffer(int size)
+{
+ static char buf[16][256];
+ static int idx;
+ char *p;
+
+ assert(size < 256);
+
+ p = buf[idx & 0x0f];
+ idx++;
+ return p;
+}
+
+static const char *wine_dbgstr_propvariant(const PROPVARIANT *var)
+{
+ char *ret;
+
+ if (!var) return "(null)";
+
+ switch (var->vt)
+ {
+ case VT_LPWSTR:
+ ret = get_temp_buffer(lstrlenW(U(*var).pwszVal) + 16);
+ sprintf(ret, "(VT_LPWSTR:%s)", wine_dbgstr_w(U(*var).pwszVal));
+ break;
+
+ case VT_LPSTR:
+ ret = get_temp_buffer(lstrlenA(U(*var).pszVal) + 16);
+ sprintf(ret, "(VT_LPSTR:%s)", U(*var).pszVal);
+ break;
+
+ default:
+ ret = get_temp_buffer(16);
+ sprintf(ret, "(vt:%u)", var->vt);
+ break;
+ }
+
+ return ret;
+}
+
+static int propvar_cmp(const PROPVARIANT *v1, LONGLONG value2)
+{
+ LONGLONG value1;
+
+ if (PropVariantToInt64(v1, &value1) != S_OK) return -1;
+
+ value1 -= value2;
+ if (value1) return value1 < 0 ? -1 : 1;
+ return 0;
+}
+
+static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT *schema,
const PROPVARIANT *id, PROPVARIANT *value)
+{
+ UINT i;
+
+ trace("%p,%s,%s,%s\n", iface, wine_dbgstr_propvariant(schema),
wine_dbgstr_propvariant(id), wine_dbgstr_propvariant(value));
+
+ 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++)
+ {
+ if (schema->vt != VT_EMPTY)
+ {
+ if (!current_metadata_block->item[i].schema)
+ continue;
+
+ switch (schema->vt)
+ {
+ case VT_LPSTR:
+ if (lstrcmpA(U(*schema).pszVal,
current_metadata_block->item[i].schema) != 0)
+ continue;
+ break;
+
+ case VT_LPWSTR:
+ {
+ char schemaA[256];
+ WideCharToMultiByte(CP_ACP, 0, U(*schema).pwszVal, -1, schemaA,
sizeof(schemaA), NULL, NULL);
+ if (lstrcmpA(schemaA, current_metadata_block->item[i].schema) != 0)
+ continue;
+ break;
+ }
+
+ default:
+ ok(0, "unsupported schema vt %u\n", schema->vt);
+ continue;
+ }
+ }
+ else if (current_metadata_block->item[i].schema)
+ continue;
+
+ switch (id->vt)
+ {
+ case VT_LPSTR:
+ if (current_metadata_block->item[i].id_str)
+ {
+ if (!lstrcmpA(U(*id).pszVal, current_metadata_block->item[i].id_str))
+ {
+ value->vt = VT_LPSTR;
+ U(*value).pszVal = the_best;
+ return S_OK;
+ }
+ break;
+ }
+ break;
+
+ case VT_LPWSTR:
+ if (current_metadata_block->item[i].id_str)
+ {
+ char idA[256];
+ WideCharToMultiByte(CP_ACP, 0, U(*id).pwszVal, -1, idA, sizeof(idA),
NULL, NULL);
+ if (!lstrcmpA(idA, current_metadata_block->item[i].id_str))
+ {
+ value->vt = VT_LPSTR;
+ U(*value).pszVal = the_worst;
+ return S_OK;
+ }
+ break;
+ }
+ break;
+
+ case VT_CLSID:
+ if (IsEqualGUID(U(*id).puuid, &GUID_MetadataFormatXMP) ||
+ IsEqualGUID(U(*id).puuid, &GUID_ContainerFormatTiff))
+ {
+ value->vt = VT_UNKNOWN;
+ value->punkVal = (IUnknown *)iface;
+ return S_OK;
+ }
+ break;
+
+ default:
+ if (!propvar_cmp(id, current_metadata_block->item[i].id))
+ {
+ value->vt = current_metadata_block->item[i].type;
+ U(*value).uiVal = current_metadata_block->item[i].value;
+ return S_OK;
+ }
+ break;
+ }
+ }
+
+ return 0xdeadbeef;
+}
+
+static HRESULT WINAPI mdr_GetEnumerator(IWICMetadataReader *iface, IWICEnumMetadataItem
**enumerator)
+{
+ ok(0, "not implemented\n");
+ return E_NOTIMPL;
+}
+
+static /* const */ IWICMetadataReaderVtbl mdr_vtbl =
+{
+ mdr_QueryInterface,
+ mdr_AddRef,
+ mdr_Release,
+ mdr_GetMetadataFormat,
+ mdr_GetMetadataHandlerInfo,
+ mdr_GetCount,
+ mdr_GetValueByIndex,
+ mdr_GetValue,
+ mdr_GetEnumerator
+};
+
+static IWICMetadataReader mdr = { &mdr_vtbl };
+
+static HRESULT WINAPI mdbr_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid,
void **out)
+{
+ if (IsEqualIID(iid, &IID_IUnknown) ||
+ IsEqualIID(iid, &IID_IWICMetadataBlockReader))
+ {
+ *out = 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)
+{
+ return 2;
+}
+
+static ULONG WINAPI mdbr_Release(IWICMetadataBlockReader *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI mdbr_GetContainerFormat(IWICMetadataBlockReader *iface, GUID
*format)
+{
+ trace("%p,%p\n", iface, format);
+
+ ok(current_metadata != NULL, "current_metadata can't be NULL\n");
+ if (!current_metadata) return E_POINTER;
+
+ *format = *current_metadata->container_format;
+ return S_OK;
+}
+
+static HRESULT WINAPI mdbr_GetCount(IWICMetadataBlockReader *iface, UINT *count)
+{
+ trace("%p,%p\n", iface, count);
+
+ ok(current_metadata != NULL, "current_metadata can't be NULL\n");
+ if (!current_metadata) return E_POINTER;
+
+ *count = current_metadata->count;
+ return S_OK;
+}
+
+static HRESULT WINAPI mdbr_GetReaderByIndex(IWICMetadataBlockReader *iface, UINT index,
IWICMetadataReader **out)
+{
+ trace("%p,%u,%p\n", iface, index, out);
+
+ *out = NULL;
+
+ ok(current_metadata != NULL, "current_metadata can't be NULL\n");
+ if (!current_metadata) return E_POINTER;
+
+ if (index < current_metadata->count)
+ {
+ current_metadata_block = ¤t_metadata->block[index];
+ *out = &mdr;
+ return S_OK;
+ }
+
+ current_metadata_block = NULL;
+ return E_INVALIDARG;
+}
+
+static HRESULT WINAPI mdbr_GetEnumerator(IWICMetadataBlockReader *iface, IEnumUnknown
**enumerator)
+{
+ ok(0, "not implemented\n");
+ return E_NOTIMPL;
+}
+
+static /* const */ IWICMetadataBlockReaderVtbl mdbr_vtbl =
+{
+ mdbr_QueryInterface,
+ mdbr_AddRef,
+ mdbr_Release,
+ mdbr_GetContainerFormat,
+ mdbr_GetCount,
+ mdbr_GetReaderByIndex,
+ mdbr_GetEnumerator
+};
+
+static IWICMetadataBlockReader mdbr = { &mdbr_vtbl };
+
+static const char xmp[] = "http://ns.adobe.com/xap/1.0/";
+static const char dc[] = "http://purl.org/dc/elements/1.1/";
+static const char tiff[] = "http://ns.adobe.com/tiff/1.0/";
+
+static const struct metadata_item item1[] =
+{
+ { NULL, NULL, 1, 2, 3 }
+};
+
+static const struct metadata_item item2[] =
+{
+ { NULL, NULL, 1, 2, 3 },
+ { "xmp", "Rating", 4, 5, 6 },
+ { NULL, "Rating", 7, 8, 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 }
+};
+
+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 }
+};
+
+static const struct metadata_block block1[] =
+{
+ { &GUID_MetadataFormatIfd, 1, item1 }
+};
+
+static const struct metadata_block block2[] =
+{
+ { &GUID_MetadataFormatXMP, 1, item1 },
+ { &GUID_MetadataFormatIfd, 3, item2 }
+};
+
+static const struct metadata_block block3[] =
+{
+ { &GUID_MetadataFormatXMP, 1, item1 },
+ { &GUID_MetadataFormatIfd, 3, item2 },
+ { &GUID_MetadataFormatXMP, 4, item3 },
+ { &GUID_MetadataFormatXMP, 7, item4 },
+ { &GUID_MetadataFormatIfd, 7, item4 }
+};
+
+static const struct metadata data1 =
+{
+ &GUID_ContainerFormatGif,
+ 1, block1
+};
+
+static const struct metadata data2 =
+{
+ &GUID_ContainerFormatTiff,
+ 2, block2
+};
+
+static const struct metadata data3 =
+{
+ &GUID_ContainerFormatPng,
+ 5, block3
+};
+
+static void test_queryreader(void)
+{
+ static const char q1[] = "/ifd/{uchar=1}";
+ static const char q2[] = "/ifd/xmp:{long=4}";
+ static const char q3[] = "/ifd/{str=xmp}:{uint=4}";
+ static const char q4[] = "/xmp/{char=7}";
+ static const char q5[] = "/[1]xmp/{short=7}";
+ static const char q6[] = "/[1]ifd/{str=dc}:{uint=7}";
+ static const char q7[] =
"/[1]ifd/{str=http://purl.org/dc/elements/1.1/}:{longlong=7}";
+ static const char q8[] =
"/[1]ifd/{str=http://ns.adobe.com/tiff/1.0/}:{int=10}";
+ static const char q9[] = "/[2]xmp/xmp:{ulong=4}";
+ static const char q10[] = "/[2]xmp/{str=xmp}:{ulong=4}";
+ static const char q11[] = "/xmp";
+ static const char q12[] = "/ifd/xmp";
+ static const char q13[] = "/ifd/xmp/tiff";
+ static const char q14[] = "/[0]ifd/[0]xmp/[0]tiff";
+ static const char q15[] = "/[*]xmp";
+
+ static const char q20[] = "/ifd/\\Rating";
+ static const char q21[] = "/[0]ifd/Rating";
+ static const char q22[] = "/[2]xmp/xmp:{str=Rating}";
+ static const char q23[] = "/[2]xmp/xmp:Rating";
+
+ static const char q24[] =
"/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:Rating";
+ static const char q25[] =
"/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:{str=Rating}";
+ static const char q26[] = "/[1]ifd/{wstr=\\RATING}";
+ static const char q27[] = "/[1]ifd/{str=R\\ATING}";
+ static const char q28[] = "/[1]ifd/{str=R\\}ATING}";
+
+ static const char q40[] = "[0]/ifd/Rating";
+ static const char q41[] = "/[+1]ifd/Rating";
+ static const char q42[] = "/[-1]ifd/Rating";
+ static const char q43[] = "/ifd/{\\str=Rating}";
+ static const char q44[] = "/ifd/{badtype=0}";
+ static const char q45[] = "/ifd/{uint=0x1234}";
+ static const char q46[] = "/ifd/[0]Rating";
+ static const char q47[] = "/ifd/[*]Rating";
+ static const struct
+ {
+ BOOL todo;
+ const struct metadata *data;
+ const char *query;
+ HRESULT hr;
+ UINT vt, value;
+ const char *str_value;
+ } test_data[] =
+ {
+ { FALSE, &data1, q1, S_OK, 2, 3, NULL },
+ { FALSE, &data2, q2, S_OK, 5, 6, NULL },
+ { FALSE, &data2, q3, S_OK, 5, 6, NULL },
+ { FALSE, &data3, q4, 0xdeadbeef },
+ { FALSE, &data3, q5, S_OK, 8, 9, NULL },
+ { FALSE, &data3, q6, 0xdeadbeef },
+ { FALSE, &data3, q7, S_OK, 8, 9, NULL },
+ { FALSE, &data3, q8, S_OK, 11, 12, NULL },
+ { FALSE, &data3, q9, S_OK, 5, 6, NULL },
+ { FALSE, &data3, q10, 0xdeadbeef },
+
+ { FALSE, &data3, q11, S_OK, VT_UNKNOWN, 0, NULL },
+ { FALSE, &data3, q12, S_OK, VT_UNKNOWN, 0, NULL },
+ { FALSE, &data3, q13, S_OK, VT_UNKNOWN, 0, NULL },
+ { FALSE, &data3, q14, S_OK, VT_UNKNOWN, 0, NULL },
+ { TRUE, &data3, q15, S_OK, VT_LPSTR, 0, the_worst },
+
+ { FALSE, &data3, q20, S_OK, VT_LPSTR, 0, the_worst },
+ { FALSE, &data3, q21, S_OK, VT_LPSTR, 0, the_worst },
+ { FALSE, &data3, q22, S_OK, VT_LPSTR, 0, the_best },
+ { FALSE, &data3, q23, S_OK, VT_LPSTR, 0, the_worst },
+ { FALSE, &data3, q24, S_OK, VT_LPSTR, 0, the_worst },
+ { FALSE, &data3, q25, S_OK, VT_LPSTR, 0, the_best },
+ { FALSE, &data3, q26, S_OK, VT_LPSTR, 0, the_worst },
+ { FALSE, &data3, q27, S_OK, VT_LPSTR, 0, the_best },
+ { FALSE, &data3, q28, S_OK, VT_LPSTR, 0, the_best },
+
+ { FALSE, &data1, q40, WINCODEC_ERR_PROPERTYNOTSUPPORTED },
+ { TRUE, &data1, q41, WINCODEC_ERR_INVALIDQUERYCHARACTER },
+ { TRUE, &data1, q42, WINCODEC_ERR_INVALIDQUERYCHARACTER },
+ { FALSE, &data1, q43, WINCODEC_ERR_WRONGSTATE },
+ { FALSE, &data1, q44, WINCODEC_ERR_WRONGSTATE },
+ { TRUE, &data1, q45, DISP_E_TYPEMISMATCH },
+ { TRUE, &data1, q46, E_INVALIDARG },
+ { TRUE, &data1, q47, WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT },
+ };
+ WCHAR queryW[256];
+ HRESULT hr;
+ IWICComponentFactory *factory;
+ IWICMetadataQueryReader *reader;
+ GUID format;
+ PROPVARIANT value;
+ UINT i;
+
+ hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IWICComponentFactory, (void **)&factory);
+ ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
+
+ hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &mdbr,
&reader);
+ ok(hr == S_OK, "CreateQueryReaderFromBlockReader error %#x\n", hr);
+
+ for (i = 0; i < sizeof(test_data)/sizeof(test_data[0]); i++)
+ {
+ current_metadata = test_data[i].data;
+
+ hr = IWICMetadataQueryReader_GetContainerFormat(reader, &format);
+ ok(hr == S_OK, "%u: GetContainerFormat error %#x\n", i, hr);
+ ok(IsEqualGUID(&format, test_data[i].data->container_format), "%u:
expected %s, got %s\n",
+ i, wine_dbgstr_guid(test_data[i].data->container_format),
wine_dbgstr_guid(&format));
+
+ MultiByteToWideChar(CP_ACP, 0, test_data[i].query, -1, queryW, 256);
+ PropVariantInit(&value);
+ hr = IWICMetadataQueryReader_GetMetadataByName(reader, queryW, &value);
+ todo_wine_if(test_data[i].todo)
+ ok(hr == test_data[i].hr, "%u: expected %#x, got %#x\n", i,
test_data[i].hr, hr);
+ if (hr == S_OK)
+ {
+ ok(value.vt == test_data[i].vt, "%u: expected %u, got %u\n", i,
test_data[i].vt, value.vt);
+ if (test_data[i].vt == value.vt)
+ {
+ if (value.vt == VT_UNKNOWN)
+ {
+ IWICMetadataQueryReader *new_reader;
+ WCHAR location[256];
+ UINT len;
+
+ hr = IUnknown_QueryInterface(value.punkVal,
&IID_IWICMetadataQueryReader, (void **)&new_reader);
+ ok(hr == S_OK, "QueryInterface error %#x\n", hr);
+
+ location[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location,
&len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n",
lstrlenW(queryW) + 1, len);
+ ok(!lstrcmpW(location, queryW), "expected %s, got %s\n",
wine_dbgstr_w(queryW), wine_dbgstr_w(location));
+
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location,
NULL);
+ ok(hr == E_INVALIDARG, "got %#x\n", hr);
+
+ location[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, location,
&len);
+ ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#x\n",
hr);
+ ok(len == 0xdeadbeef, "got %u\n", len);
+ ok(!location[0], "got %s\n", wine_dbgstr_w(location));
+
+ location[0] = 0;
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, location,
&len);
+ ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#x\n",
hr);
+ ok(len == 0xdeadbeef, "got %u\n", len);
+ ok(!location[0], "got %s\n", wine_dbgstr_w(location));
+
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL,
&len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n",
lstrlenW(queryW) + 1, len);
+
+ len = 0xdeadbeef;
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, NULL,
&len);
+ ok(hr == S_OK, "GetLocation error %#x\n", hr);
+ ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n",
lstrlenW(queryW) + 1, len);
+
+ hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL, NULL);
+ ok(hr == E_INVALIDARG, "got %#x\n", hr);
+
+ IWICMetadataQueryReader_Release(new_reader);
+ }
+ else if (value.vt == VT_LPSTR)
+ ok(!lstrcmpA(U(value).pszVal, test_data[i].str_value), "%u:
expected %s, got %s\n",
+ i, test_data[i].str_value, U(value).pszVal);
+ else
+ ok(U(value).uiVal == test_data[i].value, "%u: expected %u, got
%u\n",
+ i, test_data[i].value, U(value).uiVal);
+ }
+
+ /*
+ * Do NOT call PropVariantClear(&value) for fake value types.
+ */
+ }
+ }
+
+ IWICMetadataQueryReader_Release(reader);
+ IWICComponentFactory_Release(factory);
+}
+
START_TEST(metadata)
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+ test_queryreader();
test_WICMapGuidToShortName();
test_WICMapShortNameToGuid();
test_WICMapSchemaToName();