windowscodecs: Add a bunch of tests for GIF Comment Extenstion metadata reader.
[wine] / dlls / windowscodecs / tests / metadata.c
1 /*
2  * Copyright 2011 Vincent Povirk for CodeWeavers
3  * Copyright 2012 Dmitry Timoshkov
4  *
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.
9  *
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.
14  *
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
18  */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <math.h>
23 #include <assert.h>
24
25 #define COBJMACROS
26
27 #include "windef.h"
28 #include "objbase.h"
29 #include "wincodec.h"
30 #include "wincodecsdk.h"
31 #include "wine/test.h"
32
33 #define expect_blob(propvar, data, length) do { \
34     ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
35     if ((propvar).vt == VT_BLOB) { \
36         ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
37         if (U(propvar).blob.cbSize == (length)) { \
38             ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
39         } \
40     } \
41 } while (0)
42
43 #define IFD_BYTE 1
44 #define IFD_ASCII 2
45 #define IFD_SHORT 3
46 #define IFD_LONG 4
47 #define IFD_RATIONAL 5
48 #define IFD_SBYTE 6
49 #define IFD_UNDEFINED 7
50 #define IFD_SSHORT 8
51 #define IFD_SLONG 9
52 #define IFD_SRATIONAL 10
53 #define IFD_FLOAT 11
54 #define IFD_DOUBLE 12
55 #define IFD_IFD 13
56
57 #include "pshpack2.h"
58 struct IFD_entry
59 {
60     SHORT id;
61     SHORT type;
62     ULONG count;
63     LONG  value;
64 };
65
66 struct IFD_rational
67 {
68     LONG numerator;
69     LONG denominator;
70 };
71
72 static const struct ifd_data
73 {
74     USHORT number_of_entries;
75     struct IFD_entry entry[40];
76     ULONG next_IFD;
77     struct IFD_rational xres;
78     DOUBLE double_val;
79     struct IFD_rational srational_val;
80     char string[14];
81     SHORT short_val[4];
82     LONG long_val[2];
83     FLOAT float_val[2];
84     struct IFD_rational rational[3];
85 } IFD_data =
86 {
87     28,
88     {
89         { 0xfe,  IFD_SHORT, 1, 1 }, /* NEWSUBFILETYPE */
90         { 0x100, IFD_LONG, 1, 222 }, /* IMAGEWIDTH */
91         { 0x101, IFD_LONG, 1, 333 }, /* IMAGELENGTH */
92         { 0x102, IFD_SHORT, 1, 24 }, /* BITSPERSAMPLE */
93         { 0x103, IFD_LONG, 1, 32773 }, /* COMPRESSION: packbits */
94         { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct ifd_data, xres) },
95         { 0xf001, IFD_BYTE, 1, 0x11223344 },
96         { 0xf002, IFD_BYTE, 4, 0x11223344 },
97         { 0xf003, IFD_SBYTE, 1, 0x11223344 },
98         { 0xf004, IFD_SSHORT, 1, 0x11223344 },
99         { 0xf005, IFD_SSHORT, 2, 0x11223344 },
100         { 0xf006, IFD_SLONG, 1, 0x11223344 },
101         { 0xf007, IFD_FLOAT, 1, 0x11223344 },
102         { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct ifd_data, double_val) },
103         { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct ifd_data, srational_val) },
104         { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct ifd_data, string) },
105         { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct ifd_data, short_val) },
106         { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct ifd_data, long_val) },
107         { 0xf00d, IFD_FLOAT, 2, FIELD_OFFSET(struct ifd_data, float_val) },
108         { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct ifd_data, string) },
109         { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
110         { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct ifd_data, string) },
111         { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
112         { 0xf012, IFD_BYTE, 0, 0x11223344 },
113         { 0xf013, IFD_SHORT, 0, 0x11223344 },
114         { 0xf014, IFD_LONG, 0, 0x11223344 },
115         { 0xf015, IFD_FLOAT, 0, 0x11223344 },
116         { 0xf016, IFD_SRATIONAL, 3, FIELD_OFFSET(struct ifd_data, rational) },
117     },
118     0,
119     { 900, 3 },
120     1234567890.0987654321,
121     { 0x1a2b3c4d, 0x5a6b7c8d },
122     "Hello World!",
123     { 0x0101, 0x0202, 0x0303, 0x0404 },
124     { 0x11223344, 0x55667788 },
125     { (FLOAT)1234.5678, (FLOAT)8765.4321 },
126     { { 0x01020304, 0x05060708 }, { 0x10203040, 0x50607080 }, { 0x11223344, 0x55667788 } },
127 };
128 #include "poppack.h"
129
130 static const char metadata_unknown[] = "lalala";
131
132 static const char metadata_tEXt[] = {
133     0,0,0,14, /* chunk length */
134     't','E','X','t', /* chunk type */
135     'w','i','n','e','t','e','s','t',0, /* keyword */
136     'v','a','l','u','e', /* text */
137     0x3f,0x64,0x19,0xf3 /* chunk CRC */
138 };
139
140 static const char pngimage[285] = {
141 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
142 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
143 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
144 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
145 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
146 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
147 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
148 };
149
150 /* 1x1 pixel gif */
151 static const char gifimage[35] = {
152 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
153 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
154 0x01,0x00,0x3b
155 };
156
157 /* 1x1 pixel gif, 2 frames; first frame is white, second is black */
158 static const char gifanimation[72] = {
159 0x47,0x49,0x46,0x38,0x39,0x61,0x01,0x00,0x01,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
160 0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x21,0xf9,0x04,0x00,0x0a,0x00,0xff,
161 0x00,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x4c,0x01,0x00,
162 0x21,0xf9,0x04,0x01,0x0a,0x00,0x01,0x00,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,
163 0x00,0x00,0x02,0x02,0x44,0x01,0x00,0x3b
164 };
165
166 static const char *debugstr_guid(REFIID riid)
167 {
168     static char buf[50];
169
170     if(!riid)
171         return "(null)";
172
173     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
174             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
175             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
176             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
177
178     return buf;
179 }
180
181 static IStream *create_stream(const char *data, int data_size)
182 {
183     HRESULT hr;
184     IStream *stream;
185     HGLOBAL hdata;
186     void *locked_data;
187
188     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
189     ok(hdata != 0, "GlobalAlloc failed\n");
190     if (!hdata) return NULL;
191
192     locked_data = GlobalLock(hdata);
193     memcpy(locked_data, data, data_size);
194     GlobalUnlock(hdata);
195
196     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
197     ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
198
199     return stream;
200 }
201
202 static void load_stream(IUnknown *reader, const char *data, int data_size, DWORD persist_options)
203 {
204     HRESULT hr;
205     IWICPersistStream *persist;
206     IStream *stream;
207     LARGE_INTEGER pos;
208     ULARGE_INTEGER cur_pos;
209
210     stream = create_stream(data, data_size);
211     if (!stream)
212         return;
213
214     hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
215     ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
216
217     if (SUCCEEDED(hr))
218     {
219         hr = IWICPersistStream_LoadEx(persist, stream, NULL, persist_options);
220         ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
221
222         IWICPersistStream_Release(persist);
223     }
224
225     pos.QuadPart = 0;
226     hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos);
227     ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
228     /* IFD metadata reader doesn't rewind the stream to the start */
229     ok(cur_pos.QuadPart == 0 || cur_pos.QuadPart <= data_size,
230        "current stream pos is at %x/%x, data size %x\n", cur_pos.u.LowPart, cur_pos.u.HighPart, data_size);
231
232     IStream_Release(stream);
233 }
234
235 static void test_metadata_unknown(void)
236 {
237     HRESULT hr;
238     IWICMetadataReader *reader;
239     IWICEnumMetadataItem *enumerator;
240     IWICMetadataBlockReader *blockreader;
241     PROPVARIANT schema, id, value;
242     ULONG items_returned;
243
244     hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
245         &IID_IWICMetadataReader, (void**)&reader);
246     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
247     if (FAILED(hr)) return;
248
249     load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown), WICPersistOptionsDefault);
250
251     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
252     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
253
254     if (SUCCEEDED(hr))
255     {
256         PropVariantInit(&schema);
257         PropVariantInit(&id);
258         PropVariantInit(&value);
259
260         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
261         ok(hr == S_OK, "Next failed, hr=%x\n", hr);
262         ok(items_returned == 1, "unexpected item count %i\n", items_returned);
263
264         if (hr == S_OK && items_returned == 1)
265         {
266             ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
267             ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
268             expect_blob(value, metadata_unknown, sizeof(metadata_unknown));
269
270             PropVariantClear(&schema);
271             PropVariantClear(&id);
272             PropVariantClear(&value);
273         }
274
275         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
276         ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
277         ok(items_returned == 0, "unexpected item count %i\n", items_returned);
278
279         IWICEnumMetadataItem_Release(enumerator);
280     }
281
282     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
283     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
284
285     if (SUCCEEDED(hr))
286         IWICMetadataBlockReader_Release(blockreader);
287
288     IWICMetadataReader_Release(reader);
289 }
290
291 static void test_metadata_tEXt(void)
292 {
293     HRESULT hr;
294     IWICMetadataReader *reader;
295     IWICEnumMetadataItem *enumerator;
296     PROPVARIANT schema, id, value;
297     ULONG items_returned, count;
298     GUID format;
299
300     PropVariantInit(&schema);
301     PropVariantInit(&id);
302     PropVariantInit(&value);
303
304     hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
305         &IID_IWICMetadataReader, (void**)&reader);
306     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
307     if (FAILED(hr)) return;
308
309     hr = IWICMetadataReader_GetCount(reader, NULL);
310     ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
311
312     hr = IWICMetadataReader_GetCount(reader, &count);
313     ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
314     ok(count == 0, "unexpected count %i\n", count);
315
316     load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt), WICPersistOptionsDefault);
317
318     hr = IWICMetadataReader_GetCount(reader, &count);
319     ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
320     ok(count == 1, "unexpected count %i\n", count);
321
322     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
323     ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
324
325     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
326     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
327
328     if (SUCCEEDED(hr))
329     {
330         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
331         ok(hr == S_OK, "Next failed, hr=%x\n", hr);
332         ok(items_returned == 1, "unexpected item count %i\n", items_returned);
333
334         if (hr == S_OK && items_returned == 1)
335         {
336             ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
337             ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
338             ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
339             ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
340             ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
341
342             PropVariantClear(&schema);
343             PropVariantClear(&id);
344             PropVariantClear(&value);
345         }
346
347         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
348         ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
349         ok(items_returned == 0, "unexpected item count %i\n", items_returned);
350
351         IWICEnumMetadataItem_Release(enumerator);
352     }
353
354     hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
355     ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
356     ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
357
358     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
359     ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
360
361     id.vt = VT_LPSTR;
362     U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
363     strcpy(U(id).pszVal, "winetest");
364
365     hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
366     ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
367
368     hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
369     ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
370
371     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
372     ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
373     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
374     ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
375     PropVariantClear(&value);
376
377     strcpy(U(id).pszVal, "test");
378
379     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
380     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
381
382     PropVariantClear(&id);
383
384     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
385     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
386
387     hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
388     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
389     ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
390
391     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
392     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
393     ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
394     ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
395     PropVariantClear(&id);
396
397     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
398     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
399     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
400     ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
401     PropVariantClear(&value);
402
403     hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
404     ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
405
406     IWICMetadataReader_Release(reader);
407 }
408
409 static inline USHORT ushort_bswap(USHORT s)
410 {
411     return (s >> 8) | (s << 8);
412 }
413
414 static inline ULONG ulong_bswap(ULONG l)
415 {
416     return ((ULONG)ushort_bswap((USHORT)l) << 16) | ushort_bswap((USHORT)(l >> 16));
417 }
418
419 static inline ULONGLONG ulonglong_bswap(ULONGLONG ll)
420 {
421     return ((ULONGLONG)ulong_bswap((ULONG)ll) << 32) | ulong_bswap((ULONG)(ll >> 32));
422 }
423
424 static void byte_swap_ifd_data(char *data)
425 {
426     USHORT number_of_entries, i;
427     struct IFD_entry *entry;
428     char *data_start = data;
429
430     number_of_entries = *(USHORT *)data;
431     *(USHORT *)data = ushort_bswap(*(USHORT *)data);
432     data += sizeof(USHORT);
433
434     for (i = 0; i < number_of_entries; i++)
435     {
436         entry = (struct IFD_entry *)data;
437
438         switch (entry->type)
439         {
440         case IFD_BYTE:
441         case IFD_SBYTE:
442         case IFD_ASCII:
443         case IFD_UNDEFINED:
444             if (entry->count > 4)
445                 entry->value = ulong_bswap(entry->value);
446             break;
447
448         case IFD_SHORT:
449         case IFD_SSHORT:
450             if (entry->count > 2)
451             {
452                 ULONG j, count = entry->count;
453                 USHORT *us = (USHORT *)(data_start + entry->value);
454                 if (!count) count = 1;
455                 for (j = 0; j < count; j++)
456                     us[j] = ushort_bswap(us[j]);
457
458                 entry->value = ulong_bswap(entry->value);
459             }
460             else
461             {
462                 ULONG j, count = entry->count;
463                 USHORT *us = (USHORT *)&entry->value;
464                 if (!count) count = 1;
465                 for (j = 0; j < count; j++)
466                     us[j] = ushort_bswap(us[j]);
467             }
468             break;
469
470         case IFD_LONG:
471         case IFD_SLONG:
472         case IFD_FLOAT:
473             if (entry->count > 1)
474             {
475                 ULONG j, count = entry->count;
476                 ULONG *ul = (ULONG *)(data_start + entry->value);
477                 if (!count) count = 1;
478                 for (j = 0; j < count; j++)
479                     ul[j] = ulong_bswap(ul[j]);
480             }
481             entry->value = ulong_bswap(entry->value);
482             break;
483
484         case IFD_RATIONAL:
485         case IFD_SRATIONAL:
486             {
487                 ULONG j;
488                 ULONG *ul = (ULONG *)(data_start + entry->value);
489                 for (j = 0; j < entry->count * 2; j++)
490                     ul[j] = ulong_bswap(ul[j]);
491             }
492             entry->value = ulong_bswap(entry->value);
493             break;
494
495         case IFD_DOUBLE:
496             {
497                 ULONG j;
498                 ULONGLONG *ull = (ULONGLONG *)(data_start + entry->value);
499                 for (j = 0; j < entry->count; j++)
500                     ull[j] = ulonglong_bswap(ull[j]);
501             }
502             entry->value = ulong_bswap(entry->value);
503             break;
504
505         default:
506             assert(0);
507             break;
508         }
509
510         entry->id = ushort_bswap(entry->id);
511         entry->type = ushort_bswap(entry->type);
512         entry->count = ulong_bswap(entry->count);
513         data += sizeof(*entry);
514     }
515 }
516
517 struct test_data
518 {
519     ULONG type, id;
520     int count; /* if VT_VECTOR */
521     LONGLONG value[13];
522     const char *string;
523     const WCHAR id_string[32];
524 };
525
526 static void compare_metadata(IWICMetadataReader *reader, const struct test_data *td, ULONG count)
527 {
528     HRESULT hr;
529     IWICEnumMetadataItem *enumerator;
530     PROPVARIANT schema, id, value;
531     ULONG items_returned, i;
532
533     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
534     ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
535
536     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
537     ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
538
539     PropVariantInit(&schema);
540     PropVariantInit(&id);
541     PropVariantInit(&value);
542
543     for (i = 0; i < count; i++)
544     {
545         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
546         ok(hr == S_OK, "Next error %#x\n", hr);
547         ok(items_returned == 1, "unexpected item count %u\n", items_returned);
548
549         ok(schema.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, schema.vt);
550         ok(id.vt == VT_UI2 || id.vt == VT_LPWSTR, "%u: unexpected vt: %u\n", i, id.vt);
551         if (id.vt == VT_UI2)
552             ok(U(id).uiVal == td[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, U(id).uiVal);
553         else if (id.vt == VT_LPWSTR)
554             ok(!lstrcmpW(td[i].id_string, U(id).pwszVal),
555                "%u: expected %s, got %s\n", i, wine_dbgstr_w(td[i].id_string), wine_dbgstr_w(U(id).pwszVal));
556
557         ok(value.vt == td[i].type, "%u: expected vt %#x, got %#x\n", i, td[i].type, value.vt);
558         if (value.vt & VT_VECTOR)
559         {
560             ULONG j;
561             switch (value.vt & ~VT_VECTOR)
562             {
563             case VT_I1:
564             case VT_UI1:
565                 ok(td[i].count == U(value).caub.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
566                 for (j = 0; j < U(value).caub.cElems; j++)
567                     ok(td[i].value[j] == U(value).caub.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caub.pElems[j]);
568                 break;
569             case VT_I2:
570             case VT_UI2:
571                 ok(td[i].count == U(value).caui.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caui.cElems);
572                 for (j = 0; j < U(value).caui.cElems; j++)
573                     ok(td[i].value[j] == U(value).caui.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caui.pElems[j]);
574                 break;
575             case VT_I4:
576             case VT_UI4:
577             case VT_R4:
578                 ok(td[i].count == U(value).caul.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caul.cElems);
579                 for (j = 0; j < U(value).caul.cElems; j++)
580                     ok(td[i].value[j] == U(value).caul.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caul.pElems[j]);
581                 break;
582             case VT_I8:
583             case VT_UI8:
584             case VT_R8:
585                 ok(td[i].count == U(value).cauh.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).cauh.cElems);
586                 for (j = 0; j < U(value).cauh.cElems; j++)
587                     ok(td[i].value[j] == U(value).cauh.pElems[j].QuadPart, "%u: expected value[%d] %08x/%08x, got %08x/%08x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).cauh.pElems[j].u.LowPart, U(value).cauh.pElems[j].u.HighPart);
588                 break;
589             case VT_LPSTR:
590                 ok(td[i].count == U(value).calpstr.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
591                 for (j = 0; j < U(value).calpstr.cElems; j++)
592                     trace("%u: %s\n", j, U(value).calpstr.pElems[j]);
593                 /* fall through to not handled message */
594             default:
595                 ok(0, "%u: array of type %d is not handled\n", i, value.vt & ~VT_VECTOR);
596                 break;
597             }
598         }
599         else if (value.vt == VT_LPSTR)
600         {
601             ok(td[i].count == strlen(U(value).pszVal) ||
602                broken(td[i].count == strlen(U(value).pszVal) + 1), /* before Win7 */
603                "%u: expected count %d, got %d\n", i, td[i].count, lstrlenA(U(value).pszVal));
604             if (td[i].count == strlen(U(value).pszVal))
605                 ok(!strcmp(td[i].string, U(value).pszVal),
606                    "%u: expected %s, got %s\n", i, td[i].string, U(value).pszVal);
607         }
608         else if (value.vt == VT_BLOB)
609         {
610             ok(td[i].count == U(value).blob.cbSize, "%u: expected count %d, got %d\n", i, td[i].count, U(value).blob.cbSize);
611             ok(!memcmp(td[i].string, U(value).blob.pBlobData, td[i].count), "%u: expected %s, got %s\n", i, td[i].string, U(value).blob.pBlobData);
612         }
613         else
614             ok(U(value).uhVal.QuadPart == td[i].value[0], "%u: expected value %#x/%#x got %#x/%#x\n",
615                i, (UINT)td[i].value[0], (UINT)(td[i].value[0] >> 32), U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
616
617         PropVariantClear(&schema);
618         PropVariantClear(&id);
619         PropVariantClear(&value);
620     }
621
622     hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
623     ok(hr == S_FALSE, "Next should fail\n");
624     ok(items_returned == 0, "unexpected item count %u\n", items_returned);
625
626     IWICEnumMetadataItem_Release(enumerator);
627 }
628
629 static void test_metadata_IFD(void)
630 {
631     static const struct test_data td[28] =
632     {
633         { VT_UI2, 0xfe, 0, { 1 } },
634         { VT_UI4, 0x100, 0, { 222 } },
635         { VT_UI4, 0x101, 0, { 333 } },
636         { VT_UI2, 0x102, 0, { 24 } },
637         { VT_UI4, 0x103, 0, { 32773 } },
638         { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
639         { VT_UI1, 0xf001, 0, { 0x44 } },
640         { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
641         { VT_I1, 0xf003, 0, { 0x44 } },
642         { VT_I2, 0xf004, 0, { 0x3344 } },
643         { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
644         { VT_I4, 0xf006, 0, { 0x11223344 } },
645         { VT_R4, 0xf007, 0, { 0x11223344 } },
646         { VT_R8, 0xf008, 0, { ((LONGLONG)0x41d26580 << 32) | 0xb486522c } },
647         { VT_I8, 0xf009, 0, { ((LONGLONG)0x5a6b7c8d << 32) | 0x1a2b3c4d } },
648         { VT_UI1|VT_VECTOR, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
649         { VT_I2|VT_VECTOR, 0xf00b, 4, { 0x0101, 0x0202, 0x0303, 0x0404 } },
650         { VT_I4|VT_VECTOR, 0xf00c, 2, { 0x11223344, 0x55667788 } },
651         { VT_R4|VT_VECTOR, 0xf00d, 2, { 0x449a522b, 0x4608f5ba } },
652         { VT_LPSTR, 0xf00e, 12, { 0 }, "Hello World!" },
653         { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
654         { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
655         { VT_BLOB, 0xf011, 4, { 0 }, "abcd" },
656         { VT_UI1, 0xf012, 0, { 0x44 } },
657         { VT_UI2, 0xf013, 0, { 0x3344 } },
658         { VT_UI4, 0xf014, 0, { 0x11223344 } },
659         { VT_R4, 0xf015, 0, { 0x11223344 } },
660         { VT_I8|VT_VECTOR, 0xf016, 3,
661           { ((LONGLONG)0x05060708 << 32) | 0x01020304,
662             ((LONGLONG)0x50607080 << 32) | 0x10203040,
663             ((LONGLONG)0x55667788 << 32) | 0x11223344 } },
664     };
665     HRESULT hr;
666     IWICMetadataReader *reader;
667     IWICMetadataBlockReader *blockreader;
668     PROPVARIANT schema, id, value;
669     ULONG count;
670     GUID format;
671     char *IFD_data_swapped;
672 #ifdef WORDS_BIGENDIAN
673     DWORD persist_options = WICPersistOptionsBigEndian;
674 #else
675     DWORD persist_options = WICPersistOptionsLittleEndian;
676 #endif
677
678     hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
679         &IID_IWICMetadataReader, (void**)&reader);
680     ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
681
682     hr = IWICMetadataReader_GetCount(reader, NULL);
683     ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
684
685     hr = IWICMetadataReader_GetCount(reader, &count);
686     ok(hr == S_OK, "GetCount error %#x\n", hr);
687     ok(count == 0, "unexpected count %u\n", count);
688
689     load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data), persist_options);
690
691     hr = IWICMetadataReader_GetCount(reader, &count);
692     ok(hr == S_OK, "GetCount error %#x\n", hr);
693     ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
694
695     compare_metadata(reader, td, count);
696
697     /* test IFD data with different endianness */
698     if (persist_options == WICPersistOptionsLittleEndian)
699         persist_options = WICPersistOptionsBigEndian;
700     else
701         persist_options = WICPersistOptionsLittleEndian;
702
703     IFD_data_swapped = HeapAlloc(GetProcessHeap(), 0, sizeof(IFD_data));
704     memcpy(IFD_data_swapped, &IFD_data, sizeof(IFD_data));
705     byte_swap_ifd_data(IFD_data_swapped);
706     load_stream((IUnknown *)reader, IFD_data_swapped, sizeof(IFD_data), persist_options);
707     hr = IWICMetadataReader_GetCount(reader, &count);
708     ok(hr == S_OK, "GetCount error %#x\n", hr);
709     ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
710     compare_metadata(reader, td, count);
711     HeapFree(GetProcessHeap(), 0, IFD_data_swapped);
712
713     hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
714     ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
715     ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", debugstr_guid(&format));
716
717     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
718     ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
719
720     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
721     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
722
723     PropVariantInit(&schema);
724     PropVariantInit(&id);
725     PropVariantInit(&value);
726
727     hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
728     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
729
730     hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
731     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
732     ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
733
734     hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
735     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
736     ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
737
738     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
739     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
740     ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
741     ok(U(id).uiVal == 0xfe, "unexpected id: %#x\n", U(id).uiVal);
742     PropVariantClear(&id);
743
744     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
745     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
746     ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
747     ok(U(value).uiVal == 1, "unexpected id: %#x\n", U(value).uiVal);
748     PropVariantClear(&value);
749
750     hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
751     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
752
753     PropVariantInit(&schema);
754     PropVariantInit(&id);
755     PropVariantInit(&value);
756
757     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
758     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
759
760     hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
761     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
762
763     hr = IWICMetadataReader_GetValue(reader, &schema, NULL, NULL);
764     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
765
766     hr = IWICMetadataReader_GetValue(reader, &schema, &id, NULL);
767     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
768
769     hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
770     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
771
772     id.vt = VT_UI2;
773     U(id).uiVal = 0xf00e;
774     hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
775     ok(hr == S_OK, "GetValue error %#x\n", hr);
776
777     /* schema is ignored by Ifd metadata reader */
778     schema.vt = VT_UI4;
779     U(schema).ulVal = 0xdeadbeef;
780     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
781     ok(hr == S_OK, "GetValue error %#x\n", hr);
782     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
783     ok(!strcmp(U(value).pszVal, "Hello World!"), "unexpected value: %s\n", U(value).pszVal);
784     PropVariantClear(&value);
785
786     hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
787     ok(hr == S_OK, "GetValue error %#x\n", hr);
788     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
789     ok(!strcmp(U(value).pszVal, "Hello World!"), "unexpected value: %s\n", U(value).pszVal);
790     PropVariantClear(&value);
791
792     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
793     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
794
795     if (SUCCEEDED(hr))
796         IWICMetadataBlockReader_Release(blockreader);
797
798     IWICMetadataReader_Release(reader);
799 }
800
801 static void test_metadata_Exif(void)
802 {
803     HRESULT hr;
804     IWICMetadataReader *reader;
805     IWICMetadataBlockReader *blockreader;
806     UINT count=0;
807
808     hr = CoCreateInstance(&CLSID_WICExifMetadataReader, NULL, CLSCTX_INPROC_SERVER,
809         &IID_IWICMetadataReader, (void**)&reader);
810     todo_wine ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
811     if (FAILED(hr)) return;
812
813     hr = IWICMetadataReader_GetCount(reader, NULL);
814     ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
815
816     hr = IWICMetadataReader_GetCount(reader, &count);
817     ok(hr == S_OK, "GetCount error %#x\n", hr);
818     ok(count == 0, "unexpected count %u\n", count);
819
820     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
821     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
822
823     if (SUCCEEDED(hr))
824         IWICMetadataBlockReader_Release(blockreader);
825
826     IWICMetadataReader_Release(reader);
827 }
828
829 static void test_create_reader(void)
830 {
831     HRESULT hr;
832     IWICComponentFactory *factory;
833     IStream *stream;
834     IWICMetadataReader *reader;
835     UINT count=0;
836     GUID format;
837
838     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
839         &IID_IWICComponentFactory, (void**)&factory);
840     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
841
842     stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
843
844     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
845         &GUID_ContainerFormatPng, NULL, WICPersistOptionsDefault,
846         stream, &reader);
847 todo_wine
848     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
849     if (FAILED(hr)) return;
850
851     if (SUCCEEDED(hr))
852     {
853         hr = IWICMetadataReader_GetCount(reader, &count);
854         ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
855         ok(count == 1, "unexpected count %i\n", count);
856
857         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
858         ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
859         ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
860
861         IWICMetadataReader_Release(reader);
862     }
863
864     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
865         &GUID_ContainerFormatWmp, NULL, WICPersistOptionsDefault,
866         stream, &reader);
867     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
868
869     if (SUCCEEDED(hr))
870     {
871         hr = IWICMetadataReader_GetCount(reader, &count);
872         ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
873         ok(count == 1, "unexpected count %i\n", count);
874
875         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
876         ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
877         ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", debugstr_guid(&format));
878
879         IWICMetadataReader_Release(reader);
880     }
881
882     IStream_Release(stream);
883
884     IWICComponentFactory_Release(factory);
885 }
886
887 static void test_metadata_png(void)
888 {
889     static const struct test_data td[6] =
890     {
891         { VT_UI2, 0, 0, { 2005 }, NULL, { 'Y','e','a','r',0 } },
892         { VT_UI1, 0, 0, { 6 }, NULL, { 'M','o','n','t','h',0 } },
893         { VT_UI1, 0, 0, { 3 }, NULL, { 'D','a','y',0 } },
894         { VT_UI1, 0, 0, { 15 }, NULL, { 'H','o','u','r',0 } },
895         { VT_UI1, 0, 0, { 7 }, NULL, { 'M','i','n','u','t','e',0 } },
896         { VT_UI1, 0, 0, { 45 }, NULL, { 'S','e','c','o','n','d',0 } }
897     };
898     IStream *stream;
899     IWICBitmapDecoder *decoder;
900     IWICBitmapFrameDecode *frame;
901     IWICMetadataBlockReader *blockreader;
902     IWICMetadataReader *reader;
903     GUID containerformat;
904     HRESULT hr;
905     UINT count;
906
907     hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
908         &IID_IWICBitmapDecoder, (void**)&decoder);
909     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
910
911     if (FAILED(hr)) return;
912
913     stream = create_stream(pngimage, sizeof(pngimage));
914
915     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
916     ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
917
918     hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void**)&blockreader);
919     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
920
921     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
922     ok(hr == S_OK, "GetFrame failed, hr=%x\n", hr);
923
924     hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void**)&blockreader);
925     ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
926
927     if (SUCCEEDED(hr))
928     {
929         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
930         ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%x\n", hr);
931
932         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &containerformat);
933         ok(hr == S_OK, "GetContainerFormat failed, hr=%x\n", hr);
934         ok(IsEqualGUID(&containerformat, &GUID_ContainerFormatPng), "unexpected container format\n");
935
936         hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
937         todo_wine ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
938
939         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
940         todo_wine ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
941         todo_wine ok(count == 1, "unexpected count %d\n", count);
942
943         if (0)
944         {
945             /* Crashes on Windows XP */
946             hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, NULL);
947             ok(hr == E_INVALIDARG, "GetReaderByIndex failed, hr=%x\n", hr);
948         }
949
950         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
951         todo_wine ok(hr == S_OK, "GetReaderByIndex failed, hr=%x\n", hr);
952
953         if (SUCCEEDED(hr))
954         {
955             hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
956             ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
957                broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
958                "unexpected container format\n");
959
960             hr = IWICMetadataReader_GetCount(reader, &count);
961             ok(hr == S_OK, "GetCount error %#x\n", hr);
962             ok(count == 6 || broken(count == 1) /* XP */, "expected 6, got %u\n", count);
963             if (count == 6)
964                 compare_metadata(reader, td, count);
965
966             IWICMetadataReader_Release(reader);
967         }
968
969         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
970         todo_wine ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "GetReaderByIndex failed, hr=%x\n", hr);
971
972         IWICMetadataBlockReader_Release(blockreader);
973     }
974
975     IWICBitmapFrameDecode_Release(frame);
976
977     IWICBitmapDecoder_Release(decoder);
978
979     IStream_Release(stream);
980 }
981
982 static void test_metadata_gif(void)
983 {
984     static const struct test_data gif_LSD[9] =
985     {
986         { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','7','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
987         { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
988         { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
989         { 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 } },
990         { VT_UI1, 0, 0, { 0 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
991         { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
992         { 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 } },
993         { 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 } },
994         { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
995     };
996     static const struct test_data gif_IMD[8] =
997     {
998         { VT_UI2, 0, 0, { 0 }, NULL, { 'L','e','f','t',0 } },
999         { VT_UI2, 0, 0, { 0 }, NULL, { 'T','o','p',0 } },
1000         { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1001         { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1002         { 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 } },
1003         { VT_BOOL, 0, 0, { 0 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1004         { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1005         { 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 } }
1006     };
1007     static const struct test_data animated_gif_LSD[9] =
1008     {
1009         { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','9','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1010         { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1011         { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1012         { 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 } },
1013         { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1014         { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1015         { 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 } },
1016         { 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 } },
1017         { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1018     };
1019     static const struct test_data animated_gif_GCE[5] =
1020     {
1021         { VT_UI1, 0, 0, { 0 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
1022         { VT_BOOL, 0, 0, { 0 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
1023         { VT_BOOL, 0, 0, { 0 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
1024         { VT_UI2, 0, 0, { 10 }, NULL, { 'D','e','l','a','y',0 } },
1025         { VT_UI1, 0, 0, { 255 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','t','C','o','l','o','r','I','n','d','e','x',0 } }
1026     };
1027     IStream *stream;
1028     IWICBitmapDecoder *decoder;
1029     IWICBitmapFrameDecode *frame;
1030     IWICMetadataBlockReader *blockreader;
1031     IWICMetadataReader *reader;
1032     GUID format;
1033     HRESULT hr;
1034     UINT count;
1035
1036     /* 1x1 pixel gif */
1037     stream = create_stream(gifimage, sizeof(gifimage));
1038
1039     hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1040                           &IID_IWICBitmapDecoder, (void **)&decoder);
1041     ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
1042     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1043     ok(hr == S_OK, "Initialize error %#x\n", hr);
1044
1045     IStream_Release(stream);
1046
1047     /* global metadata block */
1048     hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1049     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1050
1051     if (SUCCEEDED(hr))
1052     {
1053         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1054         ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1055         ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1056            "wrong container format %s\n", debugstr_guid(&format));
1057
1058         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1059         ok(hr == S_OK, "GetCount error %#x\n", hr);
1060         ok(count == 1, "expected 1, got %u\n", count);
1061
1062         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1063         ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1064
1065         if (SUCCEEDED(hr))
1066         {
1067             hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1068             ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1069                "wrong container format %s\n", debugstr_guid(&format));
1070
1071             hr = IWICMetadataReader_GetCount(reader, &count);
1072             ok(hr == S_OK, "GetCount error %#x\n", hr);
1073             ok(count == sizeof(gif_LSD)/sizeof(gif_LSD[0]), "unexpected count %u\n", count);
1074
1075             compare_metadata(reader, gif_LSD, count);
1076
1077             IWICMetadataReader_Release(reader);
1078         }
1079
1080         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1081         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1082
1083         IWICMetadataBlockReader_Release(blockreader);
1084     }
1085
1086     /* frame metadata block */
1087     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1088     ok(hr == S_OK, "GetFrame error %#x\n", hr);
1089
1090     hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1091     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1092
1093     if (SUCCEEDED(hr))
1094     {
1095         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1096         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1097
1098         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1099         ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1100         ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1101            "wrong container format %s\n", debugstr_guid(&format));
1102
1103         hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1104         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1105
1106         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1107         ok(hr == S_OK, "GetCount error %#x\n", hr);
1108         ok(count == 1, "expected 1, got %u\n", count);
1109
1110         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1111         ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1112
1113         if (SUCCEEDED(hr))
1114         {
1115             hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1116             ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1117                "wrong container format %s\n", debugstr_guid(&format));
1118
1119             hr = IWICMetadataReader_GetCount(reader, &count);
1120             ok(hr == S_OK, "GetCount error %#x\n", hr);
1121             ok(count == sizeof(gif_IMD)/sizeof(gif_IMD[0]), "unexpected count %u\n", count);
1122
1123             compare_metadata(reader, gif_IMD, count);
1124
1125             IWICMetadataReader_Release(reader);
1126         }
1127
1128         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1129         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1130
1131         IWICMetadataBlockReader_Release(blockreader);
1132     }
1133
1134     IWICBitmapFrameDecode_Release(frame);
1135     IWICBitmapDecoder_Release(decoder);
1136
1137     /* 1x1 pixel gif, 2 frames */
1138     stream = create_stream(gifanimation, sizeof(gifanimation));
1139
1140     hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1141                           &IID_IWICBitmapDecoder, (void **)&decoder);
1142     ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
1143     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1144     ok(hr == S_OK, "Initialize error %#x\n", hr);
1145
1146     IStream_Release(stream);
1147
1148     /* global metadata block */
1149     hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1150     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1151
1152     if (SUCCEEDED(hr))
1153     {
1154         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1155         ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1156         ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1157            "wrong container format %s\n", debugstr_guid(&format));
1158
1159         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1160         ok(hr == S_OK, "GetCount error %#x\n", hr);
1161         ok(count == 1, "expected 1, got %u\n", count);
1162
1163         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1164         ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1165
1166         if (SUCCEEDED(hr))
1167         {
1168             hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1169             ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1170                "wrong container format %s\n", debugstr_guid(&format));
1171
1172             hr = IWICMetadataReader_GetCount(reader, &count);
1173             ok(hr == S_OK, "GetCount error %#x\n", hr);
1174             ok(count == sizeof(animated_gif_LSD)/sizeof(animated_gif_LSD[0]), "unexpected count %u\n", count);
1175
1176             compare_metadata(reader, animated_gif_LSD, count);
1177
1178             IWICMetadataReader_Release(reader);
1179         }
1180
1181         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1182         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1183
1184         IWICMetadataBlockReader_Release(blockreader);
1185     }
1186
1187     /* frame metadata block */
1188     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1189     ok(hr == S_OK, "GetFrame error %#x\n", hr);
1190
1191     hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1192     ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1193
1194     if (SUCCEEDED(hr))
1195     {
1196         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1197         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1198
1199         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1200         ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1201         ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1202            "wrong container format %s\n", debugstr_guid(&format));
1203
1204         hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1205         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1206
1207         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1208         ok(hr == S_OK, "GetCount error %#x\n", hr);
1209         ok(count == 2, "expected 2, got %u\n", count);
1210
1211         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1212         ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1213
1214         if (SUCCEEDED(hr))
1215         {
1216             hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1217             ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1218                "wrong container format %s\n", debugstr_guid(&format));
1219
1220             hr = IWICMetadataReader_GetCount(reader, &count);
1221             ok(hr == S_OK, "GetCount error %#x\n", hr);
1222             ok(count == sizeof(gif_IMD)/sizeof(gif_IMD[0]), "unexpected count %u\n", count);
1223
1224             compare_metadata(reader, gif_IMD, count);
1225
1226             IWICMetadataReader_Release(reader);
1227         }
1228
1229         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1230         ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1231
1232         if (SUCCEEDED(hr))
1233         {
1234             hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1235             ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), /* Graphic Control Extension */
1236                "wrong container format %s\n", debugstr_guid(&format));
1237
1238             hr = IWICMetadataReader_GetCount(reader, &count);
1239             ok(hr == S_OK, "GetCount error %#x\n", hr);
1240             ok(count == sizeof(animated_gif_GCE)/sizeof(animated_gif_GCE[0]), "unexpected count %u\n", count);
1241
1242             compare_metadata(reader, animated_gif_GCE, count);
1243
1244             IWICMetadataReader_Release(reader);
1245         }
1246
1247         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 2, &reader);
1248         ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1249
1250         IWICMetadataBlockReader_Release(blockreader);
1251     }
1252
1253     IWICBitmapFrameDecode_Release(frame);
1254     IWICBitmapDecoder_Release(decoder);
1255 }
1256
1257 static void test_metadata_LSD(void)
1258 {
1259     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};
1260     static const char LSD_data[] = "hello world!\x1\x2\x3\x4\xab\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf";
1261     static const struct test_data td[9] =
1262     {
1263         { VT_UI1|VT_VECTOR, 0, 6, {'w','o','r','l','d','!'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1264         { VT_UI2, 0, 0, { 0x201 }, NULL, { 'W','i','d','t','h',0 } },
1265         { VT_UI2, 0, 0, { 0x403 }, NULL, { 'H','e','i','g','h','t',0 } },
1266         { 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 } },
1267         { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1268         { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1269         { 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 } },
1270         { 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 } },
1271         { VT_UI1, 0, 0, { 7 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1272     };
1273     LARGE_INTEGER pos;
1274     HRESULT hr;
1275     IStream *stream;
1276     IWICPersistStream *persist;
1277     IWICMetadataReader *reader;
1278     IWICMetadataHandlerInfo *info;
1279     WCHAR name[64];
1280     UINT count, dummy;
1281     GUID format;
1282     CLSID id;
1283
1284     hr = CoCreateInstance(&CLSID_WICLSDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1285                           &IID_IWICMetadataReader, (void **)&reader);
1286     ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1287        "CoCreateInstance error %#x\n", hr);
1288
1289     stream = create_stream(LSD_data, sizeof(LSD_data));
1290
1291     if (SUCCEEDED(hr))
1292     {
1293         pos.QuadPart = 6;
1294         hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1295         ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1296
1297         hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1298         ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1299
1300         hr = IWICPersistStream_Load(persist, stream);
1301         ok(hr == S_OK, "Load error %#x\n", hr);
1302
1303         IWICPersistStream_Release(persist);
1304     }
1305
1306     if (SUCCEEDED(hr))
1307     {
1308         hr = IWICMetadataReader_GetCount(reader, &count);
1309         ok(hr == S_OK, "GetCount error %#x\n", hr);
1310         ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
1311
1312         compare_metadata(reader, td, count);
1313
1314         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1315         ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1316         ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), "wrong format %s\n", debugstr_guid(&format));
1317
1318         hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1319         ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1320
1321         hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1322         ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1323         ok(IsEqualGUID(&id, &CLSID_WICLSDMetadataReader), "wrong CLSID %s\n", debugstr_guid(&id));
1324
1325         hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1326         ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1327         ok(lstrcmpW(name, LSD_name) == 0, "wrong LSD reader name %s\n", wine_dbgstr_w(name));
1328
1329         IWICMetadataHandlerInfo_Release(info);
1330         IWICMetadataReader_Release(reader);
1331     }
1332
1333     IStream_Release(stream);
1334 }
1335
1336 static void test_metadata_IMD(void)
1337 {
1338     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};
1339     static const char IMD_data[] = "hello world!\x1\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
1340     static const struct test_data td[8] =
1341     {
1342         { VT_UI2, 0, 0, { 0x201 }, NULL, { 'L','e','f','t',0 } },
1343         { VT_UI2, 0, 0, { 0x403 }, NULL, { 'T','o','p',0 } },
1344         { VT_UI2, 0, 0, { 0x605 }, NULL, { 'W','i','d','t','h',0 } },
1345         { VT_UI2, 0, 0, { 0x807 }, NULL, { 'H','e','i','g','h','t',0 } },
1346         { 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 } },
1347         { VT_BOOL, 0, 0, { 1 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1348         { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1349         { 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 } }
1350     };
1351     LARGE_INTEGER pos;
1352     HRESULT hr;
1353     IStream *stream;
1354     IWICPersistStream *persist;
1355     IWICMetadataReader *reader;
1356     IWICMetadataHandlerInfo *info;
1357     WCHAR name[64];
1358     UINT count, dummy;
1359     GUID format;
1360     CLSID id;
1361
1362     hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1363                           &IID_IWICMetadataReader, (void **)&reader);
1364     ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1365        "CoCreateInstance error %#x\n", hr);
1366
1367     stream = create_stream(IMD_data, sizeof(IMD_data));
1368
1369     if (SUCCEEDED(hr))
1370     {
1371         pos.QuadPart = 12;
1372         hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1373         ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1374
1375         hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1376         ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1377
1378         hr = IWICPersistStream_Load(persist, stream);
1379         ok(hr == S_OK, "Load error %#x\n", hr);
1380
1381         IWICPersistStream_Release(persist);
1382     }
1383
1384     if (SUCCEEDED(hr))
1385     {
1386         hr = IWICMetadataReader_GetCount(reader, &count);
1387         ok(hr == S_OK, "GetCount error %#x\n", hr);
1388         ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
1389
1390         compare_metadata(reader, td, count);
1391
1392         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1393         ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1394         ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong format %s\n", debugstr_guid(&format));
1395
1396         hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1397         ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1398
1399         hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1400         ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1401         ok(IsEqualGUID(&id, &CLSID_WICIMDMetadataReader), "wrong CLSID %s\n", debugstr_guid(&id));
1402
1403         hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1404         ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1405         ok(lstrcmpW(name, IMD_name) == 0, "wrong IMD reader name %s\n", wine_dbgstr_w(name));
1406
1407         IWICMetadataHandlerInfo_Release(info);
1408         IWICMetadataReader_Release(reader);
1409     }
1410
1411     IStream_Release(stream);
1412 }
1413
1414 static void test_metadata_GCE(void)
1415 {
1416     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};
1417     static const char GCE_data[] = "hello world!\xa\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
1418     static const struct test_data td[5] =
1419     {
1420         { VT_UI1, 0, 0, { 2 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
1421         { VT_BOOL, 0, 0, { 1 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
1422         { VT_BOOL, 0, 0, { 0 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
1423         { VT_UI2, 0, 0, { 0x302 }, NULL, { 'D','e','l','a','y',0 } },
1424         { 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 } }
1425     };
1426     LARGE_INTEGER pos;
1427     HRESULT hr;
1428     IStream *stream;
1429     IWICPersistStream *persist;
1430     IWICMetadataReader *reader;
1431     IWICMetadataHandlerInfo *info;
1432     WCHAR name[64];
1433     UINT count, dummy;
1434     GUID format;
1435     CLSID id;
1436
1437     hr = CoCreateInstance(&CLSID_WICGCEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1438                           &IID_IWICMetadataReader, (void **)&reader);
1439     ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1440        "CoCreateInstance error %#x\n", hr);
1441
1442     stream = create_stream(GCE_data, sizeof(GCE_data));
1443
1444     if (SUCCEEDED(hr))
1445     {
1446         pos.QuadPart = 12;
1447         hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1448         ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1449
1450         hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1451         ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1452
1453         hr = IWICPersistStream_Load(persist, stream);
1454         ok(hr == S_OK, "Load error %#x\n", hr);
1455
1456         IWICPersistStream_Release(persist);
1457     }
1458
1459     if (SUCCEEDED(hr))
1460     {
1461         hr = IWICMetadataReader_GetCount(reader, &count);
1462         ok(hr == S_OK, "GetCount error %#x\n", hr);
1463         ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
1464
1465         compare_metadata(reader, td, count);
1466
1467         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1468         ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1469         ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), "wrong format %s\n", debugstr_guid(&format));
1470
1471         hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1472         ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1473
1474         hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1475         ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1476         ok(IsEqualGUID(&id, &CLSID_WICGCEMetadataReader), "wrong CLSID %s\n", debugstr_guid(&id));
1477
1478         hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1479         ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1480         ok(lstrcmpW(name, GCE_name) == 0, "wrong GCE reader name %s\n", wine_dbgstr_w(name));
1481
1482         IWICMetadataHandlerInfo_Release(info);
1483         IWICMetadataReader_Release(reader);
1484     }
1485
1486     IStream_Release(stream);
1487 }
1488
1489 static void test_metadata_APE(void)
1490 {
1491     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};
1492     static const char APE_data[] = { 0x21,0xff,0x0b,'H','e','l','l','o',' ','W','o','r','l','d',
1493                                      /*sub-block*/1,0x11,
1494                                      /*sub-block*/2,0x22,0x33,
1495                                      /*sub-block*/4,0x44,0x55,0x66,0x77,
1496                                      /*terminator*/0 };
1497     static const struct test_data td[2] =
1498     {
1499         { 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 } },
1500         { VT_UI1|VT_VECTOR, 0, 10, { 1,0x11,2,0x22,0x33,4,0x44,0x55,0x66,0x77 }, NULL, { 'D','a','t','a',0 } }
1501     };
1502     HRESULT hr;
1503     IStream *stream;
1504     IWICPersistStream *persist;
1505     IWICMetadataReader *reader;
1506     IWICMetadataHandlerInfo *info;
1507     WCHAR name[64];
1508     UINT count, dummy;
1509     GUID format;
1510     CLSID id;
1511
1512     hr = CoCreateInstance(&CLSID_WICAPEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1513                           &IID_IWICMetadataReader, (void **)&reader);
1514 todo_wine
1515     ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1516        "CoCreateInstance error %#x\n", hr);
1517
1518     stream = create_stream(APE_data, sizeof(APE_data));
1519
1520     if (SUCCEEDED(hr))
1521     {
1522         hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1523         ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1524
1525         hr = IWICPersistStream_Load(persist, stream);
1526         ok(hr == S_OK, "Load error %#x\n", hr);
1527
1528         IWICPersistStream_Release(persist);
1529     }
1530
1531     if (SUCCEEDED(hr))
1532     {
1533         hr = IWICMetadataReader_GetCount(reader, &count);
1534         ok(hr == S_OK, "GetCount error %#x\n", hr);
1535         ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
1536
1537         compare_metadata(reader, td, count);
1538
1539         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1540         ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1541         ok(IsEqualGUID(&format, &GUID_MetadataFormatAPE), "wrong format %s\n", debugstr_guid(&format));
1542
1543         hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1544         ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1545
1546         hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1547         ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1548         ok(IsEqualGUID(&id, &CLSID_WICAPEMetadataReader), "wrong CLSID %s\n", debugstr_guid(&id));
1549
1550         hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1551         ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1552         ok(lstrcmpW(name, APE_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
1553
1554         IWICMetadataHandlerInfo_Release(info);
1555         IWICMetadataReader_Release(reader);
1556     }
1557
1558     IStream_Release(stream);
1559 }
1560
1561 static void test_metadata_GIF_comment(void)
1562 {
1563     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};
1564     static const char GIF_comment_data[] = { 0x21,0xfe,
1565                                              /*sub-block*/5,'H','e','l','l','o',
1566                                              /*sub-block*/1,' ',
1567                                              /*sub-block*/6,'W','o','r','l','d','!',
1568                                              /*terminator*/0 };
1569     static const struct test_data td[1] =
1570     {
1571         { VT_LPSTR, 0, 12, { 0 }, "Hello World!", { 'T','e','x','t','E','n','t','r','y',0 } }
1572     };
1573     HRESULT hr;
1574     IStream *stream;
1575     IWICPersistStream *persist;
1576     IWICMetadataReader *reader;
1577     IWICMetadataHandlerInfo *info;
1578     WCHAR name[64];
1579     UINT count, dummy;
1580     GUID format;
1581     CLSID id;
1582
1583     hr = CoCreateInstance(&CLSID_WICGifCommentMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1584                           &IID_IWICMetadataReader, (void **)&reader);
1585 todo_wine
1586     ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1587        "CoCreateInstance error %#x\n", hr);
1588
1589     stream = create_stream(GIF_comment_data, sizeof(GIF_comment_data));
1590
1591     if (SUCCEEDED(hr))
1592     {
1593         hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1594         ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1595
1596         hr = IWICPersistStream_Load(persist, stream);
1597         ok(hr == S_OK, "Load error %#x\n", hr);
1598
1599         IWICPersistStream_Release(persist);
1600     }
1601
1602     if (SUCCEEDED(hr))
1603     {
1604         hr = IWICMetadataReader_GetCount(reader, &count);
1605         ok(hr == S_OK, "GetCount error %#x\n", hr);
1606         ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
1607
1608         compare_metadata(reader, td, count);
1609
1610         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1611         ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1612         ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), "wrong format %s\n", debugstr_guid(&format));
1613
1614         hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1615         ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1616
1617         hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1618         ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1619         ok(IsEqualGUID(&id, &CLSID_WICGifCommentMetadataReader), "wrong CLSID %s\n", debugstr_guid(&id));
1620
1621         hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1622         ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1623         ok(lstrcmpW(name, GIF_comment_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
1624
1625         IWICMetadataHandlerInfo_Release(info);
1626         IWICMetadataReader_Release(reader);
1627     }
1628
1629     IStream_Release(stream);
1630 }
1631
1632 START_TEST(metadata)
1633 {
1634     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1635
1636     test_metadata_unknown();
1637     test_metadata_tEXt();
1638     test_metadata_IFD();
1639     test_metadata_Exif();
1640     test_create_reader();
1641     test_metadata_png();
1642     test_metadata_gif();
1643     test_metadata_LSD();
1644     test_metadata_IMD();
1645     test_metadata_GCE();
1646     test_metadata_APE();
1647     test_metadata_GIF_comment();
1648
1649     CoUninitialize();
1650 }