windowscodecs: Implement IWICComponentInfo::GetVendorGUID.
[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
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29 #include "wincodecsdk.h"
30 #include "wine/test.h"
31
32 #define expect_blob(propvar, data, length) do { \
33     ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
34     if ((propvar).vt == VT_BLOB) { \
35         ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
36         if (U(propvar).blob.cbSize == (length)) { \
37             ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
38         } \
39     } \
40 } while (0)
41
42 #define IFD_SHORT 3
43 #define IFD_LONG 4
44 #define IFD_RATIONAL 5
45
46 #include "pshpack2.h"
47 struct IFD_entry
48 {
49     SHORT id;
50     SHORT type;
51     ULONG length;
52     LONG  value;
53 };
54
55 struct IFD_rational
56 {
57     LONG numerator;
58     LONG denominator;
59 };
60
61 static const struct
62 {
63     USHORT number_of_entries;
64     struct IFD_entry entry[6];
65     ULONG next_IFD;
66     struct IFD_rational xres;
67 } IFD_data =
68 {
69     6,
70     {
71         { 0xfe,  IFD_SHORT, 1, 1 }, /* NEWSUBFILETYPE */
72         { 0x100, IFD_LONG, 1, 222 }, /* IMAGEWIDTH */
73         { 0x101, IFD_LONG, 1, 333 }, /* IMAGELENGTH */
74         { 0x102, IFD_SHORT, 1, 24 }, /* BITSPERSAMPLE */
75         { 0x103, IFD_LONG, 1, 32773 }, /* COMPRESSION: packbits */
76         { 0x11a, IFD_RATIONAL, 1, /* XRESOLUTION */
77           sizeof(USHORT) + sizeof(struct IFD_entry) * 6 + sizeof(ULONG) }
78     },
79     0,
80     { 900, 3 }
81 };
82 #include "poppack.h"
83
84 static const char metadata_unknown[] = "lalala";
85
86 static const char metadata_tEXt[] = {
87     0,0,0,14, /* chunk length */
88     't','E','X','t', /* chunk type */
89     'w','i','n','e','t','e','s','t',0, /* keyword */
90     'v','a','l','u','e', /* text */
91     0x3f,0x64,0x19,0xf3 /* chunk CRC */
92 };
93
94 static const char pngimage[285] = {
95 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
96 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
97 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
98 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
99 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
100 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
101 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
102 };
103
104 static const char *debugstr_guid(REFIID riid)
105 {
106     static char buf[50];
107
108     if(!riid)
109         return "(null)";
110
111     sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
112             riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
113             riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
114             riid->Data4[5], riid->Data4[6], riid->Data4[7]);
115
116     return buf;
117 }
118
119 static IStream *create_stream(const char *data, int data_size)
120 {
121     HRESULT hr;
122     IStream *stream;
123     HGLOBAL hdata;
124     void *locked_data;
125
126     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
127     ok(hdata != 0, "GlobalAlloc failed\n");
128     if (!hdata) return NULL;
129
130     locked_data = GlobalLock(hdata);
131     memcpy(locked_data, data, data_size);
132     GlobalUnlock(hdata);
133
134     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
135     ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
136
137     return stream;
138 }
139
140 static void load_stream(IUnknown *reader, const char *data, int data_size)
141 {
142     HRESULT hr;
143     IWICPersistStream *persist;
144     IStream *stream;
145     LARGE_INTEGER pos;
146     ULARGE_INTEGER cur_pos;
147
148     stream = create_stream(data, data_size);
149     if (!stream)
150         return;
151
152     hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
153     ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
154
155     if (SUCCEEDED(hr))
156     {
157         hr = IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
158         ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
159
160         IWICPersistStream_Release(persist);
161     }
162
163     pos.QuadPart = 0;
164     hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos);
165     ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
166     /* IFD metadata reader doesn't rewind the stream to the start */
167     ok(cur_pos.QuadPart == 0 || cur_pos.QuadPart <= data_size,
168        "current stream pos is at %x/%x, data size %x\n", cur_pos.u.LowPart, cur_pos.u.HighPart, data_size);
169
170     IStream_Release(stream);
171 }
172
173 static void test_metadata_unknown(void)
174 {
175     HRESULT hr;
176     IWICMetadataReader *reader;
177     IWICEnumMetadataItem *enumerator;
178     IWICMetadataBlockReader *blockreader;
179     PROPVARIANT schema, id, value;
180     ULONG items_returned;
181
182     hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
183         &IID_IWICMetadataReader, (void**)&reader);
184     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
185     if (FAILED(hr)) return;
186
187     load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown));
188
189     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
190     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
191
192     if (SUCCEEDED(hr))
193     {
194         PropVariantInit(&schema);
195         PropVariantInit(&id);
196         PropVariantInit(&value);
197
198         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
199         ok(hr == S_OK, "Next failed, hr=%x\n", hr);
200         ok(items_returned == 1, "unexpected item count %i\n", items_returned);
201
202         if (hr == S_OK && items_returned == 1)
203         {
204             ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
205             ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
206             expect_blob(value, metadata_unknown, sizeof(metadata_unknown));
207
208             PropVariantClear(&schema);
209             PropVariantClear(&id);
210             PropVariantClear(&value);
211         }
212
213         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
214         ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
215         ok(items_returned == 0, "unexpected item count %i\n", items_returned);
216
217         IWICEnumMetadataItem_Release(enumerator);
218     }
219
220     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
221     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
222
223     if (SUCCEEDED(hr))
224         IWICMetadataBlockReader_Release(blockreader);
225
226     IWICMetadataReader_Release(reader);
227 }
228
229 static void test_metadata_tEXt(void)
230 {
231     HRESULT hr;
232     IWICMetadataReader *reader;
233     IWICEnumMetadataItem *enumerator;
234     PROPVARIANT schema, id, value;
235     ULONG items_returned, count;
236     GUID format;
237
238     PropVariantInit(&schema);
239     PropVariantInit(&id);
240     PropVariantInit(&value);
241
242     hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
243         &IID_IWICMetadataReader, (void**)&reader);
244     todo_wine ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
245     if (FAILED(hr)) return;
246
247     hr = IWICMetadataReader_GetCount(reader, NULL);
248     ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
249
250     hr = IWICMetadataReader_GetCount(reader, &count);
251     ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
252     ok(count == 0, "unexpected count %i\n", count);
253
254     load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt));
255
256     hr = IWICMetadataReader_GetCount(reader, &count);
257     ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
258     ok(count == 1, "unexpected count %i\n", count);
259
260     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
261     ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
262
263     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
264     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
265
266     if (SUCCEEDED(hr))
267     {
268         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
269         ok(hr == S_OK, "Next failed, hr=%x\n", hr);
270         ok(items_returned == 1, "unexpected item count %i\n", items_returned);
271
272         if (hr == S_OK && items_returned == 1)
273         {
274             ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
275             ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
276             ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
277             ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
278             ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
279
280             PropVariantClear(&schema);
281             PropVariantClear(&id);
282             PropVariantClear(&value);
283         }
284
285         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
286         ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
287         ok(items_returned == 0, "unexpected item count %i\n", items_returned);
288
289         IWICEnumMetadataItem_Release(enumerator);
290     }
291
292     hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
293     ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
294     ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
295
296     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
297     ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
298
299     id.vt = VT_LPSTR;
300     U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
301     strcpy(U(id).pszVal, "winetest");
302
303     hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
304     ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
305
306     hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
307     ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
308
309     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
310     ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
311     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
312     ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
313     PropVariantClear(&value);
314
315     strcpy(U(id).pszVal, "test");
316
317     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
318     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
319
320     PropVariantClear(&id);
321
322     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
323     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
324
325     hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
326     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
327     ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
328
329     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
330     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
331     ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
332     ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
333     PropVariantClear(&id);
334
335     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
336     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
337     ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
338     ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
339     PropVariantClear(&value);
340
341     hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
342     ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
343
344     IWICMetadataReader_Release(reader);
345 }
346
347 static void test_metadata_IFD(void)
348 {
349     static const struct test_data
350     {
351         ULONG type, id;
352         LONGLONG value;
353     } td[6] =
354     {
355         { VT_UI2, 0xfe, 1 },
356         { VT_UI4, 0x100, 222 },
357         { VT_UI4, 0x101, 333 },
358         { VT_UI2, 0x102, 24 },
359         { VT_UI4, 0x103, 32773 },
360         { VT_UI8, 0x11a,  ((LONGLONG)3 << 32) | 900 }
361     };
362     HRESULT hr;
363     IWICMetadataReader *reader;
364     IWICMetadataBlockReader *blockreader;
365     IWICEnumMetadataItem *enumerator;
366     PROPVARIANT schema, id, value;
367     ULONG items_returned, count, i;
368     GUID format;
369
370     PropVariantInit(&schema);
371     PropVariantInit(&id);
372     PropVariantInit(&value);
373
374     hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
375         &IID_IWICMetadataReader, (void**)&reader);
376     ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
377
378     hr = IWICMetadataReader_GetCount(reader, NULL);
379     ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
380
381     hr = IWICMetadataReader_GetCount(reader, &count);
382     ok(hr == S_OK, "GetCount error %#x\n", hr);
383     ok(count == 0, "unexpected count %u\n", count);
384
385     load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data));
386
387     hr = IWICMetadataReader_GetCount(reader, &count);
388     ok(hr == S_OK, "GetCount error %#x\n", hr);
389     ok(count == 6, "unexpected count %u\n", count);
390
391     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
392     ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
393
394     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
395     ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
396
397     for (i = 0; i < count; i++)
398     {
399         hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
400         ok(hr == S_OK, "Next error %#x\n", hr);
401         ok(items_returned == 1, "unexpected item count %u\n", items_returned);
402
403         ok(schema.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, schema.vt);
404         ok(id.vt == VT_UI2, "%u: unexpected vt: %u\n", i, id.vt);
405         ok(U(id).uiVal == td[i].id, "%u: unexpected id: %#x\n", i, U(id).uiVal);
406         ok(value.vt == td[i].type, "%u: unexpected vt: %u\n", i, value.vt);
407         ok(U(value).uhVal.QuadPart == td[i].value, "%u: unexpected id: %d/%d\n", i, U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
408
409         PropVariantClear(&schema);
410         PropVariantClear(&id);
411         PropVariantClear(&value);
412     }
413
414     hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
415     ok(hr == S_FALSE, "Next should fail\n");
416     ok(items_returned == 0, "unexpected item count %u\n", items_returned);
417
418     IWICEnumMetadataItem_Release(enumerator);
419
420     hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
421 todo_wine
422     ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
423 todo_wine
424     ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", debugstr_guid(&format));
425
426     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
427     ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
428
429     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
430 todo_wine
431     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
432     if (FAILED(hr))
433     {
434         IWICMetadataReader_Release(reader);
435         return;
436     }
437
438     hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
439     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
440
441     hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
442     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
443     ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
444
445     hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
446     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
447     ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
448
449     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
450     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
451     ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
452     ok(U(id).uiVal == 0xfe, "unexpected id: %#x\n", U(id).uiVal);
453     PropVariantClear(&id);
454
455     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
456     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
457     ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
458     ok(U(value).ulVal == 1, "unexpected id: %u\n", U(value).ulVal);
459     PropVariantClear(&value);
460
461     hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
462     ok(hr == E_INVALIDARG, "GetValueByIndex should fail\n");
463
464     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
465     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
466
467     if (SUCCEEDED(hr))
468         IWICMetadataBlockReader_Release(blockreader);
469
470     IWICMetadataReader_Release(reader);
471 }
472
473 static void test_metadata_Exif(void)
474 {
475     HRESULT hr;
476     IWICMetadataReader *reader;
477     IWICMetadataBlockReader *blockreader;
478     UINT count=0;
479
480     hr = CoCreateInstance(&CLSID_WICExifMetadataReader, NULL, CLSCTX_INPROC_SERVER,
481         &IID_IWICMetadataReader, (void**)&reader);
482     todo_wine ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
483     if (FAILED(hr)) return;
484
485     hr = IWICMetadataReader_GetCount(reader, NULL);
486     ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
487
488     hr = IWICMetadataReader_GetCount(reader, &count);
489     ok(hr == S_OK, "GetCount error %#x\n", hr);
490     ok(count == 0, "unexpected count %u\n", count);
491
492     hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
493     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
494
495     if (SUCCEEDED(hr))
496         IWICMetadataBlockReader_Release(blockreader);
497
498     IWICMetadataReader_Release(reader);
499 }
500
501 static void test_create_reader(void)
502 {
503     HRESULT hr;
504     IWICComponentFactory *factory;
505     IStream *stream;
506     IWICMetadataReader *reader;
507     UINT count=0;
508     GUID format;
509
510     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
511         &IID_IWICComponentFactory, (void**)&factory);
512     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
513
514     stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
515
516     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
517         &GUID_ContainerFormatPng, NULL, WICPersistOptionsDefault,
518         stream, &reader);
519 todo_wine
520     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
521     if (FAILED(hr)) return;
522
523     if (SUCCEEDED(hr))
524     {
525         hr = IWICMetadataReader_GetCount(reader, &count);
526         ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
527         ok(count == 1, "unexpected count %i\n", count);
528
529         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
530         ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
531         ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
532
533         IWICMetadataReader_Release(reader);
534     }
535
536     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
537         &GUID_ContainerFormatWmp, NULL, WICPersistOptionsDefault,
538         stream, &reader);
539     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
540
541     if (SUCCEEDED(hr))
542     {
543         hr = IWICMetadataReader_GetCount(reader, &count);
544         ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
545         ok(count == 1, "unexpected count %i\n", count);
546
547         hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
548         ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
549         ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", debugstr_guid(&format));
550
551         IWICMetadataReader_Release(reader);
552     }
553
554     IStream_Release(stream);
555
556     IWICComponentFactory_Release(factory);
557 }
558
559 static void test_metadata_png(void)
560 {
561     IStream *stream;
562     IWICBitmapDecoder *decoder;
563     IWICBitmapFrameDecode *frame;
564     IWICMetadataBlockReader *blockreader;
565     IWICMetadataReader *reader;
566     GUID containerformat;
567     HRESULT hr;
568     UINT count;
569
570     hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
571         &IID_IWICBitmapDecoder, (void**)&decoder);
572     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
573
574     if (FAILED(hr)) return;
575
576     stream = create_stream(pngimage, sizeof(pngimage));
577
578     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
579     ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
580
581     hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void**)&blockreader);
582     ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
583
584     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
585     ok(hr == S_OK, "GetFrame failed, hr=%x\n", hr);
586
587     hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void**)&blockreader);
588     ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
589
590     if (SUCCEEDED(hr))
591     {
592         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
593         ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%x\n", hr);
594
595         hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &containerformat);
596         ok(hr == S_OK, "GetContainerFormat failed, hr=%x\n", hr);
597         ok(IsEqualGUID(&containerformat, &GUID_ContainerFormatPng), "unexpected container format\n");
598
599         hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
600         todo_wine ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
601
602         hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
603         todo_wine ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
604         todo_wine ok(count == 1, "unexpected count %d\n", count);
605
606         if (0)
607         {
608             /* Crashes on Windows XP */
609             hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, NULL);
610             ok(hr == E_INVALIDARG, "GetReaderByIndex failed, hr=%x\n", hr);
611         }
612
613         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
614         todo_wine ok(hr == S_OK, "GetReaderByIndex failed, hr=%x\n", hr);
615
616         if (SUCCEEDED(hr))
617         {
618             hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
619             ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
620                broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
621                "unexpected container format\n");
622
623             IWICMetadataReader_Release(reader);
624         }
625
626         hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
627         todo_wine ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "GetReaderByIndex failed, hr=%x\n", hr);
628
629         IWICMetadataBlockReader_Release(blockreader);
630     }
631
632     IWICBitmapFrameDecode_Release(frame);
633
634     IWICBitmapDecoder_Release(decoder);
635
636     IWICStream_Release(stream);
637 }
638
639 START_TEST(metadata)
640 {
641     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
642
643     test_metadata_unknown();
644     test_metadata_tEXt();
645     test_metadata_IFD();
646     test_metadata_Exif();
647     test_create_reader();
648     test_metadata_png();
649
650     CoUninitialize();
651 }