windowscodecs: Handle IFD fields with count 0 same way as with count 1.
[wine/multimedia.git] / dlls / windowscodecs / tests / metadata.c
blob1936550c41a2bc5244f3ce5850bca40eb3c167b6
1 /*
2 * Copyright 2011 Vincent Povirk for CodeWeavers
3 * Copyright 2012 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <math.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29 #include "wincodecsdk.h"
30 #include "wine/test.h"
32 #define expect_blob(propvar, data, length) do { \
33 ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
34 if ((propvar).vt == VT_BLOB) { \
35 ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
36 if (U(propvar).blob.cbSize == (length)) { \
37 ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
38 } \
39 } \
40 } while (0)
42 #define IFD_BYTE 1
43 #define IFD_ASCII 2
44 #define IFD_SHORT 3
45 #define IFD_LONG 4
46 #define IFD_RATIONAL 5
47 #define IFD_SBYTE 6
48 #define IFD_UNDEFINED 7
49 #define IFD_SSHORT 8
50 #define IFD_SLONG 9
51 #define IFD_SRATIONAL 10
52 #define IFD_FLOAT 11
53 #define IFD_DOUBLE 12
54 #define IFD_IFD 13
56 #include "pshpack2.h"
57 struct IFD_entry
59 SHORT id;
60 SHORT type;
61 ULONG count;
62 LONG value;
65 struct IFD_rational
67 LONG numerator;
68 LONG denominator;
71 static const struct ifd_data
73 USHORT number_of_entries;
74 struct IFD_entry entry[40];
75 ULONG next_IFD;
76 struct IFD_rational xres;
77 DOUBLE double_val;
78 struct IFD_rational srational_val;
79 char string[14];
80 SHORT short_val[4];
81 LONG long_val[2];
82 FLOAT float_val[2];
83 } IFD_data =
85 27,
87 { 0xfe, IFD_SHORT, 1, 1 }, /* NEWSUBFILETYPE */
88 { 0x100, IFD_LONG, 1, 222 }, /* IMAGEWIDTH */
89 { 0x101, IFD_LONG, 1, 333 }, /* IMAGELENGTH */
90 { 0x102, IFD_SHORT, 1, 24 }, /* BITSPERSAMPLE */
91 { 0x103, IFD_LONG, 1, 32773 }, /* COMPRESSION: packbits */
92 { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct ifd_data, xres) },
93 { 0xf001, IFD_BYTE, 1, 0x11223344 },
94 { 0xf002, IFD_BYTE, 4, 0x11223344 },
95 { 0xf003, IFD_SBYTE, 1, 0x11223344 },
96 { 0xf004, IFD_SSHORT, 1, 0x11223344 },
97 { 0xf005, IFD_SSHORT, 2, 0x11223344 },
98 { 0xf006, IFD_SLONG, 1, 0x11223344 },
99 { 0xf007, IFD_FLOAT, 1, 0x11223344 },
100 { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct ifd_data, double_val) },
101 { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct ifd_data, srational_val) },
102 { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct ifd_data, string) },
103 { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct ifd_data, short_val) },
104 { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct ifd_data, long_val) },
105 { 0xf00d, IFD_FLOAT, 2, FIELD_OFFSET(struct ifd_data, float_val) },
106 { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct ifd_data, string) },
107 { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
108 { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct ifd_data, string) },
109 { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
110 { 0xf012, IFD_BYTE, 0, 0x11223344 },
111 { 0xf013, IFD_SHORT, 0, 0x11223344 },
112 { 0xf014, IFD_LONG, 0, 0x11223344 },
113 { 0xf015, IFD_FLOAT, 0, 0x11223344 },
116 { 900, 3 },
117 1234567890.0987654321,
118 { 0x1a2b3c4d, 0x5a6b7c8d },
119 "Hello World!",
120 { 0x0101, 0x0202, 0x0303, 0x0404 },
121 { 0x11223344, 0x55667788 },
122 { (FLOAT)1234.5678, (FLOAT)8765.4321 },
124 #include "poppack.h"
126 static const char metadata_unknown[] = "lalala";
128 static const char metadata_tEXt[] = {
129 0,0,0,14, /* chunk length */
130 't','E','X','t', /* chunk type */
131 'w','i','n','e','t','e','s','t',0, /* keyword */
132 'v','a','l','u','e', /* text */
133 0x3f,0x64,0x19,0xf3 /* chunk CRC */
136 static const char pngimage[285] = {
137 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
138 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
139 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
140 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
141 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
142 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
143 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
146 static const char *debugstr_guid(REFIID riid)
148 static char buf[50];
150 if(!riid)
151 return "(null)";
153 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
154 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
155 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
156 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
158 return buf;
161 static IStream *create_stream(const char *data, int data_size)
163 HRESULT hr;
164 IStream *stream;
165 HGLOBAL hdata;
166 void *locked_data;
168 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
169 ok(hdata != 0, "GlobalAlloc failed\n");
170 if (!hdata) return NULL;
172 locked_data = GlobalLock(hdata);
173 memcpy(locked_data, data, data_size);
174 GlobalUnlock(hdata);
176 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
177 ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
179 return stream;
182 static void load_stream(IUnknown *reader, const char *data, int data_size)
184 HRESULT hr;
185 IWICPersistStream *persist;
186 IStream *stream;
187 LARGE_INTEGER pos;
188 ULARGE_INTEGER cur_pos;
190 stream = create_stream(data, data_size);
191 if (!stream)
192 return;
194 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
195 ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
197 if (SUCCEEDED(hr))
199 hr = IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
200 ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
202 IWICPersistStream_Release(persist);
205 pos.QuadPart = 0;
206 hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos);
207 ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
208 /* IFD metadata reader doesn't rewind the stream to the start */
209 ok(cur_pos.QuadPart == 0 || cur_pos.QuadPart <= data_size,
210 "current stream pos is at %x/%x, data size %x\n", cur_pos.u.LowPart, cur_pos.u.HighPart, data_size);
212 IStream_Release(stream);
215 static void test_metadata_unknown(void)
217 HRESULT hr;
218 IWICMetadataReader *reader;
219 IWICEnumMetadataItem *enumerator;
220 IWICMetadataBlockReader *blockreader;
221 PROPVARIANT schema, id, value;
222 ULONG items_returned;
224 hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
225 &IID_IWICMetadataReader, (void**)&reader);
226 ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
227 if (FAILED(hr)) return;
229 load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown));
231 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
232 ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
234 if (SUCCEEDED(hr))
236 PropVariantInit(&schema);
237 PropVariantInit(&id);
238 PropVariantInit(&value);
240 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
241 ok(hr == S_OK, "Next failed, hr=%x\n", hr);
242 ok(items_returned == 1, "unexpected item count %i\n", items_returned);
244 if (hr == S_OK && items_returned == 1)
246 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
247 ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
248 expect_blob(value, metadata_unknown, sizeof(metadata_unknown));
250 PropVariantClear(&schema);
251 PropVariantClear(&id);
252 PropVariantClear(&value);
255 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
256 ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
257 ok(items_returned == 0, "unexpected item count %i\n", items_returned);
259 IWICEnumMetadataItem_Release(enumerator);
262 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
263 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
265 if (SUCCEEDED(hr))
266 IWICMetadataBlockReader_Release(blockreader);
268 IWICMetadataReader_Release(reader);
271 static void test_metadata_tEXt(void)
273 HRESULT hr;
274 IWICMetadataReader *reader;
275 IWICEnumMetadataItem *enumerator;
276 PROPVARIANT schema, id, value;
277 ULONG items_returned, count;
278 GUID format;
280 PropVariantInit(&schema);
281 PropVariantInit(&id);
282 PropVariantInit(&value);
284 hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
285 &IID_IWICMetadataReader, (void**)&reader);
286 todo_wine ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
287 if (FAILED(hr)) return;
289 hr = IWICMetadataReader_GetCount(reader, NULL);
290 ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
292 hr = IWICMetadataReader_GetCount(reader, &count);
293 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
294 ok(count == 0, "unexpected count %i\n", count);
296 load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt));
298 hr = IWICMetadataReader_GetCount(reader, &count);
299 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
300 ok(count == 1, "unexpected count %i\n", count);
302 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
303 ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
305 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
306 ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
308 if (SUCCEEDED(hr))
310 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
311 ok(hr == S_OK, "Next failed, hr=%x\n", hr);
312 ok(items_returned == 1, "unexpected item count %i\n", items_returned);
314 if (hr == S_OK && items_returned == 1)
316 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
317 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
318 ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
319 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
320 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
322 PropVariantClear(&schema);
323 PropVariantClear(&id);
324 PropVariantClear(&value);
327 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
328 ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
329 ok(items_returned == 0, "unexpected item count %i\n", items_returned);
331 IWICEnumMetadataItem_Release(enumerator);
334 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
335 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
336 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
338 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
339 ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
341 id.vt = VT_LPSTR;
342 U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
343 strcpy(U(id).pszVal, "winetest");
345 hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
346 ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
348 hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
349 ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
351 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
352 ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
353 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
354 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
355 PropVariantClear(&value);
357 strcpy(U(id).pszVal, "test");
359 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
360 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
362 PropVariantClear(&id);
364 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
365 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
367 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
368 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
369 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
371 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
372 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
373 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
374 ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
375 PropVariantClear(&id);
377 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
378 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
379 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
380 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
381 PropVariantClear(&value);
383 hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
384 ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
386 IWICMetadataReader_Release(reader);
389 static void test_metadata_IFD(void)
391 static const struct test_data
393 ULONG type, id;
394 int count; /* if VT_VECTOR */
395 LONGLONG value[13];
396 const char *string;
397 } td[27] =
399 { VT_UI2, 0xfe, 0, { 1 } },
400 { VT_UI4, 0x100, 0, { 222 } },
401 { VT_UI4, 0x101, 0, { 333 } },
402 { VT_UI2, 0x102, 0, { 24 } },
403 { VT_UI4, 0x103, 0, { 32773 } },
404 { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
405 { VT_UI1, 0xf001, 0, { 0x44 } },
406 { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
407 { VT_I1, 0xf003, 0, { 0x44 } },
408 { VT_I2, 0xf004, 0, { 0x3344 } },
409 { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
410 { VT_I4, 0xf006, 0, { 0x11223344 } },
411 { VT_R4, 0xf007, 0, { 0x11223344 } },
412 { VT_R8, 0xf008, 0, { ((LONGLONG)0x41d26580 << 32) | 0xb486522c } },
413 { VT_I8, 0xf009, 0, { ((LONGLONG)0x5a6b7c8d << 32) | 0x1a2b3c4d } },
414 { VT_UI1|VT_VECTOR, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
415 { VT_I2|VT_VECTOR, 0xf00b, 4, { 0x0101, 0x0202, 0x0303, 0x0404 } },
416 { VT_I4|VT_VECTOR, 0xf00c, 2, { 0x11223344, 0x55667788 } },
417 { VT_R4|VT_VECTOR, 0xf00d, 2, { 0x449a522b, 0x4608f5ba } },
418 { VT_LPSTR, 0xf00e, 12, { 0 }, "Hello World!" },
419 { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
420 { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
421 { VT_BLOB, 0xf011, 4, { 0 }, "abcd" },
422 { VT_UI1, 0xf012, 0, { 0x44 } },
423 { VT_UI2, 0xf013, 0, { 0x3344 } },
424 { VT_UI4, 0xf014, 0, { 0x11223344 } },
425 { VT_R4, 0xf015, 0, { 0x11223344 } },
427 HRESULT hr;
428 IWICMetadataReader *reader;
429 IWICMetadataBlockReader *blockreader;
430 IWICEnumMetadataItem *enumerator;
431 PROPVARIANT schema, id, value;
432 ULONG items_returned, count, i;
433 GUID format;
435 PropVariantInit(&schema);
436 PropVariantInit(&id);
437 PropVariantInit(&value);
439 hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
440 &IID_IWICMetadataReader, (void**)&reader);
441 ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
443 hr = IWICMetadataReader_GetCount(reader, NULL);
444 ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
446 hr = IWICMetadataReader_GetCount(reader, &count);
447 ok(hr == S_OK, "GetCount error %#x\n", hr);
448 ok(count == 0, "unexpected count %u\n", count);
450 load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data));
452 hr = IWICMetadataReader_GetCount(reader, &count);
453 ok(hr == S_OK, "GetCount error %#x\n", hr);
454 ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
456 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
457 ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
459 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
460 ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
462 for (i = 0; i < count; i++)
464 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
465 ok(hr == S_OK, "Next error %#x\n", hr);
466 ok(items_returned == 1, "unexpected item count %u\n", items_returned);
468 ok(schema.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, schema.vt);
469 ok(id.vt == VT_UI2, "%u: unexpected vt: %u\n", i, id.vt);
470 ok(U(id).uiVal == td[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, U(id).uiVal);
471 ok(value.vt == td[i].type, "%u: expected vt %#x, got %#x\n", i, td[i].type, value.vt);
472 if (value.vt & VT_VECTOR)
474 ULONG j;
475 switch (value.vt & ~VT_VECTOR)
477 case VT_I1:
478 case VT_UI1:
479 ok(td[i].count == U(value).caub.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
480 for (j = 0; j < U(value).caub.cElems; j++)
481 ok(td[i].value[j] == U(value).caub.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caub.pElems[j]);
482 break;
483 case VT_I2:
484 case VT_UI2:
485 ok(td[i].count == U(value).caui.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caui.cElems);
486 for (j = 0; j < U(value).caui.cElems; j++)
487 ok(td[i].value[j] == U(value).caui.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caui.pElems[j]);
488 break;
489 case VT_I4:
490 case VT_UI4:
491 case VT_R4:
492 ok(td[i].count == U(value).caul.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caui.cElems);
493 for (j = 0; j < U(value).caul.cElems; j++)
494 ok(td[i].value[j] == U(value).caul.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caul.pElems[j]);
495 break;
496 case VT_LPSTR:
497 ok(td[i].count == U(value).calpstr.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
498 for (j = 0; j < U(value).calpstr.cElems; j++)
499 trace("%u: %s\n", j, U(value).calpstr.pElems[j]);
500 /* fall through to not handled message */
501 default:
502 ok(0, "%u: array of type %d is not handled\n", i, value.vt & ~VT_VECTOR);
503 break;
506 else if (value.vt == VT_LPSTR)
508 ok(td[i].count == strlen(U(value).pszVal) ||
509 broken(td[i].count == strlen(U(value).pszVal) + 1), /* before Win7 */
510 "%u: expected count %d, got %d\n", i, td[i].count, lstrlenA(U(value).pszVal));
511 if (td[i].count == strlen(U(value).pszVal))
512 ok(!strcmp(td[i].string, U(value).pszVal),
513 "%u: expected %s, got %s\n", i, td[i].string, U(value).pszVal);
515 else if (value.vt == VT_BLOB)
517 ok(td[i].count == U(value).blob.cbSize, "%u: expected count %d, got %d\n", i, td[i].count, U(value).blob.cbSize);
518 ok(!memcmp(td[i].string, U(value).blob.pBlobData, td[i].count), "%u: expected %s, got %s\n", i, td[i].string, U(value).blob.pBlobData);
520 else
521 ok(U(value).uhVal.QuadPart == td[i].value[0], "%u: unexpected value: %d/%d\n", i, U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
523 PropVariantClear(&schema);
524 PropVariantClear(&id);
525 PropVariantClear(&value);
528 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
529 ok(hr == S_FALSE, "Next should fail\n");
530 ok(items_returned == 0, "unexpected item count %u\n", items_returned);
532 IWICEnumMetadataItem_Release(enumerator);
534 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
535 ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
536 ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", debugstr_guid(&format));
538 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
539 ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
541 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
542 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
544 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
545 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
547 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
548 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
549 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
551 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
552 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
553 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
555 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
556 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
557 ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
558 ok(U(id).uiVal == 0xfe, "unexpected id: %#x\n", U(id).uiVal);
559 PropVariantClear(&id);
561 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
562 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
563 ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
564 ok(U(value).ulVal == 1, "unexpected id: %u\n", U(value).ulVal);
565 PropVariantClear(&value);
567 hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
568 ok(hr == E_INVALIDARG, "GetValueByIndex should fail\n");
570 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
571 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
573 if (SUCCEEDED(hr))
574 IWICMetadataBlockReader_Release(blockreader);
576 IWICMetadataReader_Release(reader);
579 static void test_metadata_Exif(void)
581 HRESULT hr;
582 IWICMetadataReader *reader;
583 IWICMetadataBlockReader *blockreader;
584 UINT count=0;
586 hr = CoCreateInstance(&CLSID_WICExifMetadataReader, NULL, CLSCTX_INPROC_SERVER,
587 &IID_IWICMetadataReader, (void**)&reader);
588 todo_wine ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
589 if (FAILED(hr)) return;
591 hr = IWICMetadataReader_GetCount(reader, NULL);
592 ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
594 hr = IWICMetadataReader_GetCount(reader, &count);
595 ok(hr == S_OK, "GetCount error %#x\n", hr);
596 ok(count == 0, "unexpected count %u\n", count);
598 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
599 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
601 if (SUCCEEDED(hr))
602 IWICMetadataBlockReader_Release(blockreader);
604 IWICMetadataReader_Release(reader);
607 static void test_create_reader(void)
609 HRESULT hr;
610 IWICComponentFactory *factory;
611 IStream *stream;
612 IWICMetadataReader *reader;
613 UINT count=0;
614 GUID format;
616 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
617 &IID_IWICComponentFactory, (void**)&factory);
618 ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
620 stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
622 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
623 &GUID_ContainerFormatPng, NULL, WICPersistOptionsDefault,
624 stream, &reader);
625 todo_wine
626 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
627 if (FAILED(hr)) return;
629 if (SUCCEEDED(hr))
631 hr = IWICMetadataReader_GetCount(reader, &count);
632 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
633 ok(count == 1, "unexpected count %i\n", count);
635 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
636 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
637 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
639 IWICMetadataReader_Release(reader);
642 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
643 &GUID_ContainerFormatWmp, NULL, WICPersistOptionsDefault,
644 stream, &reader);
645 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
647 if (SUCCEEDED(hr))
649 hr = IWICMetadataReader_GetCount(reader, &count);
650 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
651 ok(count == 1, "unexpected count %i\n", count);
653 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
654 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
655 ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", debugstr_guid(&format));
657 IWICMetadataReader_Release(reader);
660 IStream_Release(stream);
662 IWICComponentFactory_Release(factory);
665 static void test_metadata_png(void)
667 IStream *stream;
668 IWICBitmapDecoder *decoder;
669 IWICBitmapFrameDecode *frame;
670 IWICMetadataBlockReader *blockreader;
671 IWICMetadataReader *reader;
672 GUID containerformat;
673 HRESULT hr;
674 UINT count;
676 hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
677 &IID_IWICBitmapDecoder, (void**)&decoder);
678 ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
680 if (FAILED(hr)) return;
682 stream = create_stream(pngimage, sizeof(pngimage));
684 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
685 ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
687 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void**)&blockreader);
688 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
690 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
691 ok(hr == S_OK, "GetFrame failed, hr=%x\n", hr);
693 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void**)&blockreader);
694 ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
696 if (SUCCEEDED(hr))
698 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
699 ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%x\n", hr);
701 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &containerformat);
702 ok(hr == S_OK, "GetContainerFormat failed, hr=%x\n", hr);
703 ok(IsEqualGUID(&containerformat, &GUID_ContainerFormatPng), "unexpected container format\n");
705 hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
706 todo_wine ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
708 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
709 todo_wine ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
710 todo_wine ok(count == 1, "unexpected count %d\n", count);
712 if (0)
714 /* Crashes on Windows XP */
715 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, NULL);
716 ok(hr == E_INVALIDARG, "GetReaderByIndex failed, hr=%x\n", hr);
719 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
720 todo_wine ok(hr == S_OK, "GetReaderByIndex failed, hr=%x\n", hr);
722 if (SUCCEEDED(hr))
724 hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
725 ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
726 broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
727 "unexpected container format\n");
729 IWICMetadataReader_Release(reader);
732 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
733 todo_wine ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "GetReaderByIndex failed, hr=%x\n", hr);
735 IWICMetadataBlockReader_Release(blockreader);
738 IWICBitmapFrameDecode_Release(frame);
740 IWICBitmapDecoder_Release(decoder);
742 IWICStream_Release(stream);
745 START_TEST(metadata)
747 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
749 test_metadata_unknown();
750 test_metadata_tEXt();
751 test_metadata_IFD();
752 test_metadata_Exif();
753 test_create_reader();
754 test_metadata_png();
756 CoUninitialize();