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