include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / windowscodecs / tests / metadata.c
blob886e62833bfad13bcf563aa7cd9d8295b31573d5
1 /*
2 * Copyright 2011 Vincent Povirk for CodeWeavers
3 * Copyright 2012,2017 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>
23 #include <assert.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30 #include "wincodecsdk.h"
31 #include "propvarutil.h"
32 #include "wine/test.h"
34 #include "initguid.h"
35 DEFINE_GUID(IID_MdbrUnknown, 0x00240e6f,0x3f23,0x4432,0xb0,0xcc,0x48,0xd5,0xbb,0xff,0x6c,0x36);
37 #define expect_blob(propvar, data, length) do { \
38 ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
39 if ((propvar).vt == VT_BLOB) { \
40 ok(propvar.blob.cbSize == (length), "expected size %lu, got %lu\n", (ULONG)(length), propvar.blob.cbSize); \
41 if (propvar.blob.cbSize == (length)) { \
42 ok(!memcmp(propvar.blob.pBlobData, (data), (length)), "unexpected data\n"); \
43 } \
44 } \
45 } while (0)
47 #define IFD_BYTE 1
48 #define IFD_ASCII 2
49 #define IFD_SHORT 3
50 #define IFD_LONG 4
51 #define IFD_RATIONAL 5
52 #define IFD_SBYTE 6
53 #define IFD_UNDEFINED 7
54 #define IFD_SSHORT 8
55 #define IFD_SLONG 9
56 #define IFD_SRATIONAL 10
57 #define IFD_FLOAT 11
58 #define IFD_DOUBLE 12
59 #define IFD_IFD 13
61 #include "pshpack2.h"
62 struct IFD_entry
64 SHORT id;
65 SHORT type;
66 ULONG count;
67 LONG value;
70 struct IFD_rational
72 LONG numerator;
73 LONG denominator;
76 static const struct ifd_data
78 USHORT number_of_entries;
79 struct IFD_entry entry[40];
80 ULONG next_IFD;
81 struct IFD_rational xres;
82 DOUBLE double_val;
83 struct IFD_rational srational_val;
84 char string[14];
85 SHORT short_val[4];
86 LONG long_val[2];
87 FLOAT float_val[2];
88 struct IFD_rational rational[3];
89 } IFD_data =
91 28,
93 { 0xfe, IFD_SHORT, 1, 1 }, /* NEWSUBFILETYPE */
94 { 0x100, IFD_LONG, 1, 222 }, /* IMAGEWIDTH */
95 { 0x101, IFD_LONG, 1, 333 }, /* IMAGELENGTH */
96 { 0x102, IFD_SHORT, 1, 24 }, /* BITSPERSAMPLE */
97 { 0x103, IFD_LONG, 1, 32773 }, /* COMPRESSION: packbits */
98 { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct ifd_data, xres) },
99 { 0xf001, IFD_BYTE, 1, 0x11223344 },
100 { 0xf002, IFD_BYTE, 4, 0x11223344 },
101 { 0xf003, IFD_SBYTE, 1, 0x11223344 },
102 { 0xf004, IFD_SSHORT, 1, 0x11223344 },
103 { 0xf005, IFD_SSHORT, 2, 0x11223344 },
104 { 0xf006, IFD_SLONG, 1, 0x11223344 },
105 { 0xf007, IFD_FLOAT, 1, 0x11223344 },
106 { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct ifd_data, double_val) },
107 { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct ifd_data, srational_val) },
108 { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct ifd_data, string) },
109 { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct ifd_data, short_val) },
110 { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct ifd_data, long_val) },
111 { 0xf00d, IFD_FLOAT, 2, FIELD_OFFSET(struct ifd_data, float_val) },
112 { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct ifd_data, string) },
113 { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
114 { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct ifd_data, string) },
115 { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
116 { 0xf012, IFD_BYTE, 0, 0x11223344 },
117 { 0xf013, IFD_SHORT, 0, 0x11223344 },
118 { 0xf014, IFD_LONG, 0, 0x11223344 },
119 { 0xf015, IFD_FLOAT, 0, 0x11223344 },
120 { 0xf016, IFD_SRATIONAL, 3, FIELD_OFFSET(struct ifd_data, rational) },
123 { 900, 3 },
124 1234567890.0987654321,
125 { 0x1a2b3c4d, 0x5a6b7c8d },
126 "Hello World!",
127 { 0x0101, 0x0202, 0x0303, 0x0404 },
128 { 0x11223344, 0x55667788 },
129 { (FLOAT)1234.5678, (FLOAT)8765.4321 },
130 { { 0x01020304, 0x05060708 }, { 0x10203040, 0x50607080 }, { 0x11223344, 0x55667788 } },
132 #include "poppack.h"
134 static const char metadata_unknown[] = "lalala";
136 static const char metadata_tEXt[] = {
137 0,0,0,14, /* chunk length */
138 't','E','X','t', /* chunk type */
139 'w','i','n','e','t','e','s','t',0, /* keyword */
140 'v','a','l','u','e', /* text */
141 0x3f,0x64,0x19,0xf3 /* chunk CRC */
144 static const char metadata_gAMA[] = {
145 0,0,0,4, /* chunk length */
146 'g','A','M','A', /* chunk type */
147 0,0,130,53, /* gamma */
148 0xff,0xff,0xff,0xff /* chunk CRC */
151 static const char metadata_cHRM[] = {
152 0,0,0,32, /* chunk length */
153 'c','H','R','M', /* chunk type */
154 0,0,122,38, 0,0,128,132, /* white point */
155 0,0,250,0, 0,0,128,232, /* red */
156 0,0,117,48, 0,0,234,96, /* green */
157 0,0,58,152, 0,0,23,112, /* blue */
158 0xff,0xff,0xff,0xff /* chunk CRC */
161 static const char metadata_hIST[] = {
162 0,0,0,40, /* chunk length */
163 'h','I','S','T', /* chunk type */
164 0,1, 0,2, 0,3, 0,4,
165 0,5, 0,6, 0,7, 0,8,
166 0,9, 0,10, 0,11, 0,12,
167 0,13, 0,14, 0,15, 0,16,
168 0,17, 0,18, 0,19, 0,20,
169 0xff,0xff,0xff,0xff
172 static const char metadata_tIME[] = {
173 0,0,0,7, /* chunk length */
174 't','I','M','E', /* chunk type */
175 0x07,0xd0,0x01,0x02, /* year (2 bytes), month, day */
176 0x0c,0x22,0x38, /* hour, minute, second */
177 0xff,0xff,0xff,0xff
180 static const char pngimage[285] = {
181 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
182 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
183 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
184 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
185 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
186 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
187 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
190 /* 1x1 pixel gif */
191 static const char gifimage[35] = {
192 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
193 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
194 0x01,0x00,0x3b
197 /* 1x1 pixel gif, 2 frames; first frame is white, second is black */
198 static const char animatedgif[] = {
199 'G','I','F','8','9','a',0x01,0x00,0x01,0x00,0xA1,0x00,0x00,
200 0x6F,0x6F,0x6F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
201 /*0x21,0xFF,0x0B,'N','E','T','S','C','A','P','E','2','.','0',*/
202 0x21,0xFF,0x0B,'A','N','I','M','E','X','T','S','1','.','0',
203 0x03,0x01,0x05,0x00,0x00,
204 0x21,0xFE,0x0C,'H','e','l','l','o',' ','W','o','r','l','d','!',0x00,
205 0x21,0x01,0x0D,'a','n','i','m','a','t','i','o','n','.','g','i','f',0x00,
206 0x21,0xF9,0x04,0x00,0x0A,0x00,0xFF,0x00,0x2C,
207 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
208 0xDE,0xDE,0xDE,0x00,0x00,0x00,
209 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x4C,0x01,0x00,
210 0x21,0xF9,0x04,0x01,0x0A,0x00,0x01,0x00,
211 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','1',0x00,
212 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','1',0x00,
213 0x2C,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
214 0x4D,0x4D,0x4D,0x00,0x00,0x00,
215 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x44,0x01,0x00,
216 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','2',0x00,
217 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','2',0x00,0x3B
220 static ULONG get_refcount(void *iface)
222 IUnknown *unknown = iface;
223 IUnknown_AddRef(unknown);
224 return IUnknown_Release(unknown);
227 static IStream *create_stream(const char *data, int data_size)
229 HRESULT hr;
230 IStream *stream;
231 HGLOBAL hdata;
232 void *locked_data;
234 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
235 ok(hdata != 0, "GlobalAlloc failed\n");
236 if (!hdata) return NULL;
238 locked_data = GlobalLock(hdata);
239 memcpy(locked_data, data, data_size);
240 GlobalUnlock(hdata);
242 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
243 ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%lx\n", hr);
245 return stream;
248 static void load_stream(IUnknown *reader, const char *data, int data_size, DWORD persist_options)
250 HRESULT hr;
251 IWICPersistStream *persist;
252 IStream *stream;
253 LARGE_INTEGER pos;
254 ULARGE_INTEGER cur_pos;
256 stream = create_stream(data, data_size);
257 if (!stream)
258 return;
260 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
261 ok(hr == S_OK, "QueryInterface failed, hr=%lx\n", hr);
263 if (SUCCEEDED(hr))
265 hr = IWICPersistStream_LoadEx(persist, stream, NULL, persist_options);
266 ok(hr == S_OK, "LoadEx failed, hr=%lx\n", hr);
268 IWICPersistStream_Release(persist);
271 pos.QuadPart = 0;
272 hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos);
273 ok(hr == S_OK, "IStream_Seek error %#lx\n", hr);
274 /* IFD metadata reader doesn't rewind the stream to the start */
275 ok(cur_pos.QuadPart == 0 || cur_pos.QuadPart <= data_size,
276 "current stream pos is at %lx/%lx, data size %x\n", cur_pos.u.LowPart, cur_pos.u.HighPart, data_size);
278 IStream_Release(stream);
281 struct test_data
283 ULONG type, id;
284 int count; /* if VT_VECTOR */
285 LONGLONG value[13];
286 const char *string;
287 const WCHAR id_string[32];
290 static void compare_metadata(IWICMetadataReader *reader, const struct test_data *td, ULONG count)
292 HRESULT hr;
293 IWICEnumMetadataItem *enumerator;
294 PROPVARIANT schema, id, value;
295 ULONG items_returned, i;
297 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
298 ok(hr == E_INVALIDARG, "GetEnumerator error %#lx\n", hr);
300 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
301 ok(hr == S_OK, "GetEnumerator error %#lx\n", hr);
303 PropVariantInit(&schema);
304 PropVariantInit(&id);
305 PropVariantInit(&value);
307 for (i = 0; i < count; i++)
309 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
310 ok(hr == S_OK, "Next error %#lx\n", hr);
311 ok(items_returned == 1, "unexpected item count %lu\n", items_returned);
313 ok(schema.vt == VT_EMPTY, "%lu: unexpected vt: %u\n", i, schema.vt);
314 ok(id.vt == VT_UI2 || id.vt == VT_LPWSTR || id.vt == VT_EMPTY, "%lu: unexpected vt: %u\n", i, id.vt);
315 if (id.vt == VT_UI2)
316 ok(id.uiVal == td[i].id, "%lu: expected id %#lx, got %#x\n", i, td[i].id, id.uiVal);
317 else if (id.vt == VT_LPWSTR)
318 ok(!lstrcmpW(td[i].id_string, id.pwszVal),
319 "%lu: expected %s, got %s\n", i, wine_dbgstr_w(td[i].id_string), wine_dbgstr_w(id.pwszVal));
321 ok(value.vt == td[i].type, "%lu: expected vt %#lx, got %#x\n", i, td[i].type, value.vt);
322 if (value.vt & VT_VECTOR)
324 ULONG j;
325 switch (value.vt & ~VT_VECTOR)
327 case VT_I1:
328 case VT_UI1:
329 ok(td[i].count == value.caub.cElems, "%lu: expected cElems %d, got %ld\n", i, td[i].count, value.caub.cElems);
330 for (j = 0; j < value.caub.cElems; j++)
331 ok(td[i].value[j] == value.caub.pElems[j], "%lu: expected value[%ld] %#I64x, got %#x\n", i, j, td[i].value[j], value.caub.pElems[j]);
332 break;
333 case VT_I2:
334 case VT_UI2:
335 ok(td[i].count == value.caui.cElems, "%lu: expected cElems %d, got %ld\n", i, td[i].count, value.caui.cElems);
336 for (j = 0; j < value.caui.cElems; j++)
337 ok(td[i].value[j] == value.caui.pElems[j], "%lu: expected value[%ld] %#I64x, got %#x\n", i, j, td[i].value[j], value.caui.pElems[j]);
338 break;
339 case VT_I4:
340 case VT_UI4:
341 case VT_R4:
342 ok(td[i].count == value.caul.cElems, "%lu: expected cElems %d, got %ld\n", i, td[i].count, value.caul.cElems);
343 for (j = 0; j < value.caul.cElems; j++)
344 ok(td[i].value[j] == value.caul.pElems[j], "%lu: expected value[%ld] %#I64x, got %#lx\n", i, j, td[i].value[j], value.caul.pElems[j]);
345 break;
346 case VT_I8:
347 case VT_UI8:
348 case VT_R8:
349 ok(td[i].count == value.cauh.cElems, "%lu: expected cElems %d, got %ld\n", i, td[i].count, value.cauh.cElems);
350 for (j = 0; j < value.cauh.cElems; j++)
351 ok(td[i].value[j] == value.cauh.pElems[j].QuadPart, "%lu: expected value[%ld] %I64x, got %08lx/%08lx\n", i, j, td[i].value[j], value.cauh.pElems[j].u.LowPart, value.cauh.pElems[j].u.HighPart);
352 break;
353 case VT_LPSTR:
354 ok(td[i].count == value.calpstr.cElems, "%lu: expected cElems %d, got %ld\n", i, td[i].count, value.caub.cElems);
355 for (j = 0; j < value.calpstr.cElems; j++)
356 trace("%lu: %s\n", j, value.calpstr.pElems[j]);
357 /* fall through to not handled message */
358 default:
359 ok(0, "%lu: array of type %d is not handled\n", i, value.vt & ~VT_VECTOR);
360 break;
363 else if (value.vt == VT_LPSTR)
365 ok(td[i].count == strlen(value.pszVal) ||
366 broken(td[i].count == strlen(value.pszVal) + 1), /* before Win7 */
367 "%lu: expected count %d, got %d\n", i, td[i].count, lstrlenA(value.pszVal));
368 if (td[i].count == strlen(value.pszVal))
369 ok(!strcmp(td[i].string, value.pszVal),
370 "%lu: expected %s, got %s\n", i, td[i].string, value.pszVal);
372 else if (value.vt == VT_BLOB)
374 ok(td[i].count == value.blob.cbSize, "%lu: expected count %d, got %ld\n", i, td[i].count, value.blob.cbSize);
375 ok(!memcmp(td[i].string, value.blob.pBlobData, td[i].count), "%lu: expected %s, got %s\n", i, td[i].string, value.blob.pBlobData);
377 else
378 ok(value.uhVal.QuadPart == td[i].value[0], "%lu: expected value %#I64x got %#lx/%#lx\n",
379 i, td[i].value[0], value.uhVal.u.LowPart, value.uhVal.u.HighPart);
381 PropVariantClear(&schema);
382 PropVariantClear(&id);
383 PropVariantClear(&value);
386 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
387 ok(hr == S_FALSE, "Next should fail\n");
388 ok(items_returned == 0, "unexpected item count %lu\n", items_returned);
390 IWICEnumMetadataItem_Release(enumerator);
393 static void test_metadata_unknown(void)
395 HRESULT hr;
396 IWICMetadataReader *reader;
397 IWICEnumMetadataItem *enumerator;
398 IWICMetadataBlockReader *blockreader;
399 PROPVARIANT schema, id, value;
400 ULONG items_returned;
402 hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
403 &IID_IWICMetadataReader, (void**)&reader);
404 ok(hr == S_OK, "CoCreateInstance failed, hr=%lx\n", hr);
405 if (FAILED(hr)) return;
407 load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown), WICPersistOptionDefault);
409 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
410 ok(hr == S_OK, "GetEnumerator failed, hr=%lx\n", hr);
412 if (SUCCEEDED(hr))
414 PropVariantInit(&schema);
415 PropVariantInit(&id);
416 PropVariantInit(&value);
418 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
419 ok(hr == S_OK, "Next failed, hr=%lx\n", hr);
420 ok(items_returned == 1, "unexpected item count %li\n", items_returned);
422 if (hr == S_OK && items_returned == 1)
424 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
425 ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
426 expect_blob(value, metadata_unknown, sizeof(metadata_unknown));
428 PropVariantClear(&schema);
429 PropVariantClear(&id);
430 PropVariantClear(&value);
433 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
434 ok(hr == S_FALSE, "Next failed, hr=%lx\n", hr);
435 ok(items_returned == 0, "unexpected item count %li\n", items_returned);
437 hr = IWICEnumMetadataItem_Reset(enumerator);
438 ok(hr == S_OK, "Reset failed, hr=%lx\n", hr);
440 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, NULL, NULL);
441 ok(hr == S_OK, "Next failed, hr=%lx\n", hr);
443 if (hr == S_OK)
445 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
446 ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
448 PropVariantClear(&schema);
449 PropVariantClear(&id);
452 IWICEnumMetadataItem_Release(enumerator);
455 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
456 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%lx\n", hr);
458 if (SUCCEEDED(hr))
459 IWICMetadataBlockReader_Release(blockreader);
461 IWICMetadataReader_Release(reader);
464 static void test_metadata_tEXt(void)
466 HRESULT hr;
467 IWICMetadataReader *reader;
468 IWICEnumMetadataItem *enumerator;
469 PROPVARIANT schema, id, value;
470 ULONG items_returned;
471 UINT count;
472 GUID format;
474 PropVariantInit(&schema);
475 PropVariantInit(&id);
476 PropVariantInit(&value);
478 hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
479 &IID_IWICMetadataReader, (void**)&reader);
480 ok(hr == S_OK, "CoCreateInstance failed, hr=%lx\n", hr);
481 if (FAILED(hr)) return;
483 hr = IWICMetadataReader_GetCount(reader, NULL);
484 ok(hr == E_INVALIDARG, "GetCount failed, hr=%lx\n", hr);
486 hr = IWICMetadataReader_GetCount(reader, &count);
487 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
488 ok(count == 0, "unexpected count %i\n", count);
490 load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt), WICPersistOptionDefault);
492 hr = IWICMetadataReader_GetCount(reader, &count);
493 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
494 ok(count == 1, "unexpected count %i\n", count);
496 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
497 ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%lx\n", hr);
499 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
500 ok(hr == S_OK, "GetEnumerator failed, hr=%lx\n", hr);
502 if (SUCCEEDED(hr))
504 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
505 ok(hr == S_OK, "Next failed, hr=%lx\n", hr);
506 ok(items_returned == 1, "unexpected item count %li\n", items_returned);
508 if (hr == S_OK && items_returned == 1)
510 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
511 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
512 ok(!strcmp(id.pszVal, "winetest"), "unexpected id: %s\n", id.pszVal);
513 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
514 ok(!strcmp(value.pszVal, "value"), "unexpected value: %s\n", value.pszVal);
516 PropVariantClear(&schema);
517 PropVariantClear(&id);
518 PropVariantClear(&value);
521 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
522 ok(hr == S_FALSE, "Next failed, hr=%lx\n", hr);
523 ok(items_returned == 0, "unexpected item count %li\n", items_returned);
525 IWICEnumMetadataItem_Release(enumerator);
528 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
529 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
530 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", wine_dbgstr_guid(&format));
532 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
533 ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%lx\n", hr);
535 id.vt = VT_LPSTR;
536 id.pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
537 strcpy(id.pszVal, "winetest");
539 hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
540 ok(hr == S_OK, "GetValue failed, hr=%lx\n", hr);
542 hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
543 ok(hr == E_INVALIDARG, "GetValue failed, hr=%lx\n", hr);
545 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
546 ok(hr == S_OK, "GetValue failed, hr=%lx\n", hr);
547 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
548 ok(!strcmp(value.pszVal, "value"), "unexpected value: %s\n", value.pszVal);
549 PropVariantClear(&value);
551 strcpy(id.pszVal, "test");
553 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
554 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%lx\n", hr);
556 PropVariantClear(&id);
558 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
559 ok(hr == S_OK, "GetValueByIndex failed, hr=%lx\n", hr);
561 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
562 ok(hr == S_OK, "GetValueByIndex failed, hr=%lx\n", hr);
563 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
565 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
566 ok(hr == S_OK, "GetValueByIndex failed, hr=%lx\n", hr);
567 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
568 ok(!strcmp(id.pszVal, "winetest"), "unexpected id: %s\n", id.pszVal);
569 PropVariantClear(&id);
571 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
572 ok(hr == S_OK, "GetValueByIndex failed, hr=%lx\n", hr);
573 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
574 ok(!strcmp(value.pszVal, "value"), "unexpected value: %s\n", value.pszVal);
575 PropVariantClear(&value);
577 hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
578 ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%lx\n", hr);
580 IWICMetadataReader_Release(reader);
583 static void test_metadata_gAMA(void)
585 HRESULT hr;
586 IWICMetadataReader *reader;
587 PROPVARIANT schema, id, value;
588 UINT count;
589 GUID format;
590 static const WCHAR ImageGamma[] = {'I','m','a','g','e','G','a','m','m','a',0};
592 PropVariantInit(&schema);
593 PropVariantInit(&id);
594 PropVariantInit(&value);
596 hr = CoCreateInstance(&CLSID_WICPngGamaMetadataReader, NULL, CLSCTX_INPROC_SERVER,
597 &IID_IWICMetadataReader, (void**)&reader);
598 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%lx\n", hr);
599 if (FAILED(hr)) return;
601 load_stream((IUnknown*)reader, metadata_gAMA, sizeof(metadata_gAMA), WICPersistOptionDefault);
603 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
604 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
605 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunkgAMA), "unexpected format %s\n", wine_dbgstr_guid(&format));
607 hr = IWICMetadataReader_GetCount(reader, &count);
608 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
609 ok(count == 1, "unexpected count %i\n", count);
611 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, &id, &value);
612 ok(hr == S_OK, "GetValue failed, hr=%lx\n", hr);
614 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
615 PropVariantClear(&schema);
617 ok(id.vt == VT_LPWSTR, "unexpected vt: %i\n", id.vt);
618 ok(!lstrcmpW(id.pwszVal, ImageGamma), "unexpected value: %s\n", wine_dbgstr_w(id.pwszVal));
619 PropVariantClear(&id);
621 ok(value.vt == VT_UI4, "unexpected vt: %i\n", value.vt);
622 ok(value.ulVal == 33333, "unexpected value: %lu\n", value.ulVal);
623 PropVariantClear(&value);
625 IWICMetadataReader_Release(reader);
628 static void test_metadata_cHRM(void)
630 HRESULT hr;
631 IWICMetadataReader *reader;
632 PROPVARIANT schema, id, value;
633 UINT count;
634 GUID format;
635 int i;
636 static const WCHAR expected_names[8][12] = {
637 {'W','h','i','t','e','P','o','i','n','t','X',0},
638 {'W','h','i','t','e','P','o','i','n','t','Y',0},
639 {'R','e','d','X',0},
640 {'R','e','d','Y',0},
641 {'G','r','e','e','n','X',0},
642 {'G','r','e','e','n','Y',0},
643 {'B','l','u','e','X',0},
644 {'B','l','u','e','Y',0},
646 static const ULONG expected_vals[8] = {
647 31270,32900, 64000,33000, 30000,60000, 15000,6000
650 PropVariantInit(&schema);
651 PropVariantInit(&id);
652 PropVariantInit(&value);
654 hr = CoCreateInstance(&CLSID_WICPngChrmMetadataReader, NULL, CLSCTX_INPROC_SERVER,
655 &IID_IWICMetadataReader, (void**)&reader);
656 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%lx\n", hr);
657 if (FAILED(hr)) return;
659 load_stream((IUnknown*)reader, metadata_cHRM, sizeof(metadata_cHRM), WICPersistOptionDefault);
661 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
662 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
663 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunkcHRM), "unexpected format %s\n", wine_dbgstr_guid(&format));
665 hr = IWICMetadataReader_GetCount(reader, &count);
666 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
667 ok(count == 8, "unexpected count %i\n", count);
669 for (i=0; i<8; i++)
671 hr = IWICMetadataReader_GetValueByIndex(reader, i, &schema, &id, &value);
672 ok(hr == S_OK, "GetValue failed, hr=%lx\n", hr);
674 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
675 PropVariantClear(&schema);
677 ok(id.vt == VT_LPWSTR, "unexpected vt: %i\n", id.vt);
678 ok(!lstrcmpW(id.pwszVal, expected_names[i]), "got %s, expected %s\n", wine_dbgstr_w(id.pwszVal), wine_dbgstr_w(expected_names[i]));
679 PropVariantClear(&id);
681 ok(value.vt == VT_UI4, "unexpected vt: %i\n", value.vt);
682 ok(value.ulVal == expected_vals[i], "got %lu, expected %lu\n", value.ulVal, expected_vals[i]);
683 PropVariantClear(&value);
686 IWICMetadataReader_Release(reader);
689 static void test_metadata_hIST(void)
691 HRESULT hr;
692 IWICMetadataReader *reader;
693 PROPVARIANT schema, id, value;
694 UINT count, i;
695 GUID format;
696 static const WCHAR Frequencies[] = L"Frequencies";
698 PropVariantInit(&schema);
699 PropVariantInit(&id);
700 PropVariantInit(&value);
702 hr = CoCreateInstance(&CLSID_WICPngHistMetadataReader, NULL, CLSCTX_INPROC_SERVER,
703 &IID_IWICMetadataReader, (void**)&reader);
704 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%lx\n", hr);
705 if (FAILED(hr)) return;
707 load_stream((IUnknown*)reader, metadata_hIST, sizeof(metadata_hIST), WICPersistOptionDefault);
709 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
710 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
711 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunkhIST), "unexpected format %s\n", wine_dbgstr_guid(&format));
713 hr = IWICMetadataReader_GetCount(reader, &count);
714 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
715 ok(count == 1, "unexpected count %i\n", count);
717 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, &id, &value);
718 ok(hr == S_OK, "GetValue failed, hr=%lx\n", hr);
720 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
721 PropVariantClear(&schema);
723 ok(id.vt == VT_LPWSTR, "unexpected vt: %i\n", id.vt);
724 ok(!lstrcmpW(id.pwszVal, Frequencies), "unexpected value: %s\n", wine_dbgstr_w(id.pwszVal));
725 PropVariantClear(&id);
727 ok(value.vt == (VT_UI2|VT_VECTOR), "unexpected vt: %i\n", value.vt);
728 ok(20 == value.caui.cElems, "expected cElems %d, got %ld\n", 20, value.caub.cElems);
729 for (i = 0; i < value.caui.cElems; i++)
730 ok(i+1 == value.caui.pElems[i], "%u: expected value %u, got %u\n", i, i+1, value.caui.pElems[i]);
731 PropVariantClear(&value);
733 IWICMetadataReader_Release(reader);
736 static void test_metadata_tIME(void)
738 HRESULT hr;
739 IWICMetadataReader *reader;
740 UINT count;
741 GUID format;
742 static const struct test_data td[] =
744 { VT_UI2, 0, 0, { 2000 }, NULL, L"Year" },
745 { VT_UI1, 0, 0, { 1 }, NULL, L"Month" },
746 { VT_UI1, 0, 0, { 2 }, NULL, L"Day" },
747 { VT_UI1, 0, 0, { 12 }, NULL, L"Hour" },
748 { VT_UI1, 0, 0, { 34 }, NULL, L"Minute" },
749 { VT_UI1, 0, 0, { 56 }, NULL, L"Second" },
752 hr = CoCreateInstance(&CLSID_WICPngTimeMetadataReader, NULL, CLSCTX_INPROC_SERVER,
753 &IID_IWICMetadataReader, (void**)&reader);
754 ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%lx\n", hr);
755 if (FAILED(hr)) return;
757 load_stream((IUnknown*)reader, metadata_tIME, sizeof(metadata_tIME), WICPersistOptionDefault);
759 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
760 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
761 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktIME), "unexpected format %s\n", wine_dbgstr_guid(&format));
763 hr = IWICMetadataReader_GetCount(reader, &count);
764 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
765 ok(count == ARRAY_SIZE(td), "unexpected count %i\n", count);
767 compare_metadata(reader, td, count);
769 IWICMetadataReader_Release(reader);
772 static inline USHORT ushort_bswap(USHORT s)
774 return (s >> 8) | (s << 8);
777 static inline ULONG ulong_bswap(ULONG l)
779 return ((ULONG)ushort_bswap((USHORT)l) << 16) | ushort_bswap((USHORT)(l >> 16));
782 static inline ULONGLONG ulonglong_bswap(ULONGLONG ll)
784 return ((ULONGLONG)ulong_bswap((ULONG)ll) << 32) | ulong_bswap((ULONG)(ll >> 32));
787 static void byte_swap_ifd_data(char *data)
789 USHORT number_of_entries, i;
790 struct IFD_entry *entry;
791 char *data_start = data;
793 number_of_entries = *(USHORT *)data;
794 *(USHORT *)data = ushort_bswap(*(USHORT *)data);
795 data += sizeof(USHORT);
797 for (i = 0; i < number_of_entries; i++)
799 entry = (struct IFD_entry *)data;
801 switch (entry->type)
803 case IFD_BYTE:
804 case IFD_SBYTE:
805 case IFD_ASCII:
806 case IFD_UNDEFINED:
807 if (entry->count > 4)
808 entry->value = ulong_bswap(entry->value);
809 break;
811 case IFD_SHORT:
812 case IFD_SSHORT:
813 if (entry->count > 2)
815 ULONG j, count = entry->count;
816 USHORT *us = (USHORT *)(data_start + entry->value);
817 if (!count) count = 1;
818 for (j = 0; j < count; j++)
819 us[j] = ushort_bswap(us[j]);
821 entry->value = ulong_bswap(entry->value);
823 else
825 ULONG j, count = entry->count;
826 USHORT *us = (USHORT *)&entry->value;
827 if (!count) count = 1;
828 for (j = 0; j < count; j++)
829 us[j] = ushort_bswap(us[j]);
831 break;
833 case IFD_LONG:
834 case IFD_SLONG:
835 case IFD_FLOAT:
836 if (entry->count > 1)
838 ULONG j, count = entry->count;
839 ULONG *ul = (ULONG *)(data_start + entry->value);
840 if (!count) count = 1;
841 for (j = 0; j < count; j++)
842 ul[j] = ulong_bswap(ul[j]);
844 entry->value = ulong_bswap(entry->value);
845 break;
847 case IFD_RATIONAL:
848 case IFD_SRATIONAL:
850 ULONG j;
851 ULONG *ul = (ULONG *)(data_start + entry->value);
852 for (j = 0; j < entry->count * 2; j++)
853 ul[j] = ulong_bswap(ul[j]);
855 entry->value = ulong_bswap(entry->value);
856 break;
858 case IFD_DOUBLE:
860 ULONG j;
861 ULONGLONG *ull = (ULONGLONG *)(data_start + entry->value);
862 for (j = 0; j < entry->count; j++)
863 ull[j] = ulonglong_bswap(ull[j]);
865 entry->value = ulong_bswap(entry->value);
866 break;
868 default:
869 assert(0);
870 break;
873 entry->id = ushort_bswap(entry->id);
874 entry->type = ushort_bswap(entry->type);
875 entry->count = ulong_bswap(entry->count);
876 data += sizeof(*entry);
880 static void test_metadata_IFD(void)
882 static const struct test_data td[28] =
884 { VT_UI2, 0xfe, 0, { 1 } },
885 { VT_UI4, 0x100, 0, { 222 } },
886 { VT_UI4, 0x101, 0, { 333 } },
887 { VT_UI2, 0x102, 0, { 24 } },
888 { VT_UI4, 0x103, 0, { 32773 } },
889 { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
890 { VT_UI1, 0xf001, 0, { 0x44 } },
891 { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
892 { VT_I1, 0xf003, 0, { 0x44 } },
893 { VT_I2, 0xf004, 0, { 0x3344 } },
894 { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
895 { VT_I4, 0xf006, 0, { 0x11223344 } },
896 { VT_R4, 0xf007, 0, { 0x11223344 } },
897 { VT_R8, 0xf008, 0, { ((LONGLONG)0x41d26580 << 32) | 0xb486522c } },
898 { VT_I8, 0xf009, 0, { ((LONGLONG)0x5a6b7c8d << 32) | 0x1a2b3c4d } },
899 { VT_UI1|VT_VECTOR, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
900 { VT_I2|VT_VECTOR, 0xf00b, 4, { 0x0101, 0x0202, 0x0303, 0x0404 } },
901 { VT_I4|VT_VECTOR, 0xf00c, 2, { 0x11223344, 0x55667788 } },
902 { VT_R4|VT_VECTOR, 0xf00d, 2, { 0x449a522b, 0x4608f5ba } },
903 { VT_LPSTR, 0xf00e, 12, { 0 }, "Hello World!" },
904 { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
905 { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
906 { VT_BLOB, 0xf011, 4, { 0 }, "abcd" },
907 { VT_UI1, 0xf012, 0, { 0x44 } },
908 { VT_UI2, 0xf013, 0, { 0x3344 } },
909 { VT_UI4, 0xf014, 0, { 0x11223344 } },
910 { VT_R4, 0xf015, 0, { 0x11223344 } },
911 { VT_I8|VT_VECTOR, 0xf016, 3,
912 { ((LONGLONG)0x05060708 << 32) | 0x01020304,
913 ((LONGLONG)0x50607080 << 32) | 0x10203040,
914 ((LONGLONG)0x55667788 << 32) | 0x11223344 } },
916 HRESULT hr;
917 IWICMetadataReader *reader;
918 IWICMetadataBlockReader *blockreader;
919 PROPVARIANT schema, id, value;
920 UINT count;
921 GUID format;
922 char *IFD_data_swapped;
923 #ifdef WORDS_BIGENDIAN
924 DWORD persist_options = WICPersistOptionBigEndian;
925 #else
926 DWORD persist_options = WICPersistOptionLittleEndian;
927 #endif
929 hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
930 &IID_IWICMetadataReader, (void**)&reader);
931 ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
933 hr = IWICMetadataReader_GetCount(reader, NULL);
934 ok(hr == E_INVALIDARG, "GetCount error %#lx\n", hr);
936 hr = IWICMetadataReader_GetCount(reader, &count);
937 ok(hr == S_OK, "GetCount error %#lx\n", hr);
938 ok(count == 0, "unexpected count %u\n", count);
940 load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data), persist_options);
942 hr = IWICMetadataReader_GetCount(reader, &count);
943 ok(hr == S_OK, "GetCount error %#lx\n", hr);
944 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
946 compare_metadata(reader, td, count);
948 /* test IFD data with different endianness */
949 if (persist_options == WICPersistOptionLittleEndian)
950 persist_options = WICPersistOptionBigEndian;
951 else
952 persist_options = WICPersistOptionLittleEndian;
954 IFD_data_swapped = HeapAlloc(GetProcessHeap(), 0, sizeof(IFD_data));
955 memcpy(IFD_data_swapped, &IFD_data, sizeof(IFD_data));
956 byte_swap_ifd_data(IFD_data_swapped);
957 load_stream((IUnknown *)reader, IFD_data_swapped, sizeof(IFD_data), persist_options);
958 hr = IWICMetadataReader_GetCount(reader, &count);
959 ok(hr == S_OK, "GetCount error %#lx\n", hr);
960 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
961 compare_metadata(reader, td, count);
962 HeapFree(GetProcessHeap(), 0, IFD_data_swapped);
964 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
965 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
966 ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", wine_dbgstr_guid(&format));
968 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
969 ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
971 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
972 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
974 PropVariantInit(&schema);
975 PropVariantInit(&id);
976 PropVariantInit(&value);
978 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
979 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
981 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
982 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
983 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
985 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
986 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
987 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
989 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
990 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
991 ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
992 ok(id.uiVal == 0xfe, "unexpected id: %#x\n", id.uiVal);
993 PropVariantClear(&id);
995 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
996 ok(hr == S_OK, "GetValueByIndex error %#lx\n", hr);
997 ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
998 ok(value.uiVal == 1, "unexpected id: %#x\n", value.uiVal);
999 PropVariantClear(&value);
1001 hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
1002 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1004 PropVariantInit(&schema);
1005 PropVariantInit(&id);
1006 PropVariantInit(&value);
1008 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
1009 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#lx\n", hr);
1011 hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
1012 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#lx\n", hr);
1014 hr = IWICMetadataReader_GetValue(reader, &schema, NULL, NULL);
1015 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1017 hr = IWICMetadataReader_GetValue(reader, &schema, &id, NULL);
1018 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#lx\n", hr);
1020 hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
1021 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1023 id.vt = VT_UI2;
1024 id.uiVal = 0xf00e;
1025 hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
1026 ok(hr == S_OK, "GetValue error %#lx\n", hr);
1028 /* schema is ignored by Ifd metadata reader */
1029 schema.vt = VT_UI4;
1030 schema.ulVal = 0xdeadbeef;
1031 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
1032 ok(hr == S_OK, "GetValue error %#lx\n", hr);
1033 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
1034 ok(!strcmp(value.pszVal, "Hello World!"), "unexpected value: %s\n", value.pszVal);
1035 PropVariantClear(&value);
1037 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
1038 ok(hr == S_OK, "GetValue error %#lx\n", hr);
1039 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
1040 ok(!strcmp(value.pszVal, "Hello World!"), "unexpected value: %s\n", value.pszVal);
1041 PropVariantClear(&value);
1043 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1044 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%lx\n", hr);
1046 if (SUCCEEDED(hr))
1047 IWICMetadataBlockReader_Release(blockreader);
1049 IWICMetadataReader_Release(reader);
1052 static void test_metadata_Exif(void)
1054 HRESULT hr;
1055 IWICMetadataReader *reader;
1056 IWICMetadataBlockReader *blockreader;
1057 UINT count=0;
1059 hr = CoCreateInstance(&CLSID_WICExifMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1060 &IID_IWICMetadataReader, (void**)&reader);
1061 todo_wine ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
1062 if (FAILED(hr)) return;
1064 hr = IWICMetadataReader_GetCount(reader, NULL);
1065 ok(hr == E_INVALIDARG, "GetCount error %#lx\n", hr);
1067 hr = IWICMetadataReader_GetCount(reader, &count);
1068 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1069 ok(count == 0, "unexpected count %u\n", count);
1071 hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1072 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%lx\n", hr);
1074 if (SUCCEEDED(hr))
1075 IWICMetadataBlockReader_Release(blockreader);
1077 IWICMetadataReader_Release(reader);
1080 static void test_create_reader(void)
1082 HRESULT hr;
1083 IWICComponentFactory *factory;
1084 IStream *stream;
1085 IWICMetadataReader *reader;
1086 UINT count=0;
1087 GUID format;
1089 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1090 &IID_IWICComponentFactory, (void**)&factory);
1091 ok(hr == S_OK, "CoCreateInstance failed, hr=%lx\n", hr);
1093 stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
1095 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1096 NULL, NULL, WICPersistOptionDefault,
1097 stream, &reader);
1098 ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%lx\n", hr);
1100 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1101 &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
1102 NULL, &reader);
1103 ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%lx\n", hr);
1105 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1106 &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
1107 stream, NULL);
1108 ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%lx\n", hr);
1110 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1111 &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
1112 stream, &reader);
1113 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%lx\n", hr);
1115 if (SUCCEEDED(hr))
1117 hr = IWICMetadataReader_GetCount(reader, &count);
1118 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
1119 ok(count == 1, "unexpected count %i\n", count);
1121 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1122 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
1123 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", wine_dbgstr_guid(&format));
1125 IWICMetadataReader_Release(reader);
1128 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1129 &GUID_ContainerFormatWmp, NULL, WICPersistOptionDefault,
1130 stream, &reader);
1131 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%lx\n", hr);
1133 if (SUCCEEDED(hr))
1135 hr = IWICMetadataReader_GetCount(reader, &count);
1136 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
1137 ok(count == 1, "unexpected count %i\n", count);
1139 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1140 ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
1141 ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", wine_dbgstr_guid(&format));
1143 IWICMetadataReader_Release(reader);
1146 IStream_Release(stream);
1148 IWICComponentFactory_Release(factory);
1151 static void test_metadata_png(void)
1153 static const struct test_data td[6] =
1155 { VT_UI2, 0, 0, { 2005 }, NULL, L"Year" },
1156 { VT_UI1, 0, 0, { 6 }, NULL, L"Month" },
1157 { VT_UI1, 0, 0, { 3 }, NULL, L"Day" },
1158 { VT_UI1, 0, 0, { 15 }, NULL, L"Hour" },
1159 { VT_UI1, 0, 0, { 7 }, NULL, L"Minute" },
1160 { VT_UI1, 0, 0, { 45 }, NULL, L"Second" }
1162 IStream *stream;
1163 IWICBitmapDecoder *decoder;
1164 IWICBitmapFrameDecode *frame;
1165 IWICMetadataBlockReader *blockreader;
1166 IWICMetadataReader *reader;
1167 IWICMetadataQueryReader *queryreader;
1168 IWICComponentFactory *factory;
1169 GUID containerformat;
1170 HRESULT hr;
1171 UINT count=0xdeadbeef;
1173 hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
1174 &IID_IWICBitmapDecoder, (void**)&decoder);
1175 ok(hr == S_OK, "CoCreateInstance failed, hr=%lx\n", hr);
1177 if (FAILED(hr)) return;
1179 stream = create_stream(pngimage, sizeof(pngimage));
1181 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1182 ok(hr == S_OK, "Initialize failed, hr=%lx\n", hr);
1184 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1185 ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%lx\n", hr);
1187 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1188 ok(hr == S_OK, "GetFrame failed, hr=%lx\n", hr);
1190 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1191 ok(hr == S_OK, "QueryInterface failed, hr=%lx\n", hr);
1193 if (SUCCEEDED(hr))
1195 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1196 ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%lx\n", hr);
1198 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &containerformat);
1199 ok(hr == S_OK, "GetContainerFormat failed, hr=%lx\n", hr);
1200 ok(IsEqualGUID(&containerformat, &GUID_ContainerFormatPng), "unexpected container format\n");
1202 hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1203 ok(hr == E_INVALIDARG, "GetCount failed, hr=%lx\n", hr);
1205 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1206 ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
1207 ok(count == 1, "unexpected count %d\n", count);
1209 if (0)
1211 /* Crashes on Windows XP */
1212 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, NULL);
1213 ok(hr == E_INVALIDARG, "GetReaderByIndex failed, hr=%lx\n", hr);
1216 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1217 ok(hr == S_OK, "GetReaderByIndex failed, hr=%lx\n", hr);
1219 if (SUCCEEDED(hr))
1221 hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
1222 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1223 ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
1224 broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
1225 "unexpected container format\n");
1227 hr = IWICMetadataReader_GetCount(reader, &count);
1228 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1229 ok(count == 6 || broken(count == 1) /* XP */, "expected 6, got %u\n", count);
1230 if (count == 6)
1231 compare_metadata(reader, td, count);
1233 IWICMetadataReader_Release(reader);
1236 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1237 todo_wine ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "GetReaderByIndex failed, hr=%lx\n", hr);
1239 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1240 &IID_IWICComponentFactory, (void**)&factory);
1241 ok(hr == S_OK, "CoCreateInstance failed, hr=%lx\n", hr);
1243 hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, NULL, &queryreader);
1244 ok(hr == E_INVALIDARG, "CreateQueryReaderFromBlockReader should have failed: %08lx\n", hr);
1246 hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, blockreader, NULL);
1247 ok(hr == E_INVALIDARG, "CreateQueryReaderFromBlockReader should have failed: %08lx\n", hr);
1249 hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, blockreader, &queryreader);
1250 ok(hr == S_OK, "CreateQueryReaderFromBlockReader failed: %08lx\n", hr);
1252 IWICMetadataQueryReader_Release(queryreader);
1254 IWICComponentFactory_Release(factory);
1256 IWICMetadataBlockReader_Release(blockreader);
1259 hr = IWICBitmapFrameDecode_GetMetadataQueryReader(frame, &queryreader);
1260 ok(hr == S_OK, "GetMetadataQueryReader failed: %08lx\n", hr);
1262 if (SUCCEEDED(hr))
1264 IWICMetadataQueryReader_Release(queryreader);
1267 IWICBitmapFrameDecode_Release(frame);
1269 IWICBitmapDecoder_Release(decoder);
1271 IStream_Release(stream);
1274 static void test_metadata_gif(void)
1276 static const struct test_data gif_LSD[9] =
1278 { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','7','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1279 { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1280 { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1281 { VT_BOOL, 0, 0, { 1 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1282 { VT_UI1, 0, 0, { 0 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1283 { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1284 { VT_UI1, 0, 0, { 0 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } },
1285 { VT_UI1, 0, 0, { 0 }, NULL, { 'B','a','c','k','g','r','o','u','n','d','C','o','l','o','r','I','n','d','e','x',0 } },
1286 { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1288 static const struct test_data gif_IMD[8] =
1290 { VT_UI2, 0, 0, { 0 }, NULL, { 'L','e','f','t',0 } },
1291 { VT_UI2, 0, 0, { 0 }, NULL, { 'T','o','p',0 } },
1292 { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1293 { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1294 { VT_BOOL, 0, 0, { 0 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1295 { VT_BOOL, 0, 0, { 0 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1296 { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1297 { VT_UI1, 0, 0, { 0 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } }
1299 static const struct test_data animated_gif_LSD[9] =
1301 { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','9','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1302 { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1303 { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1304 { VT_BOOL, 0, 0, { 1 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1305 { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1306 { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1307 { VT_UI1, 0, 0, { 1 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } },
1308 { VT_UI1, 0, 0, { 0 }, NULL, { 'B','a','c','k','g','r','o','u','n','d','C','o','l','o','r','I','n','d','e','x',0 } },
1309 { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1311 static const struct test_data animated_gif_IMD[8] =
1313 { VT_UI2, 0, 0, { 0 }, NULL, { 'L','e','f','t',0 } },
1314 { VT_UI2, 0, 0, { 0 }, NULL, { 'T','o','p',0 } },
1315 { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1316 { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1317 { VT_BOOL, 0, 0, { 1 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1318 { VT_BOOL, 0, 0, { 0 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1319 { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1320 { VT_UI1, 0, 0, { 1 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } }
1322 static const struct test_data animated_gif_GCE[5] =
1324 { VT_UI1, 0, 0, { 0 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
1325 { VT_BOOL, 0, 0, { 0 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
1326 { VT_BOOL, 0, 0, { 1 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
1327 { VT_UI2, 0, 0, { 10 }, NULL, { 'D','e','l','a','y',0 } },
1328 { VT_UI1, 0, 0, { 1 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 } }
1330 static const struct test_data animated_gif_APE[2] =
1332 { VT_UI1|VT_VECTOR, 0, 11, { 'A','N','I','M','E','X','T','S','1','.','0' }, NULL, { 'A','p','p','l','i','c','a','t','i','o','n',0 } },
1333 { VT_UI1|VT_VECTOR, 0, 4, { 0x03,0x01,0x05,0x00 }, NULL, { 'D','a','t','a',0 } }
1335 static const struct test_data animated_gif_comment_1[1] =
1337 { VT_LPSTR, 0, 12, { 0 }, "Hello World!", { 'T','e','x','t','E','n','t','r','y',0 } }
1339 static const struct test_data animated_gif_comment_2[1] =
1341 { VT_LPSTR, 0, 8, { 0 }, "image #1", { 'T','e','x','t','E','n','t','r','y',0 } }
1343 static const struct test_data animated_gif_plain_1[1] =
1345 { VT_BLOB, 0, 17, { 0 }, "\x21\x01\x0d\x61nimation.gif" }
1347 static const struct test_data animated_gif_plain_2[1] =
1349 { VT_BLOB, 0, 16, { 0 }, "\x21\x01\x0cplaintext #1" }
1351 IStream *stream;
1352 IWICBitmapDecoder *decoder;
1353 IWICBitmapFrameDecode *frame;
1354 IWICMetadataBlockReader *blockreader;
1355 IWICMetadataReader *reader;
1356 IWICMetadataQueryReader *queryreader;
1357 GUID format;
1358 HRESULT hr;
1359 UINT count;
1361 /* 1x1 pixel gif */
1362 stream = create_stream(gifimage, sizeof(gifimage));
1364 hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1365 &IID_IWICBitmapDecoder, (void **)&decoder);
1366 ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
1367 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1368 ok(hr == S_OK, "Initialize error %#lx\n", hr);
1370 IStream_Release(stream);
1372 /* global metadata block */
1373 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1374 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#lx\n", hr);
1376 if (SUCCEEDED(hr))
1378 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1379 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1380 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1381 "wrong container format %s\n", wine_dbgstr_guid(&format));
1383 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1384 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1385 ok(count == 1, "expected 1, got %u\n", count);
1387 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1388 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1390 if (SUCCEEDED(hr))
1392 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1393 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1394 ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1395 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1397 hr = IWICMetadataReader_GetCount(reader, &count);
1398 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1399 ok(count == ARRAY_SIZE(gif_LSD), "unexpected count %u\n", count);
1401 compare_metadata(reader, gif_LSD, count);
1403 IWICMetadataReader_Release(reader);
1406 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1407 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1409 IWICMetadataBlockReader_Release(blockreader);
1412 /* frame metadata block */
1413 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1414 ok(hr == S_OK, "GetFrame error %#lx\n", hr);
1416 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1417 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#lx\n", hr);
1419 if (SUCCEEDED(hr))
1421 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1422 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1424 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1425 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1426 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1427 "wrong container format %s\n", wine_dbgstr_guid(&format));
1429 hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1430 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1432 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1433 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1434 ok(count == 1, "expected 1, got %u\n", count);
1436 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1437 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1439 if (SUCCEEDED(hr))
1441 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1442 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1443 ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1444 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1446 hr = IWICMetadataReader_GetCount(reader, &count);
1447 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1448 ok(count == ARRAY_SIZE(gif_IMD), "unexpected count %u\n", count);
1450 compare_metadata(reader, gif_IMD, count);
1452 IWICMetadataReader_Release(reader);
1455 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1456 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1458 IWICMetadataBlockReader_Release(blockreader);
1461 IWICBitmapFrameDecode_Release(frame);
1462 IWICBitmapDecoder_Release(decoder);
1464 /* 1x1 pixel gif, 2 frames */
1465 stream = create_stream(animatedgif, sizeof(animatedgif));
1467 hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1468 &IID_IWICBitmapDecoder, (void **)&decoder);
1469 ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
1470 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1471 ok(hr == S_OK, "Initialize error %#lx\n", hr);
1473 IStream_Release(stream);
1475 /* global metadata block */
1476 hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1477 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#lx\n", hr);
1479 if (SUCCEEDED(hr))
1481 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1482 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1483 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1484 "wrong container format %s\n", wine_dbgstr_guid(&format));
1486 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1487 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1488 ok(count == 4, "expected 4, got %u\n", count);
1490 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1491 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1493 if (SUCCEEDED(hr))
1495 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1496 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1497 ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1498 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1500 hr = IWICMetadataReader_GetCount(reader, &count);
1501 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1502 ok(count == ARRAY_SIZE(animated_gif_LSD), "unexpected count %u\n", count);
1504 compare_metadata(reader, animated_gif_LSD, count);
1506 IWICMetadataReader_Release(reader);
1509 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1510 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1512 if (SUCCEEDED(hr))
1514 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1515 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1516 ok(IsEqualGUID(&format, &GUID_MetadataFormatAPE), /* Application Extension */
1517 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1519 hr = IWICMetadataReader_GetCount(reader, &count);
1520 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1521 ok(count == ARRAY_SIZE(animated_gif_APE), "unexpected count %u\n", count);
1523 compare_metadata(reader, animated_gif_APE, count);
1525 IWICMetadataReader_Release(reader);
1528 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 2, &reader);
1529 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1531 if (SUCCEEDED(hr))
1533 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1534 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1535 ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), /* Comment Extension */
1536 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1538 hr = IWICMetadataReader_GetCount(reader, &count);
1539 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1540 ok(count == ARRAY_SIZE(animated_gif_comment_1), "unexpected count %u\n", count);
1542 compare_metadata(reader, animated_gif_comment_1, count);
1544 IWICMetadataReader_Release(reader);
1547 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 3, &reader);
1548 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1550 if (SUCCEEDED(hr))
1552 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1553 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1554 ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown),
1555 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1557 hr = IWICMetadataReader_GetCount(reader, &count);
1558 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1559 ok(count == ARRAY_SIZE(animated_gif_plain_1), "unexpected count %u\n", count);
1561 compare_metadata(reader, animated_gif_plain_1, count);
1563 IWICMetadataReader_Release(reader);
1566 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 4, &reader);
1567 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1569 IWICMetadataBlockReader_Release(blockreader);
1572 /* frame metadata block */
1573 hr = IWICBitmapDecoder_GetFrame(decoder, 1, &frame);
1574 ok(hr == S_OK, "GetFrame error %#lx\n", hr);
1576 hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1577 ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#lx\n", hr);
1579 if (SUCCEEDED(hr))
1581 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1582 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1584 hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1585 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1586 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1587 "wrong container format %s\n", wine_dbgstr_guid(&format));
1589 hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1590 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1592 hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1593 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1594 ok(count == 4, "expected 4, got %u\n", count);
1596 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1597 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1599 if (SUCCEEDED(hr))
1601 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1602 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1603 ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1604 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1606 hr = IWICMetadataReader_GetCount(reader, &count);
1607 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1608 ok(count == ARRAY_SIZE(animated_gif_IMD), "unexpected count %u\n", count);
1610 compare_metadata(reader, animated_gif_IMD, count);
1612 IWICMetadataReader_Release(reader);
1615 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1616 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1618 if (SUCCEEDED(hr))
1620 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1621 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1622 ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), /* Graphic Control Extension */
1623 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1625 hr = IWICMetadataReader_GetCount(reader, &count);
1626 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1627 ok(count == ARRAY_SIZE(animated_gif_GCE), "unexpected count %u\n", count);
1629 compare_metadata(reader, animated_gif_GCE, count);
1631 IWICMetadataReader_Release(reader);
1634 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 2, &reader);
1635 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1637 if (SUCCEEDED(hr))
1639 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1640 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1641 ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), /* Comment Extension */
1642 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1644 hr = IWICMetadataReader_GetCount(reader, &count);
1645 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1646 ok(count == ARRAY_SIZE(animated_gif_comment_2), "unexpected count %u\n", count);
1648 if (count == 1)
1649 compare_metadata(reader, animated_gif_comment_2, count);
1651 IWICMetadataReader_Release(reader);
1654 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 3, &reader);
1655 ok(hr == S_OK, "GetReaderByIndex error %#lx\n", hr);
1657 if (SUCCEEDED(hr))
1659 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1660 ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
1661 ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown),
1662 "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1664 hr = IWICMetadataReader_GetCount(reader, &count);
1665 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1666 ok(count == ARRAY_SIZE(animated_gif_plain_2), "unexpected count %u\n", count);
1668 compare_metadata(reader, animated_gif_plain_2, count);
1670 IWICMetadataReader_Release(reader);
1673 hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 4, &reader);
1674 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#lx\n", hr);
1676 IWICMetadataBlockReader_Release(blockreader);
1679 hr = IWICBitmapDecoder_GetMetadataQueryReader(decoder, &queryreader);
1680 ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
1681 "GetMetadataQueryReader error %#lx\n", hr);
1682 if (SUCCEEDED(hr))
1684 static const struct
1686 const char *query;
1687 HRESULT hr;
1688 UINT vt;
1689 } decoder_data[] =
1691 { "/logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
1692 { "/[0]logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
1693 { "/logscrdesc/\\Signature", S_OK, VT_UI1 | VT_VECTOR },
1694 { "/Logscrdesc/\\signature", S_OK, VT_UI1 | VT_VECTOR },
1695 { "/logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
1696 { "/[0]logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
1697 { "/logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
1698 { "/[0]logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
1699 { "/appext/Application", S_OK, VT_UI1 | VT_VECTOR },
1700 { "/appext/{STR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
1701 { "/appext/{WSTR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
1702 { "/LogSCRdesC", S_OK, VT_UNKNOWN },
1703 { "/[0]LogSCRdesC", S_OK, VT_UNKNOWN },
1704 { "/appEXT", S_OK, VT_UNKNOWN },
1705 { "/[0]appEXT", S_OK, VT_UNKNOWN },
1706 { "grctlext", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
1707 { "/imgdesc", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1709 static const WCHAR rootW[] = {'/',0};
1710 WCHAR name[256];
1711 UINT len, i, j;
1712 PROPVARIANT value;
1713 IWICMetadataQueryReader *meta_reader;
1715 hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
1716 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1717 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1718 "wrong container format %s\n", wine_dbgstr_guid(&format));
1720 name[0] = 0;
1721 len = 0xdeadbeef;
1722 hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
1723 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
1724 ok(len == 2, "expected 2, got %u\n", len);
1725 ok(!lstrcmpW(name, rootW), "expected '/', got %s\n", wine_dbgstr_w(name));
1727 for (i = 0; i < ARRAY_SIZE(decoder_data); i++)
1729 WCHAR queryW[256];
1731 if (winetest_debug > 1)
1732 trace("query: %s\n", decoder_data[i].query);
1733 MultiByteToWideChar(CP_ACP, 0, decoder_data[i].query, -1, queryW, 256);
1735 hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, NULL);
1736 ok(hr == decoder_data[i].hr, "GetMetadataByName(%s) returned %#lx, expected %#lx\n", wine_dbgstr_w(queryW), hr, decoder_data[i].hr);
1738 PropVariantInit(&value);
1739 hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1740 ok(hr == decoder_data[i].hr, "GetMetadataByName(%s) returned %#lx, expected %#lx\n", wine_dbgstr_w(queryW), hr, decoder_data[i].hr);
1741 ok(value.vt == decoder_data[i].vt, "expected %#x, got %#x\n", decoder_data[i].vt, value.vt);
1742 if (hr == S_OK && value.vt == VT_UNKNOWN)
1744 hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&meta_reader);
1745 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
1747 name[0] = 0;
1748 len = 0xdeadbeef;
1749 hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name, &len);
1750 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
1751 ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
1752 ok(!lstrcmpW(name, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(name));
1754 for (j = 0; j < ARRAY_SIZE(decoder_data); j++)
1756 MultiByteToWideChar(CP_ACP, 0, decoder_data[j].query, -1, queryW, 256);
1758 if (CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, queryW, len-1, name, len-1) == CSTR_EQUAL && decoder_data[j].query[len - 1] != 0)
1760 if (winetest_debug > 1)
1761 trace("query: %s\n", wine_dbgstr_w(queryW + len - 1));
1762 PropVariantClear(&value);
1763 hr = IWICMetadataQueryReader_GetMetadataByName(meta_reader, queryW + len - 1, &value);
1764 ok(hr == decoder_data[j].hr, "GetMetadataByName(%s) returned %#lx, expected %#lx\n", wine_dbgstr_w(queryW + len - 1), hr, decoder_data[j].hr);
1765 ok(value.vt == decoder_data[j].vt, "expected %#x, got %#x\n", decoder_data[j].vt, value.vt);
1769 IWICMetadataQueryReader_Release(meta_reader);
1772 PropVariantClear(&value);
1775 IWICMetadataQueryReader_Release(queryreader);
1778 hr = IWICBitmapFrameDecode_GetMetadataQueryReader(frame, &queryreader);
1779 ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
1780 "GetMetadataQueryReader error %#lx\n", hr);
1781 if (SUCCEEDED(hr))
1783 static const struct
1785 const char *query;
1786 HRESULT hr;
1787 UINT vt;
1788 } frame_data[] =
1790 { "/grctlext/Delay", S_OK, VT_UI2 },
1791 { "/[0]grctlext/Delay", S_OK, VT_UI2 },
1792 { "/grctlext/{str=delay}", S_OK, VT_UI2 },
1793 { "/[0]grctlext/{str=delay}", S_OK, VT_UI2 },
1794 { "/grctlext/{wstr=delay}", S_OK, VT_UI2 },
1795 { "/[0]grctlext/{wstr=delay}", S_OK, VT_UI2 },
1796 { "/imgdesc/InterlaceFlag", S_OK, VT_BOOL },
1797 { "/imgdesc/{STR=interlaceFLAG}", S_OK, VT_BOOL },
1798 { "/imgdesc/{WSTR=interlaceFLAG}", S_OK, VT_BOOL },
1799 { "/grctlext", S_OK, VT_UNKNOWN },
1800 { "/[0]grctlext", S_OK, VT_UNKNOWN },
1801 { "/imgdesc", S_OK, VT_UNKNOWN },
1802 { "/[0]imgdesc", S_OK, VT_UNKNOWN },
1803 { "/LogSCRdesC", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1804 { "/appEXT", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1805 { "/grctlext/{\\str=delay}", WINCODEC_ERR_WRONGSTATE, 0 },
1806 { "/grctlext/{str=\\delay}", S_OK, VT_UI2 },
1807 { "grctlext/Delay", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
1809 static const WCHAR rootW[] = {'/',0};
1810 static const WCHAR guidW[] = {'/','{','g','u','i','d','=','\\',0};
1811 static const WCHAR imgdescW[] = {'i','m','g','d','e','s','c',0};
1812 static const WCHAR ImgDescW[] = {'I','m','g','D','e','s','c',0};
1813 WCHAR name[256], queryW[256];
1814 UINT len, i;
1815 PROPVARIANT value;
1816 IWICMetadataQueryReader *meta_reader;
1818 hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
1819 ok(hr == S_OK, "GetContainerFormat error %#lx\n", hr);
1820 ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1821 "wrong container format %s\n", wine_dbgstr_guid(&format));
1823 name[0] = 0;
1824 len = 0xdeadbeef;
1825 hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
1826 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
1827 ok(len == 2, "expected 2, got %u\n", len);
1828 ok(!lstrcmpW(name, rootW), "expected '/', got %s\n", wine_dbgstr_w(name));
1830 for (i = 0; i < ARRAY_SIZE(frame_data); i++)
1832 if (winetest_debug > 1)
1833 trace("query: %s\n", frame_data[i].query);
1834 MultiByteToWideChar(CP_ACP, 0, frame_data[i].query, -1, queryW, 256);
1835 PropVariantInit(&value);
1836 hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1837 ok(hr == frame_data[i].hr, "GetMetadataByName(%s) returned %#lx, expected %#lx\n", wine_dbgstr_w(queryW), hr, frame_data[i].hr);
1838 ok(value.vt == frame_data[i].vt, "expected %#x, got %#x\n", frame_data[i].vt, value.vt);
1839 if (hr == S_OK && value.vt == VT_UNKNOWN)
1841 hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&meta_reader);
1842 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
1844 name[0] = 0;
1845 len = 0xdeadbeef;
1846 hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name, &len);
1847 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
1848 ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
1849 ok(!lstrcmpW(name, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(name));
1851 IWICMetadataQueryReader_Release(meta_reader);
1854 PropVariantClear(&value);
1857 name[0] = 0;
1858 len = 0xdeadbeef;
1859 hr = WICMapGuidToShortName(&GUID_MetadataFormatIMD, 256, name, &len);
1860 ok(hr == S_OK, "WICMapGuidToShortName error %#lx\n", hr);
1861 ok(!lstrcmpW(name, imgdescW), "wrong short name %s\n", wine_dbgstr_w(name));
1863 format = GUID_NULL;
1864 hr = WICMapShortNameToGuid(imgdescW, &format);
1865 ok(hr == S_OK, "WICMapGuidToShortName error %#lx\n", hr);
1866 ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid %s\n", wine_dbgstr_guid(&format));
1868 format = GUID_NULL;
1869 hr = WICMapShortNameToGuid(ImgDescW, &format);
1870 ok(hr == S_OK, "WICMapGuidToShortName error %#lx\n", hr);
1871 ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid %s\n", wine_dbgstr_guid(&format));
1873 lstrcpyW(queryW, guidW);
1874 StringFromGUID2(&GUID_MetadataFormatIMD, queryW + lstrlenW(queryW) - 1, 39);
1875 memcpy(queryW, guidW, sizeof(guidW) - 2);
1876 if (winetest_debug > 1)
1877 trace("query: %s\n", wine_dbgstr_w(queryW));
1878 PropVariantInit(&value);
1879 hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1880 ok(hr == S_OK, "GetMetadataByName(%s) error %#lx\n", wine_dbgstr_w(queryW), hr);
1881 ok(value.vt == VT_UNKNOWN, "expected VT_UNKNOWN, got %#x\n", value.vt);
1882 PropVariantClear(&value);
1884 IWICMetadataQueryReader_Release(queryreader);
1887 IWICBitmapFrameDecode_Release(frame);
1888 IWICBitmapDecoder_Release(decoder);
1891 static void test_metadata_LSD(void)
1893 static const WCHAR LSD_name[] = {'L','o','g','i','c','a','l',' ','S','c','r','e','e','n',' ','D','e','s','c','r','i','p','t','o','r',' ','R','e','a','d','e','r',0};
1894 static const char LSD_data[] = "hello world!\x1\x2\x3\x4\xab\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf";
1895 static const struct test_data td[9] =
1897 { VT_UI1|VT_VECTOR, 0, 6, {'w','o','r','l','d','!'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1898 { VT_UI2, 0, 0, { 0x201 }, NULL, { 'W','i','d','t','h',0 } },
1899 { VT_UI2, 0, 0, { 0x403 }, NULL, { 'H','e','i','g','h','t',0 } },
1900 { VT_BOOL, 0, 0, { 1 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1901 { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1902 { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1903 { VT_UI1, 0, 0, { 3 }, NULL, { 'G','l','o','b','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } },
1904 { VT_UI1, 0, 0, { 6 }, NULL, { 'B','a','c','k','g','r','o','u','n','d','C','o','l','o','r','I','n','d','e','x',0 } },
1905 { VT_UI1, 0, 0, { 7 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1907 LARGE_INTEGER pos;
1908 HRESULT hr;
1909 IStream *stream;
1910 IWICPersistStream *persist;
1911 IWICMetadataReader *reader;
1912 IWICMetadataHandlerInfo *info;
1913 WCHAR name[64];
1914 UINT count, dummy;
1915 GUID format;
1916 CLSID id;
1918 hr = CoCreateInstance(&CLSID_WICLSDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1919 &IID_IWICMetadataReader, (void **)&reader);
1920 ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1921 "CoCreateInstance error %#lx\n", hr);
1923 stream = create_stream(LSD_data, sizeof(LSD_data));
1925 if (SUCCEEDED(hr))
1927 pos.QuadPart = 6;
1928 hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1929 ok(hr == S_OK, "IStream_Seek error %#lx\n", hr);
1931 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1932 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
1934 hr = IWICPersistStream_Load(persist, stream);
1935 ok(hr == S_OK, "Load error %#lx\n", hr);
1937 IWICPersistStream_Release(persist);
1940 if (SUCCEEDED(hr))
1942 hr = IWICMetadataReader_GetCount(reader, &count);
1943 ok(hr == S_OK, "GetCount error %#lx\n", hr);
1944 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
1946 compare_metadata(reader, td, count);
1948 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1949 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
1950 ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), "wrong format %s\n", wine_dbgstr_guid(&format));
1952 hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1953 ok(hr == S_OK, "GetMetadataHandlerInfo error %#lx\n", hr);
1955 hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1956 ok(hr == S_OK, "GetCLSID error %#lx\n", hr);
1957 ok(IsEqualGUID(&id, &CLSID_WICLSDMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
1959 hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1960 ok(hr == S_OK, "GetFriendlyName error %#lx\n", hr);
1961 ok(lstrcmpW(name, LSD_name) == 0, "wrong LSD reader name %s\n", wine_dbgstr_w(name));
1963 IWICMetadataHandlerInfo_Release(info);
1964 IWICMetadataReader_Release(reader);
1967 IStream_Release(stream);
1970 static void test_metadata_IMD(void)
1972 static const WCHAR IMD_name[] = {'I','m','a','g','e',' ','D','e','s','c','r','i','p','t','o','r',' ','R','e','a','d','e','r',0};
1973 static const char IMD_data[] = "hello world!\x1\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
1974 static const struct test_data td[8] =
1976 { VT_UI2, 0, 0, { 0x201 }, NULL, { 'L','e','f','t',0 } },
1977 { VT_UI2, 0, 0, { 0x403 }, NULL, { 'T','o','p',0 } },
1978 { VT_UI2, 0, 0, { 0x605 }, NULL, { 'W','i','d','t','h',0 } },
1979 { VT_UI2, 0, 0, { 0x807 }, NULL, { 'H','e','i','g','h','t',0 } },
1980 { VT_BOOL, 0, 0, { 1 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','F','l','a','g',0 } },
1981 { VT_BOOL, 0, 0, { 1 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1982 { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1983 { VT_UI1, 0, 0, { 5 }, NULL, { 'L','o','c','a','l','C','o','l','o','r','T','a','b','l','e','S','i','z','e',0 } }
1985 LARGE_INTEGER pos;
1986 HRESULT hr;
1987 IStream *stream;
1988 IWICPersistStream *persist;
1989 IWICMetadataReader *reader;
1990 IWICMetadataHandlerInfo *info;
1991 WCHAR name[64];
1992 UINT count, dummy;
1993 GUID format;
1994 CLSID id;
1996 hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1997 &IID_IWICMetadataReader, (void **)&reader);
1998 ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1999 "CoCreateInstance error %#lx\n", hr);
2001 stream = create_stream(IMD_data, sizeof(IMD_data));
2003 if (SUCCEEDED(hr))
2005 pos.QuadPart = 12;
2006 hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
2007 ok(hr == S_OK, "IStream_Seek error %#lx\n", hr);
2009 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2010 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
2012 hr = IWICPersistStream_Load(persist, stream);
2013 ok(hr == S_OK, "Load error %#lx\n", hr);
2015 IWICPersistStream_Release(persist);
2018 if (SUCCEEDED(hr))
2020 hr = IWICMetadataReader_GetCount(reader, &count);
2021 ok(hr == S_OK, "GetCount error %#lx\n", hr);
2022 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2024 compare_metadata(reader, td, count);
2026 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2027 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
2028 ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong format %s\n", wine_dbgstr_guid(&format));
2030 hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2031 ok(hr == S_OK, "GetMetadataHandlerInfo error %#lx\n", hr);
2033 hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
2034 ok(hr == S_OK, "GetCLSID error %#lx\n", hr);
2035 ok(IsEqualGUID(&id, &CLSID_WICIMDMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
2037 hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2038 ok(hr == S_OK, "GetFriendlyName error %#lx\n", hr);
2039 ok(lstrcmpW(name, IMD_name) == 0, "wrong IMD reader name %s\n", wine_dbgstr_w(name));
2041 IWICMetadataHandlerInfo_Release(info);
2042 IWICMetadataReader_Release(reader);
2045 IStream_Release(stream);
2048 static void test_metadata_GCE(void)
2050 static const WCHAR GCE_name[] = {'G','r','a','p','h','i','c',' ','C','o','n','t','r','o','l',' ','E','x','t','e','n','s','i','o','n',' ','R','e','a','d','e','r',0};
2051 static const char GCE_data[] = "hello world!\xa\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
2052 static const struct test_data td[5] =
2054 { VT_UI1, 0, 0, { 2 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
2055 { VT_BOOL, 0, 0, { 1 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
2056 { VT_BOOL, 0, 0, { 0 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
2057 { VT_UI2, 0, 0, { 0x302 }, NULL, { 'D','e','l','a','y',0 } },
2058 { VT_UI1, 0, 0, { 4 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 } }
2060 LARGE_INTEGER pos;
2061 HRESULT hr;
2062 IStream *stream;
2063 IWICPersistStream *persist;
2064 IWICMetadataReader *reader;
2065 IWICMetadataHandlerInfo *info;
2066 WCHAR name[64];
2067 UINT count, dummy;
2068 GUID format;
2069 CLSID id;
2071 hr = CoCreateInstance(&CLSID_WICGCEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
2072 &IID_IWICMetadataReader, (void **)&reader);
2073 ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
2074 "CoCreateInstance error %#lx\n", hr);
2076 stream = create_stream(GCE_data, sizeof(GCE_data));
2078 if (SUCCEEDED(hr))
2080 pos.QuadPart = 12;
2081 hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
2082 ok(hr == S_OK, "IStream_Seek error %#lx\n", hr);
2084 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2085 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
2087 hr = IWICPersistStream_Load(persist, stream);
2088 ok(hr == S_OK, "Load error %#lx\n", hr);
2090 IWICPersistStream_Release(persist);
2093 if (SUCCEEDED(hr))
2095 hr = IWICMetadataReader_GetCount(reader, &count);
2096 ok(hr == S_OK, "GetCount error %#lx\n", hr);
2097 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2099 compare_metadata(reader, td, count);
2101 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2102 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
2103 ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), "wrong format %s\n", wine_dbgstr_guid(&format));
2105 hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2106 ok(hr == S_OK, "GetMetadataHandlerInfo error %#lx\n", hr);
2108 hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
2109 ok(hr == S_OK, "GetCLSID error %#lx\n", hr);
2110 ok(IsEqualGUID(&id, &CLSID_WICGCEMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
2112 hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2113 ok(hr == S_OK, "GetFriendlyName error %#lx\n", hr);
2114 ok(lstrcmpW(name, GCE_name) == 0, "wrong GCE reader name %s\n", wine_dbgstr_w(name));
2116 IWICMetadataHandlerInfo_Release(info);
2117 IWICMetadataReader_Release(reader);
2120 IStream_Release(stream);
2123 static void test_metadata_APE(void)
2125 static const WCHAR APE_name[] = {'A','p','p','l','i','c','a','t','i','o','n',' ','E','x','t','e','n','s','i','o','n',' ','R','e','a','d','e','r',0};
2126 static const char APE_data[] = { 0x21,0xff,0x0b,'H','e','l','l','o',' ','W','o','r','l','d',
2127 /*sub-block*/1,0x11,
2128 /*sub-block*/2,0x22,0x33,
2129 /*sub-block*/4,0x44,0x55,0x66,0x77,
2130 /*terminator*/0 };
2131 static const struct test_data td[2] =
2133 { VT_UI1|VT_VECTOR, 0, 11, { 'H','e','l','l','o',' ','W','o','r','l','d' }, NULL, { 'A','p','p','l','i','c','a','t','i','o','n',0 } },
2134 { VT_UI1|VT_VECTOR, 0, 10, { 1,0x11,2,0x22,0x33,4,0x44,0x55,0x66,0x77 }, NULL, { 'D','a','t','a',0 } }
2136 WCHAR dataW[] = { 'd','a','t','a',0 };
2137 HRESULT hr;
2138 IStream *stream;
2139 IWICPersistStream *persist;
2140 IWICMetadataReader *reader;
2141 IWICMetadataHandlerInfo *info;
2142 WCHAR name[64];
2143 UINT count, dummy, i;
2144 GUID format;
2145 CLSID clsid;
2146 PROPVARIANT id, value;
2148 hr = CoCreateInstance(&CLSID_WICAPEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
2149 &IID_IWICMetadataReader, (void **)&reader);
2150 ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
2151 "CoCreateInstance error %#lx\n", hr);
2153 stream = create_stream(APE_data, sizeof(APE_data));
2155 if (SUCCEEDED(hr))
2157 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2158 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
2160 hr = IWICPersistStream_Load(persist, stream);
2161 ok(hr == S_OK, "Load error %#lx\n", hr);
2163 IWICPersistStream_Release(persist);
2166 if (SUCCEEDED(hr))
2168 hr = IWICMetadataReader_GetCount(reader, &count);
2169 ok(hr == S_OK, "GetCount error %#lx\n", hr);
2170 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2172 compare_metadata(reader, td, count);
2174 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2175 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
2176 ok(IsEqualGUID(&format, &GUID_MetadataFormatAPE), "wrong format %s\n", wine_dbgstr_guid(&format));
2178 PropVariantInit(&value);
2179 id.vt = VT_LPWSTR;
2180 id.pwszVal = dataW;
2182 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2183 ok(hr == S_OK, "GetValue error %#lx\n", hr);
2184 ok(value.vt == (VT_UI1|VT_VECTOR), "unexpected vt: %i\n", id.vt);
2185 ok(td[1].count == value.caub.cElems, "expected cElems %d, got %ld\n", td[1].count, value.caub.cElems);
2186 for (i = 0; i < value.caub.cElems; i++)
2187 ok(td[1].value[i] == value.caub.pElems[i], "%u: expected value %#I64x, got %#x\n", i, td[1].value[i], value.caub.pElems[i]);
2188 PropVariantClear(&value);
2190 hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2191 ok(hr == S_OK, "GetMetadataHandlerInfo error %#lx\n", hr);
2193 hr = IWICMetadataHandlerInfo_GetCLSID(info, &clsid);
2194 ok(hr == S_OK, "GetCLSID error %#lx\n", hr);
2195 ok(IsEqualGUID(&clsid, &CLSID_WICAPEMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&clsid));
2197 hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2198 ok(hr == S_OK, "GetFriendlyName error %#lx\n", hr);
2199 ok(lstrcmpW(name, APE_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
2201 IWICMetadataHandlerInfo_Release(info);
2202 IWICMetadataReader_Release(reader);
2205 IStream_Release(stream);
2208 static void test_metadata_GIF_comment(void)
2210 static const WCHAR GIF_comment_name[] = {'C','o','m','m','e','n','t',' ','E','x','t','e','n','s','i','o','n',' ','R','e','a','d','e','r',0};
2211 static const char GIF_comment_data[] = { 0x21,0xfe,
2212 /*sub-block*/5,'H','e','l','l','o',
2213 /*sub-block*/1,' ',
2214 /*sub-block*/6,'W','o','r','l','d','!',
2215 /*terminator*/0 };
2216 static const struct test_data td[1] =
2218 { VT_LPSTR, 0, 12, { 0 }, "Hello World!", { 'T','e','x','t','E','n','t','r','y',0 } }
2220 WCHAR text_entryW[] = { 'T','E','X','T','E','N','T','R','Y',0 };
2221 HRESULT hr;
2222 IStream *stream;
2223 IWICPersistStream *persist;
2224 IWICMetadataReader *reader;
2225 IWICMetadataHandlerInfo *info;
2226 WCHAR name[64];
2227 UINT count, dummy;
2228 GUID format;
2229 CLSID clsid;
2230 PROPVARIANT id, value;
2232 hr = CoCreateInstance(&CLSID_WICGifCommentMetadataReader, NULL, CLSCTX_INPROC_SERVER,
2233 &IID_IWICMetadataReader, (void **)&reader);
2234 ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
2235 "CoCreateInstance error %#lx\n", hr);
2237 stream = create_stream(GIF_comment_data, sizeof(GIF_comment_data));
2239 if (SUCCEEDED(hr))
2241 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2242 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
2244 hr = IWICPersistStream_Load(persist, stream);
2245 ok(hr == S_OK, "Load error %#lx\n", hr);
2247 IWICPersistStream_Release(persist);
2250 if (SUCCEEDED(hr))
2252 hr = IWICMetadataReader_GetCount(reader, &count);
2253 ok(hr == S_OK, "GetCount error %#lx\n", hr);
2254 ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2256 compare_metadata(reader, td, count);
2258 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2259 ok(hr == S_OK, "GetMetadataFormat error %#lx\n", hr);
2260 ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), "wrong format %s\n", wine_dbgstr_guid(&format));
2262 PropVariantInit(&value);
2263 id.vt = VT_LPWSTR;
2264 id.pwszVal = text_entryW;
2266 hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2267 ok(hr == S_OK, "GetValue error %#lx\n", hr);
2268 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
2269 ok(!strcmp(value.pszVal, "Hello World!"), "unexpected value: %s\n", value.pszVal);
2270 PropVariantClear(&value);
2272 hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2273 ok(hr == S_OK, "GetMetadataHandlerInfo error %#lx\n", hr);
2275 hr = IWICMetadataHandlerInfo_GetCLSID(info, &clsid);
2276 ok(hr == S_OK, "GetCLSID error %#lx\n", hr);
2277 ok(IsEqualGUID(&clsid, &CLSID_WICGifCommentMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&clsid));
2279 hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2280 ok(hr == S_OK, "GetFriendlyName error %#lx\n", hr);
2281 ok(lstrcmpW(name, GIF_comment_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
2283 IWICMetadataHandlerInfo_Release(info);
2284 IWICMetadataReader_Release(reader);
2287 IStream_Release(stream);
2290 static void test_WICMapGuidToShortName(void)
2292 static const WCHAR unkW[] = { 'u','n','k',0 };
2293 static const WCHAR unknownW[] = { 'u','n','k','n','o','w','n',0 };
2294 HRESULT hr;
2295 UINT len;
2296 WCHAR name[16];
2298 name[0] = 0;
2299 len = 0xdeadbeef;
2300 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, name, &len);
2301 ok(hr == S_OK, "got %#lx\n", hr);
2302 ok(len == 8, "got %u\n", len);
2303 ok(!lstrcmpW(name, unknownW), "got %s\n", wine_dbgstr_w(name));
2305 name[0] = 0;
2306 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, name, NULL);
2307 ok(hr == S_OK, "got %#lx\n", hr);
2308 ok(!lstrcmpW(name, unknownW), "got %s\n", wine_dbgstr_w(name));
2310 len = 0xdeadbeef;
2311 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, NULL, &len);
2312 ok(hr == S_OK, "got %#lx\n", hr);
2313 ok(len == 8, "got %u\n", len);
2315 len = 0xdeadbeef;
2316 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, NULL, &len);
2317 ok(hr == S_OK, "got %#lx\n", hr);
2318 ok(len == 8, "got %u\n", len);
2320 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, NULL, NULL);
2321 ok(hr == S_OK, "got %#lx\n", hr);
2323 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, NULL, NULL);
2324 ok(hr == S_OK, "got %#lx\n", hr);
2326 hr = WICMapGuidToShortName(&GUID_NULL, 0, NULL, NULL);
2327 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#lx\n", hr);
2329 name[0] = 0;
2330 len = 0xdeadbeef;
2331 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 4, name, &len);
2332 ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "got %#lx\n", hr);
2333 ok(len == 0xdeadbeef, "got %u\n", len);
2334 ok(!lstrcmpW(name, unkW), "got %s\n", wine_dbgstr_w(name));
2336 name[0] = 0;
2337 len = 0xdeadbeef;
2338 hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, name, &len);
2339 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2340 ok(len == 0xdeadbeef, "got %u\n", len);
2341 ok(!name[0], "got %s\n", wine_dbgstr_w(name));
2343 hr = WICMapGuidToShortName(NULL, 8, name, NULL);
2344 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2347 static void test_WICMapShortNameToGuid(void)
2349 static const WCHAR unkW[] = { 'u','n','k',0 };
2350 static const WCHAR xmpW[] = { 'x','m','p',0 };
2351 static const WCHAR XmPW[] = { 'X','m','P',0 };
2352 static const WCHAR unknownW[] = { 'u','n','k','n','o','w','n',0 };
2353 HRESULT hr;
2354 GUID guid;
2356 hr = WICMapShortNameToGuid(NULL, NULL);
2357 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2359 hr = WICMapShortNameToGuid(NULL, &guid);
2360 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2362 hr = WICMapShortNameToGuid(unknownW, NULL);
2363 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2365 hr = WICMapShortNameToGuid(unkW, &guid);
2366 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#lx\n", hr);
2368 hr = WICMapShortNameToGuid(unknownW, &guid);
2369 ok(hr == S_OK, "got %#lx\n", hr);
2370 ok(IsEqualGUID(&guid, &GUID_MetadataFormatUnknown), "got %s\n", wine_dbgstr_guid(&guid));
2372 hr = WICMapShortNameToGuid(xmpW, &guid);
2373 ok(hr == S_OK, "got %#lx\n", hr);
2374 ok(IsEqualGUID(&guid, &GUID_MetadataFormatXMP), "got %s\n", wine_dbgstr_guid(&guid));
2376 guid = GUID_NULL;
2377 hr = WICMapShortNameToGuid(XmPW, &guid);
2378 ok(hr == S_OK, "got %#lx\n", hr);
2379 ok(IsEqualGUID(&guid, &GUID_MetadataFormatXMP), "got %s\n", wine_dbgstr_guid(&guid));
2382 static const GUID *guid_list[] =
2384 &GUID_ContainerFormatBmp,
2385 &GUID_ContainerFormatPng,
2386 &GUID_ContainerFormatIco,
2387 &GUID_ContainerFormatJpeg,
2388 &GUID_ContainerFormatTiff,
2389 &GUID_ContainerFormatGif,
2390 &GUID_ContainerFormatWmp,
2391 &GUID_MetadataFormatUnknown,
2392 &GUID_MetadataFormatIfd,
2393 &GUID_MetadataFormatSubIfd,
2394 &GUID_MetadataFormatExif,
2395 &GUID_MetadataFormatGps,
2396 &GUID_MetadataFormatInterop,
2397 &GUID_MetadataFormatApp0,
2398 &GUID_MetadataFormatApp1,
2399 &GUID_MetadataFormatApp13,
2400 &GUID_MetadataFormatIPTC,
2401 &GUID_MetadataFormatIRB,
2402 &GUID_MetadataFormat8BIMIPTC,
2403 &GUID_MetadataFormat8BIMResolutionInfo,
2404 &GUID_MetadataFormat8BIMIPTCDigest,
2405 &GUID_MetadataFormatXMP,
2406 &GUID_MetadataFormatThumbnail,
2407 &GUID_MetadataFormatChunktEXt,
2408 &GUID_MetadataFormatXMPStruct,
2409 &GUID_MetadataFormatXMPBag,
2410 &GUID_MetadataFormatXMPSeq,
2411 &GUID_MetadataFormatXMPAlt,
2412 &GUID_MetadataFormatLSD,
2413 &GUID_MetadataFormatIMD,
2414 &GUID_MetadataFormatGCE,
2415 &GUID_MetadataFormatAPE,
2416 &GUID_MetadataFormatJpegChrominance,
2417 &GUID_MetadataFormatJpegLuminance,
2418 &GUID_MetadataFormatJpegComment,
2419 &GUID_MetadataFormatGifComment,
2420 &GUID_MetadataFormatChunkgAMA,
2421 &GUID_MetadataFormatChunkbKGD,
2422 &GUID_MetadataFormatChunkiTXt,
2423 &GUID_MetadataFormatChunkcHRM,
2424 &GUID_MetadataFormatChunkhIST,
2425 &GUID_MetadataFormatChunkiCCP,
2426 &GUID_MetadataFormatChunksRGB,
2427 &GUID_MetadataFormatChunktIME
2430 static WCHAR rdf_scheme[] = { 'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/','1','9','9','9','/','0','2','/','2','2','-','r','d','f','-','s','y','n','t','a','x','-','n','s','#',0 };
2431 static WCHAR dc_scheme[] = { 'h','t','t','p',':','/','/','p','u','r','l','.','o','r','g','/','d','c','/','e','l','e','m','e','n','t','s','/','1','.','1','/',0 };
2432 static WCHAR xmp_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2433 static WCHAR xmpidq_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','m','p','/','I','d','e','n','t','i','f','i','e','r','/','q','u','a','l','/','1','.','0','/',0 };
2434 static WCHAR xmpRights_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','r','i','g','h','t','s','/',0 };
2435 static WCHAR xmpMM_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','m','m','/',0 };
2436 static WCHAR xmpBJ_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','b','j','/',0 };
2437 static WCHAR xmpTPg_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','t','/','p','g','/',0 };
2438 static WCHAR pdf_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','p','d','f','/','1','.','3','/',0 };
2439 static WCHAR photoshop_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','p','h','o','t','o','s','h','o','p','/','1','.','0','/',0 };
2440 static WCHAR tiff_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','t','i','f','f','/','1','.','0','/',0 };
2441 static WCHAR exif_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','e','x','i','f','/','1','.','0','/',0 };
2442 static WCHAR stDim_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','D','i','m','e','n','s','i','o','n','s','#',0 };
2443 static WCHAR xapGImg_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','g','/','i','m','g','/',0 };
2444 static WCHAR stEvt_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','E','v','e','n','t','#',0 };
2445 static WCHAR stRef_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','R','e','s','o','u','r','c','e','R','e','f','#',0 };
2446 static WCHAR stVer_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','V','e','r','s','i','o','n','#',0 };
2447 static WCHAR stJob_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/','s','T','y','p','e','/','J','o','b','#',0 };
2448 static WCHAR aux_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','e','x','i','f','/','1','.','0','/','a','u','x','/',0 };
2449 static WCHAR crs_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','c','a','m','e','r','a','-','r','a','w','-','s','e','t','t','i','n','g','s','/','1','.','0','/',0 };
2450 static WCHAR xmpDM_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','m','p','/','1','.','0','/','D','y','n','a','m','i','c','M','e','d','i','a','/',0 };
2451 static WCHAR Iptc4xmpCore_scheme[] = { 'h','t','t','p',':','/','/','i','p','t','c','.','o','r','g','/','s','t','d','/','I','p','t','c','4','x','m','p','C','o','r','e','/','1','.','0','/','x','m','l','n','s','/',0 };
2452 static WCHAR MicrosoftPhoto_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','0','/',0 };
2453 static WCHAR MP_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/',0 };
2454 static WCHAR MPRI_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/','t','/','R','e','g','i','o','n','I','n','f','o','#',0 };
2455 static WCHAR MPReg_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','m','i','c','r','o','s','o','f','t','.','c','o','m','/','p','h','o','t','o','/','1','.','2','/','t','/','R','e','g','i','o','n','#',0 };
2457 static WCHAR *schema_list[] =
2459 aux_scheme,
2460 rdf_scheme,
2461 dc_scheme,
2462 xmp_scheme,
2463 xmpidq_scheme,
2464 xmpRights_scheme,
2465 xmpMM_scheme,
2466 xmpBJ_scheme,
2467 xmpTPg_scheme,
2468 pdf_scheme,
2469 photoshop_scheme,
2470 tiff_scheme,
2471 exif_scheme,
2472 stDim_scheme,
2473 xapGImg_scheme,
2474 stEvt_scheme,
2475 stRef_scheme,
2476 stVer_scheme,
2477 stJob_scheme,
2478 crs_scheme,
2479 xmpDM_scheme,
2480 Iptc4xmpCore_scheme,
2481 MicrosoftPhoto_scheme,
2482 MP_scheme,
2483 MPRI_scheme,
2484 MPReg_scheme
2487 static void test_WICMapSchemaToName(void)
2489 static const WCHAR xmW[] = { 'x','m',0 };
2490 static const WCHAR xmpW[] = { 'x','m','p',0 };
2491 static WCHAR schemaW[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2492 static WCHAR SCHEMAW[] = { 'H','T','T','P',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2493 HRESULT hr;
2494 UINT len, i, j;
2495 WCHAR name[16];
2497 hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, NULL, 0, NULL, NULL);
2498 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2500 hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, schemaW, 0, NULL, NULL);
2501 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2503 hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, schemaW, 0, NULL, &len);
2504 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#lx\n", hr);
2506 hr = WICMapSchemaToName(NULL, schemaW, 0, NULL, &len);
2507 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2509 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, NULL, NULL);
2510 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2512 len = 0xdeadbeef;
2513 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, NULL, &len);
2514 ok(hr == S_OK, "got %#lx\n", hr);
2515 ok(len == 4, "got %u\n", len);
2517 len = 0xdeadbeef;
2518 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, NULL, &len);
2519 ok(hr == S_OK, "got %#lx\n", hr);
2520 ok(len == 4, "got %u\n", len);
2522 len = 0xdeadbeef;
2523 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, SCHEMAW, 0, NULL, &len);
2524 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#lx\n", hr);
2525 ok(len == 0xdeadbeef, "got %u\n", len);
2527 name[0] = 0;
2528 len = 0xdeadbeef;
2529 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, name, &len);
2530 ok(hr == S_OK, "got %#lx\n", hr);
2531 ok(len == 4, "got %u\n", len);
2532 ok(!lstrcmpW(name, xmpW), "got %s\n", wine_dbgstr_w(name));
2534 len = 0xdeadbeef;
2535 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, name, &len);
2536 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2537 ok(len == 0xdeadbeef, "got %u\n", len);
2539 name[0] = 0;
2540 len = 0xdeadbeef;
2541 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 3, name, &len);
2542 ok(hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "got %#lx\n", hr);
2543 ok(len == 0xdeadbeef, "got %u\n", len);
2544 ok(!lstrcmpW(name, xmW), "got %s\n", wine_dbgstr_w(name));
2546 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, name, NULL);
2547 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
2549 /* Check whether modern schemas are supported */
2550 hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schema_list[0], 0, NULL, &len);
2551 if (hr == WINCODEC_ERR_PROPERTYNOTFOUND)
2553 win_skip("Modern schemas are not supported\n");
2554 return;
2557 for (i = 0; i < ARRAY_SIZE(guid_list); i++)
2559 for (j = 0; j < ARRAY_SIZE(schema_list); j++)
2561 hr = WICMapSchemaToName(guid_list[i], schema_list[j], 0, NULL, &len);
2562 if (IsEqualGUID(guid_list[i], &GUID_MetadataFormatXMP) ||
2563 IsEqualGUID(guid_list[i], &GUID_MetadataFormatXMPStruct))
2565 ok(hr == S_OK, "%u: %u: format %s does not support schema %s\n",
2566 i, j, wine_dbgstr_guid(guid_list[i]), wine_dbgstr_w(schema_list[j]));
2568 else
2570 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "%u: %u: format %s supports schema %s\n",
2571 i, j, wine_dbgstr_guid(guid_list[i]), wine_dbgstr_w(schema_list[j]));
2577 struct metadata_item
2579 const char *schema, *id_str;
2580 UINT id, type, value;
2583 struct metadata_block
2585 const GUID *metadata_format;
2586 UINT count;
2587 const struct metadata_item *item;
2590 struct metadata
2592 const GUID *container_format;
2593 UINT count;
2594 const struct metadata_block *block;
2597 static const struct metadata *current_metadata;
2598 static const struct metadata_block *current_metadata_block;
2600 static char the_best[] = "The Best";
2601 static char the_worst[] = "The Worst";
2603 static HRESULT WINAPI mdr_QueryInterface(IWICMetadataReader *iface, REFIID iid, void **out)
2605 trace("%p,%s,%p\n", iface, wine_dbgstr_guid(iid), out);
2607 if (IsEqualIID(iid, &IID_IUnknown) ||
2608 IsEqualIID(iid, &IID_IWICMetadataReader))
2610 *out = iface;
2611 return S_OK;
2614 ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid));
2616 *out = NULL;
2617 return E_NOINTERFACE;
2620 static ULONG WINAPI mdr_AddRef(IWICMetadataReader *iface)
2622 return 2;
2625 static ULONG WINAPI mdr_Release(IWICMetadataReader *iface)
2627 return 1;
2630 static HRESULT WINAPI mdr_GetMetadataFormat(IWICMetadataReader *iface, GUID *format)
2632 trace("%p,%p\n", iface, format);
2634 ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2635 if (!current_metadata_block) return E_POINTER;
2637 *format = *current_metadata_block->metadata_format;
2638 return S_OK;
2641 static HRESULT WINAPI mdr_GetMetadataHandlerInfo(IWICMetadataReader *iface, IWICMetadataHandlerInfo **handler)
2643 ok(0, "not implemented\n");
2644 return E_NOTIMPL;
2647 static HRESULT WINAPI mdr_GetCount(IWICMetadataReader *iface, UINT *count)
2649 trace("%p,%p\n", iface, count);
2651 ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2652 if (!current_metadata_block) return E_POINTER;
2654 *count = current_metadata_block->count;
2655 return S_OK;
2658 static HRESULT WINAPI mdr_GetValueByIndex(IWICMetadataReader *iface, UINT index, PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value)
2660 ok(0, "not implemented\n");
2661 return E_NOTIMPL;
2664 static char *get_temp_buffer(int size)
2666 static char buf[16][256];
2667 static int idx;
2668 char *p;
2670 assert(size < 256);
2672 p = buf[idx & 0x0f];
2673 idx++;
2674 return p;
2677 static const char *wine_dbgstr_propvariant(const PROPVARIANT *var)
2679 char *ret;
2681 if (!var) return "(null)";
2683 switch (var->vt)
2685 case VT_LPWSTR:
2686 ret = get_temp_buffer(lstrlenW(var->pwszVal) + 16);
2687 sprintf(ret, "(VT_LPWSTR:%s)", wine_dbgstr_w(var->pwszVal));
2688 break;
2690 case VT_LPSTR:
2691 ret = get_temp_buffer(lstrlenA(var->pszVal) + 16);
2692 sprintf(ret, "(VT_LPSTR:%s)", var->pszVal);
2693 break;
2695 default:
2696 ret = get_temp_buffer(16);
2697 sprintf(ret, "(vt:%u)", var->vt);
2698 break;
2701 return ret;
2704 static int propvar_cmp(const PROPVARIANT *v1, LONGLONG value2)
2706 LONGLONG value1;
2708 if (PropVariantToInt64(v1, &value1) != S_OK) return -1;
2710 value1 -= value2;
2711 if (value1) return value1 < 0 ? -1 : 1;
2712 return 0;
2715 static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value)
2717 UINT i;
2719 trace("%p,%s,%s,%s\n", iface, wine_dbgstr_propvariant(schema), wine_dbgstr_propvariant(id), wine_dbgstr_propvariant(value));
2721 ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2722 if (!current_metadata_block) return E_POINTER;
2724 ok(schema != NULL && id != NULL && value != NULL, "%p, %p, %p should not be NULL\n", schema, id, value);
2726 for (i = 0; i < current_metadata_block->count; i++)
2728 if (schema->vt != VT_EMPTY)
2730 if (!current_metadata_block->item[i].schema)
2731 continue;
2733 switch (schema->vt)
2735 case VT_LPSTR:
2736 if (lstrcmpA(schema->pszVal, current_metadata_block->item[i].schema) != 0)
2737 continue;
2738 break;
2740 case VT_LPWSTR:
2742 char schemaA[256];
2743 WideCharToMultiByte(CP_ACP, 0, schema->pwszVal, -1, schemaA, sizeof(schemaA), NULL, NULL);
2744 if (lstrcmpA(schemaA, current_metadata_block->item[i].schema) != 0)
2745 continue;
2746 break;
2749 default:
2750 ok(0, "unsupported schema vt %u\n", schema->vt);
2751 continue;
2754 else if (current_metadata_block->item[i].schema)
2755 continue;
2757 switch (id->vt)
2759 case VT_LPSTR:
2760 if (current_metadata_block->item[i].id_str)
2762 if (!lstrcmpA(id->pszVal, current_metadata_block->item[i].id_str))
2764 value->vt = VT_LPSTR;
2765 value->pszVal = the_best;
2766 return S_OK;
2768 break;
2770 break;
2772 case VT_LPWSTR:
2773 if (current_metadata_block->item[i].id_str)
2775 char idA[256];
2776 WideCharToMultiByte(CP_ACP, 0, id->pwszVal, -1, idA, sizeof(idA), NULL, NULL);
2777 if (!lstrcmpA(idA, current_metadata_block->item[i].id_str))
2779 value->vt = VT_LPSTR;
2780 value->pszVal = the_worst;
2781 return S_OK;
2783 break;
2785 break;
2787 case VT_CLSID:
2788 if (IsEqualGUID(id->puuid, &GUID_MetadataFormatXMP) ||
2789 IsEqualGUID(id->puuid, &GUID_ContainerFormatTiff))
2791 value->vt = VT_UNKNOWN;
2792 value->punkVal = (IUnknown *)iface;
2793 return S_OK;
2795 break;
2797 default:
2798 if (!propvar_cmp(id, current_metadata_block->item[i].id))
2800 value->vt = current_metadata_block->item[i].type;
2801 value->uiVal = current_metadata_block->item[i].value;
2802 return S_OK;
2804 break;
2808 return 0xdeadbeef;
2811 static HRESULT WINAPI mdr_GetEnumerator(IWICMetadataReader *iface, IWICEnumMetadataItem **enumerator)
2813 ok(0, "not implemented\n");
2814 return E_NOTIMPL;
2817 static const IWICMetadataReaderVtbl mdr_vtbl =
2819 mdr_QueryInterface,
2820 mdr_AddRef,
2821 mdr_Release,
2822 mdr_GetMetadataFormat,
2823 mdr_GetMetadataHandlerInfo,
2824 mdr_GetCount,
2825 mdr_GetValueByIndex,
2826 mdr_GetValue,
2827 mdr_GetEnumerator
2830 static IWICMetadataReader mdr = { &mdr_vtbl };
2832 static HRESULT WINAPI mdbr_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, void **out)
2834 if (IsEqualIID(iid, &IID_IUnknown) ||
2835 IsEqualIID(iid, &IID_IWICMetadataBlockReader))
2837 *out = iface;
2838 return S_OK;
2841 /* Windows 8/10 query for some undocumented IID */
2842 if (!IsEqualIID(iid, &IID_MdbrUnknown))
2843 ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid));
2845 *out = NULL;
2846 return E_NOINTERFACE;
2849 static ULONG WINAPI mdbr_AddRef(IWICMetadataBlockReader *iface)
2851 return 2;
2854 static ULONG WINAPI mdbr_Release(IWICMetadataBlockReader *iface)
2856 return 1;
2859 static HRESULT WINAPI mdbr_GetContainerFormat(IWICMetadataBlockReader *iface, GUID *format)
2861 trace("%p,%p\n", iface, format);
2863 ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2864 if (!current_metadata) return E_POINTER;
2866 *format = *current_metadata->container_format;
2867 return S_OK;
2870 static HRESULT WINAPI mdbr_GetCount(IWICMetadataBlockReader *iface, UINT *count)
2872 trace("%p,%p\n", iface, count);
2874 ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2875 if (!current_metadata) return E_POINTER;
2877 *count = current_metadata->count;
2878 return S_OK;
2881 static HRESULT WINAPI mdbr_GetReaderByIndex(IWICMetadataBlockReader *iface, UINT index, IWICMetadataReader **out)
2883 trace("%p,%u,%p\n", iface, index, out);
2885 *out = NULL;
2887 ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2888 if (!current_metadata) return E_POINTER;
2890 if (index < current_metadata->count)
2892 current_metadata_block = &current_metadata->block[index];
2893 *out = &mdr;
2894 return S_OK;
2897 current_metadata_block = NULL;
2898 return E_INVALIDARG;
2901 static HRESULT WINAPI mdbr_GetEnumerator(IWICMetadataBlockReader *iface, IEnumUnknown **enumerator)
2903 ok(0, "not implemented\n");
2904 return E_NOTIMPL;
2907 static const IWICMetadataBlockReaderVtbl mdbr_vtbl =
2909 mdbr_QueryInterface,
2910 mdbr_AddRef,
2911 mdbr_Release,
2912 mdbr_GetContainerFormat,
2913 mdbr_GetCount,
2914 mdbr_GetReaderByIndex,
2915 mdbr_GetEnumerator
2918 static IWICMetadataBlockReader mdbr = { &mdbr_vtbl };
2920 static const char xmp[] = "http://ns.adobe.com/xap/1.0/";
2921 static const char dc[] = "http://purl.org/dc/elements/1.1/";
2922 static const char tiff[] = "http://ns.adobe.com/tiff/1.0/";
2924 static const struct metadata_item item1[] =
2926 { NULL, NULL, 1, 2, 3 }
2929 static const struct metadata_item item2[] =
2931 { NULL, NULL, 1, 2, 3 },
2932 { "xmp", "Rating", 4, 5, 6 },
2933 { NULL, "Rating", 7, 8, 9 }
2936 static const struct metadata_item item3[] =
2938 { NULL, NULL, 1, 2, 3 },
2939 { NULL, NULL, 4, 5, 6 },
2940 { NULL, NULL, 7, 8, 9 },
2941 { NULL, NULL, 10, 11, 12 }
2944 static const struct metadata_item item4[] =
2946 { NULL, NULL, 1, 2, 3 },
2947 { xmp, "Rating", 4, 5, 6 },
2948 { dc, NULL, 7, 8, 9 },
2949 { tiff, NULL, 10, 11, 12 },
2950 { NULL, "RATING", 13, 14, 15 },
2951 { NULL, "R}ATING", 16, 17, 18 },
2952 { NULL, "xmp", 19, 20, 21 }
2955 static const struct metadata_block block1[] =
2957 { &GUID_MetadataFormatIfd, 1, item1 }
2960 static const struct metadata_block block2[] =
2962 { &GUID_MetadataFormatXMP, 1, item1 },
2963 { &GUID_MetadataFormatIfd, 3, item2 }
2966 static const struct metadata_block block3[] =
2968 { &GUID_MetadataFormatXMP, 1, item1 },
2969 { &GUID_MetadataFormatIfd, 3, item2 },
2970 { &GUID_MetadataFormatXMP, 4, item3 },
2971 { &GUID_MetadataFormatXMP, 7, item4 },
2972 { &GUID_MetadataFormatIfd, 7, item4 }
2975 static const struct metadata data1 =
2977 &GUID_ContainerFormatGif,
2978 1, block1
2981 static const struct metadata data2 =
2983 &GUID_ContainerFormatTiff,
2984 2, block2
2987 static const struct metadata data3 =
2989 &GUID_ContainerFormatPng,
2990 5, block3
2993 static void test_queryreader(void)
2995 static const char q1[] = "/ifd/{uchar=1}";
2996 static const char q2[] = "/ifd/xmp:{long=4}";
2997 static const char q3[] = "/ifd/{str=xmp}:{uint=4}";
2998 static const char q4[] = "/xmp/{char=7}";
2999 static const char q5[] = "/[1]xmp/{short=7}";
3000 static const char q6[] = "/[1]ifd/{str=dc}:{uint=7}";
3001 static const char q7[] = "/[1]ifd/{str=http://purl.org/dc/elements/1.1/}:{longlong=7}";
3002 static const char q8[] = "/[1]ifd/{str=http://ns.adobe.com/tiff/1.0/}:{int=10}";
3003 static const char q9[] = "/[2]xmp/xmp:{ulong=4}";
3004 static const char q10[] = "/[2]xmp/{str=xmp}:{ulong=4}";
3005 static const char q11[] = "/xmp";
3006 static const char q12[] = "/ifd/xmp";
3007 static const char q13[] = "/ifd/xmp/tiff";
3008 static const char q14[] = "/[0]ifd/[0]xmp/[0]tiff";
3009 static const char q15[] = "/[*]xmp";
3011 static const char q20[] = "/ifd/\\Rating";
3012 static const char q21[] = "/[0]ifd/Rating";
3013 static const char q22[] = "/[2]xmp/xmp:{str=Rating}";
3014 static const char q23[] = "/[2]xmp/xmp:Rating";
3016 static const char q24[] = "/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:Rating";
3017 static const char q25[] = "/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:{str=Rating}";
3018 static const char q26[] = "/[1]ifd/{wstr=\\RATING}";
3019 static const char q27[] = "/[1]ifd/{str=R\\ATING}";
3020 static const char q28[] = "/[1]ifd/{str=R\\}ATING}";
3022 static const char q40[] = "[0]/ifd/Rating";
3023 static const char q41[] = "/[+1]ifd/Rating";
3024 static const char q42[] = "/[-1]ifd/Rating";
3025 static const char q43[] = "/ifd/{\\str=Rating}";
3026 static const char q44[] = "/ifd/{badtype=0}";
3027 static const char q45[] = "/ifd/{uint=0x1234}";
3028 static const char q46[] = "/ifd/[0]Rating";
3029 static const char q47[] = "/ifd/[*]Rating";
3030 static const struct
3032 BOOL todo;
3033 const struct metadata *data;
3034 const char *query;
3035 HRESULT hr;
3036 UINT vt, value;
3037 const char *str_value;
3038 } test_data[] =
3040 { FALSE, &data1, q1, S_OK, 2, 3, NULL },
3041 { FALSE, &data2, q2, S_OK, 5, 6, NULL },
3042 { FALSE, &data2, q3, S_OK, 5, 6, NULL },
3043 { FALSE, &data3, q4, 0xdeadbeef },
3044 { FALSE, &data3, q5, S_OK, 8, 9, NULL },
3045 { FALSE, &data3, q6, 0xdeadbeef },
3046 { FALSE, &data3, q7, S_OK, 8, 9, NULL },
3047 { FALSE, &data3, q8, S_OK, 11, 12, NULL },
3048 { FALSE, &data3, q9, S_OK, 5, 6, NULL },
3049 { FALSE, &data3, q10, 0xdeadbeef },
3051 { FALSE, &data3, q11, S_OK, VT_UNKNOWN, 0, NULL },
3052 { FALSE, &data3, q12, S_OK, VT_UNKNOWN, 0, NULL },
3053 { FALSE, &data3, q13, S_OK, VT_UNKNOWN, 0, NULL },
3054 { FALSE, &data3, q14, S_OK, VT_UNKNOWN, 0, NULL },
3055 { TRUE, &data3, q15, S_OK, VT_LPSTR, 0, the_worst },
3057 { FALSE, &data3, q20, S_OK, VT_LPSTR, 0, the_worst },
3058 { FALSE, &data3, q21, S_OK, VT_LPSTR, 0, the_worst },
3059 { FALSE, &data3, q22, S_OK, VT_LPSTR, 0, the_best },
3060 { FALSE, &data3, q23, S_OK, VT_LPSTR, 0, the_worst },
3061 { FALSE, &data3, q24, S_OK, VT_LPSTR, 0, the_worst },
3062 { FALSE, &data3, q25, S_OK, VT_LPSTR, 0, the_best },
3063 { FALSE, &data3, q26, S_OK, VT_LPSTR, 0, the_worst },
3064 { FALSE, &data3, q27, S_OK, VT_LPSTR, 0, the_best },
3065 { FALSE, &data3, q28, S_OK, VT_LPSTR, 0, the_best },
3067 { FALSE, &data1, q40, WINCODEC_ERR_PROPERTYNOTSUPPORTED },
3068 { TRUE, &data1, q41, WINCODEC_ERR_INVALIDQUERYCHARACTER },
3069 { TRUE, &data1, q42, WINCODEC_ERR_INVALIDQUERYCHARACTER },
3070 { FALSE, &data1, q43, WINCODEC_ERR_WRONGSTATE },
3071 { FALSE, &data1, q44, WINCODEC_ERR_WRONGSTATE },
3072 { TRUE, &data1, q45, DISP_E_TYPEMISMATCH },
3073 { TRUE, &data1, q46, E_INVALIDARG },
3074 { TRUE, &data1, q47, WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT },
3076 WCHAR queryW[256];
3077 HRESULT hr;
3078 IWICComponentFactory *factory;
3079 IWICMetadataQueryReader *reader;
3080 GUID format;
3081 PROPVARIANT value;
3082 UINT i;
3084 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
3085 &IID_IWICComponentFactory, (void **)&factory);
3086 ok(hr == S_OK, "CoCreateInstance error %#lx\n", hr);
3088 hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &mdbr, &reader);
3089 ok(hr == S_OK, "CreateQueryReaderFromBlockReader error %#lx\n", hr);
3091 for (i = 0; i < ARRAY_SIZE(test_data); i++)
3093 current_metadata = test_data[i].data;
3095 hr = IWICMetadataQueryReader_GetContainerFormat(reader, &format);
3096 ok(hr == S_OK, "%u: GetContainerFormat error %#lx\n", i, hr);
3097 ok(IsEqualGUID(&format, test_data[i].data->container_format), "%u: expected %s, got %s\n",
3098 i, wine_dbgstr_guid(test_data[i].data->container_format), wine_dbgstr_guid(&format));
3100 MultiByteToWideChar(CP_ACP, 0, test_data[i].query, -1, queryW, 256);
3101 PropVariantInit(&value);
3102 hr = IWICMetadataQueryReader_GetMetadataByName(reader, queryW, &value);
3103 todo_wine_if(test_data[i].todo)
3104 ok(hr == test_data[i].hr, "%u: expected %#lx, got %#lx\n", i, test_data[i].hr, hr);
3105 if (hr == S_OK)
3107 ok(value.vt == test_data[i].vt, "%u: expected %u, got %u\n", i, test_data[i].vt, value.vt);
3108 if (test_data[i].vt == value.vt)
3110 if (value.vt == VT_UNKNOWN)
3112 IWICMetadataQueryReader *new_reader;
3113 WCHAR location[256];
3114 UINT len;
3116 hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&new_reader);
3117 ok(hr == S_OK, "QueryInterface error %#lx\n", hr);
3119 location[0] = 0;
3120 len = 0xdeadbeef;
3121 hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location, &len);
3122 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
3123 ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3124 ok(!lstrcmpW(location, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(location));
3126 hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location, NULL);
3127 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
3129 location[0] = 0;
3130 len = 0xdeadbeef;
3131 hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, location, &len);
3132 ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#lx\n", hr);
3133 ok(len == 0xdeadbeef, "got %u\n", len);
3134 ok(!location[0], "got %s\n", wine_dbgstr_w(location));
3136 location[0] = 0;
3137 len = 0xdeadbeef;
3138 hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, location, &len);
3139 ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#lx\n", hr);
3140 ok(len == 0xdeadbeef, "got %u\n", len);
3141 ok(!location[0], "got %s\n", wine_dbgstr_w(location));
3143 len = 0xdeadbeef;
3144 hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL, &len);
3145 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
3146 ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3148 len = 0xdeadbeef;
3149 hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, NULL, &len);
3150 ok(hr == S_OK, "GetLocation error %#lx\n", hr);
3151 ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3153 hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL, NULL);
3154 ok(hr == E_INVALIDARG, "got %#lx\n", hr);
3156 IWICMetadataQueryReader_Release(new_reader);
3157 PropVariantClear(&value);
3159 else if (value.vt == VT_LPSTR)
3160 ok(!lstrcmpA(value.pszVal, test_data[i].str_value), "%u: expected %s, got %s\n",
3161 i, test_data[i].str_value, value.pszVal);
3162 else
3163 ok(value.uiVal == test_data[i].value, "%u: expected %u, got %u\n",
3164 i, test_data[i].value, value.uiVal);
3168 * Do NOT call PropVariantClear(&value) for fake value types.
3173 IWICMetadataQueryReader_Release(reader);
3174 IWICComponentFactory_Release(factory);
3177 static void test_metadata_writer(void)
3179 static struct
3181 REFCLSID rclsid;
3182 BOOL wine_supports_encoder;
3183 BOOL metadata_supported;
3184 BOOL succeeds_uninitialized;
3186 tests[] =
3188 {&CLSID_WICBmpEncoder, TRUE, FALSE},
3189 {&CLSID_WICPngEncoder, TRUE, TRUE},
3190 {&CLSID_WICJpegEncoder, TRUE, TRUE},
3191 {&CLSID_WICGifEncoder, TRUE, TRUE},
3192 {&CLSID_WICTiffEncoder, TRUE, TRUE},
3193 {&CLSID_WICWmpEncoder, FALSE, TRUE, TRUE},
3196 IWICMetadataQueryWriter *querywriter, *querywriter2;
3197 IWICMetadataBlockWriter *blockwriter;
3198 IWICBitmapFrameEncode *frameencode;
3199 IWICComponentFactory *factory;
3200 IWICBitmapEncoder *encoder;
3201 IEnumString *enumstring;
3202 LPOLESTR olestring;
3203 ULONG ref, count;
3204 IStream *stream;
3205 unsigned int i;
3206 HRESULT hr;
3208 for (i = 0; i < ARRAY_SIZE(tests); ++i)
3210 hr = CoCreateInstance(tests[i].rclsid, NULL, CLSCTX_INPROC_SERVER,
3211 &IID_IWICBitmapEncoder, (void **)&encoder);
3212 todo_wine_if(!tests[i].wine_supports_encoder) ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3213 if (FAILED(hr))
3214 continue;
3216 blockwriter = NULL;
3217 querywriter = querywriter2 = NULL;
3219 hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
3220 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3221 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
3222 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3223 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, NULL);
3224 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3226 hr = IWICBitmapFrameEncode_QueryInterface(frameencode, &IID_IWICMetadataBlockWriter, (void**)&blockwriter);
3227 ok(hr == (tests[i].metadata_supported ? S_OK : E_NOINTERFACE), "Got unexpected hr %#lx, i %u.\n", hr, i);
3229 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
3230 &IID_IWICComponentFactory, (void**)&factory);
3231 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3233 hr = IWICComponentFactory_CreateQueryWriterFromBlockWriter(factory, blockwriter, &querywriter);
3234 ok(hr == (tests[i].metadata_supported ? S_OK : E_INVALIDARG), "Got unexpected hr %#lx, i %u.\n", hr, i);
3236 hr = IWICBitmapFrameEncode_GetMetadataQueryWriter(frameencode, &querywriter2);
3237 ok(hr == (tests[i].succeeds_uninitialized ? S_OK : WINCODEC_ERR_NOTINITIALIZED),
3238 "Got unexpected hr %#lx, i %u.\n", hr, i);
3239 if (hr == S_OK)
3240 IWICMetadataQueryWriter_Release(querywriter2);
3242 hr = IWICBitmapFrameEncode_Initialize(frameencode, NULL);
3243 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3245 hr = IWICBitmapFrameEncode_GetMetadataQueryWriter(frameencode, &querywriter2);
3246 ok(hr == (tests[i].metadata_supported ? S_OK : WINCODEC_ERR_UNSUPPORTEDOPERATION),
3247 "Got unexpected hr %#lx, i %u.\n", hr, i);
3249 if (tests[i].metadata_supported)
3250 ok(querywriter2 != querywriter, "Got unexpected interfaces %p, %p, i %u.\n", querywriter, querywriter2, i);
3252 IWICComponentFactory_Release(factory);
3253 if (querywriter)
3255 ref = get_refcount(querywriter);
3256 ok(ref == 1, "Got unexpected ref %lu, i %u.\n", ref, i);
3258 hr = IWICMetadataQueryWriter_QueryInterface(querywriter, &IID_IEnumString, (void **)&enumstring);
3259 ok(hr == E_NOINTERFACE, "Got unexpected hr %#lx, i %u.\n", hr, i);
3261 hr = IWICMetadataQueryWriter_GetEnumerator(querywriter, &enumstring);
3262 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3264 ref = get_refcount(querywriter);
3265 ok(ref == 1, "Got unexpected ref %lu, i %u.\n", ref, i);
3267 hr = IEnumString_Skip(enumstring, 0);
3268 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3270 count = 0xdeadbeef;
3271 hr = IEnumString_Next(enumstring, 0, NULL, &count);
3272 ok(hr == E_INVALIDARG, "Got unexpected hr %#lx, i %u.\n", hr, i);
3273 ok(count == 0xdeadbeef, "Got unexpected count %lu, i %u.\n", count, i);
3275 hr = IEnumString_Next(enumstring, 0, &olestring, &count);
3276 ok(hr == S_OK || hr == WINCODEC_ERR_VALUEOUTOFRANGE, "Got unexpected hr %#lx, i %u.\n", hr, i);
3278 count = 0xdeadbeef;
3279 hr = IEnumString_Next(enumstring, 1, &olestring, &count);
3280 ok(hr == S_OK || hr == S_FALSE, "Got unexpected hr %#lx, i %u.\n", hr, i);
3281 ok((hr && !count) || (!hr && count == 1), "Got unexpected hr %#lx, count %lu, i %u.\n", hr, count, i);
3282 if (count)
3284 CoTaskMemFree(olestring);
3286 /* IEnumString_Skip() crashes at least on Win7 when
3287 * trying to skip past the string count. */
3288 hr = IEnumString_Reset(enumstring);
3289 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3291 hr = IEnumString_Skip(enumstring, 1);
3292 ok(hr == S_OK, "Got unexpected hr %#lx, i %u.\n", hr, i);
3294 IEnumString_Release(enumstring);
3296 IWICMetadataQueryWriter_Release(querywriter);
3297 IWICMetadataQueryWriter_Release(querywriter2);
3298 IWICMetadataBlockWriter_Release(blockwriter);
3300 IWICBitmapFrameEncode_Release(frameencode);
3301 IStream_Release(stream);
3302 IWICBitmapEncoder_Release(encoder);
3306 START_TEST(metadata)
3308 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
3310 test_queryreader();
3311 test_WICMapGuidToShortName();
3312 test_WICMapShortNameToGuid();
3313 test_WICMapSchemaToName();
3314 test_metadata_unknown();
3315 test_metadata_tEXt();
3316 test_metadata_gAMA();
3317 test_metadata_cHRM();
3318 test_metadata_hIST();
3319 test_metadata_tIME();
3320 test_metadata_IFD();
3321 test_metadata_Exif();
3322 test_create_reader();
3323 test_metadata_png();
3324 test_metadata_gif();
3325 test_metadata_LSD();
3326 test_metadata_IMD();
3327 test_metadata_GCE();
3328 test_metadata_APE();
3329 test_metadata_GIF_comment();
3330 test_metadata_writer();
3332 CoUninitialize();