ReactOS  0.4.12-dev-934-g9a4676f
metadata.c
Go to the documentation of this file.
1 /*
2  * Copyright 2011 Vincent Povirk for CodeWeavers
3  * Copyright 2012,2017 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <math.h>
23 #include <assert.h>
24 
25 #define COBJMACROS
26 #ifdef __REACTOS__
27 #define CONST_VTABLE
28 #endif
29 
30 #include "windef.h"
31 #include "objbase.h"
32 #include "wincodec.h"
33 #include "wincodecsdk.h"
34 #include "propvarutil.h"
35 #include "wine/test.h"
36 
37 #include "initguid.h"
38 DEFINE_GUID(IID_MdbrUnknown, 0x00240e6f,0x3f23,0x4432,0xb0,0xcc,0x48,0xd5,0xbb,0xff,0x6c,0x36);
39 
40 #define expect_blob(propvar, data, length) do { \
41  ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
42  if ((propvar).vt == VT_BLOB) { \
43  ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
44  if (U(propvar).blob.cbSize == (length)) { \
45  ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
46  } \
47  } \
48 } while (0)
49 
50 #define IFD_BYTE 1
51 #define IFD_ASCII 2
52 #define IFD_SHORT 3
53 #define IFD_LONG 4
54 #define IFD_RATIONAL 5
55 #define IFD_SBYTE 6
56 #define IFD_UNDEFINED 7
57 #define IFD_SSHORT 8
58 #define IFD_SLONG 9
59 #define IFD_SRATIONAL 10
60 #define IFD_FLOAT 11
61 #define IFD_DOUBLE 12
62 #define IFD_IFD 13
63 
64 #include "pshpack2.h"
65 struct IFD_entry
66 {
67  SHORT id;
68  SHORT type;
69  ULONG count;
70  LONG value;
71 };
72 
73 struct IFD_rational
74 {
77 };
78 
79 static const struct ifd_data
80 {
82  struct IFD_entry entry[40];
87  char string[14];
92 } IFD_data =
93 {
94  28,
95  {
96  { 0xfe, IFD_SHORT, 1, 1 }, /* NEWSUBFILETYPE */
97  { 0x100, IFD_LONG, 1, 222 }, /* IMAGEWIDTH */
98  { 0x101, IFD_LONG, 1, 333 }, /* IMAGELENGTH */
99  { 0x102, IFD_SHORT, 1, 24 }, /* BITSPERSAMPLE */
100  { 0x103, IFD_LONG, 1, 32773 }, /* COMPRESSION: packbits */
101  { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct ifd_data, xres) },
102  { 0xf001, IFD_BYTE, 1, 0x11223344 },
103  { 0xf002, IFD_BYTE, 4, 0x11223344 },
104  { 0xf003, IFD_SBYTE, 1, 0x11223344 },
105  { 0xf004, IFD_SSHORT, 1, 0x11223344 },
106  { 0xf005, IFD_SSHORT, 2, 0x11223344 },
107  { 0xf006, IFD_SLONG, 1, 0x11223344 },
108  { 0xf007, IFD_FLOAT, 1, 0x11223344 },
109  { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct ifd_data, double_val) },
110  { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct ifd_data, srational_val) },
111  { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct ifd_data, string) },
112  { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct ifd_data, short_val) },
113  { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct ifd_data, long_val) },
114  { 0xf00d, IFD_FLOAT, 2, FIELD_OFFSET(struct ifd_data, float_val) },
115  { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct ifd_data, string) },
116  { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
117  { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct ifd_data, string) },
118  { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 },
119  { 0xf012, IFD_BYTE, 0, 0x11223344 },
120  { 0xf013, IFD_SHORT, 0, 0x11223344 },
121  { 0xf014, IFD_LONG, 0, 0x11223344 },
122  { 0xf015, IFD_FLOAT, 0, 0x11223344 },
123  { 0xf016, IFD_SRATIONAL, 3, FIELD_OFFSET(struct ifd_data, rational) },
124  },
125  0,
126  { 900, 3 },
127  1234567890.0987654321,
128  { 0x1a2b3c4d, 0x5a6b7c8d },
129  "Hello World!",
130  { 0x0101, 0x0202, 0x0303, 0x0404 },
131  { 0x11223344, 0x55667788 },
132  { (FLOAT)1234.5678, (FLOAT)8765.4321 },
133  { { 0x01020304, 0x05060708 }, { 0x10203040, 0x50607080 }, { 0x11223344, 0x55667788 } },
134 };
135 #include "poppack.h"
136 
137 static const char metadata_unknown[] = "lalala";
138 
139 static const char metadata_tEXt[] = {
140  0,0,0,14, /* chunk length */
141  't','E','X','t', /* chunk type */
142  'w','i','n','e','t','e','s','t',0, /* keyword */
143  'v','a','l','u','e', /* text */
144  0x3f,0x64,0x19,0xf3 /* chunk CRC */
145 };
146 
147 static const char metadata_gAMA[] = {
148  0,0,0,4, /* chunk length */
149  'g','A','M','A', /* chunk type */
150  0,0,130,53, /* gamma */
151  0xff,0xff,0xff,0xff /* chunk CRC */
152 };
153 
154 static const char metadata_cHRM[] = {
155  0,0,0,32, /* chunk length */
156  'c','H','R','M', /* chunk type */
157  0,0,122,38, 0,0,128,132, /* white point */
158  0,0,250,0, 0,0,128,232, /* red */
159  0,0,117,48, 0,0,234,96, /* green */
160  0,0,58,152, 0,0,23,112, /* blue */
161  0xff,0xff,0xff,0xff /* chunk CRC */
162 };
163 
164 static const char pngimage[285] = {
165 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
166 0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
167 0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
168 0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
169 0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
170 0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
171 0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
172 };
173 
174 /* 1x1 pixel gif */
175 static const char gifimage[35] = {
176 0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
177 0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
178 0x01,0x00,0x3b
179 };
180 
181 /* 1x1 pixel gif, 2 frames; first frame is white, second is black */
182 static const char animatedgif[] = {
183 'G','I','F','8','9','a',0x01,0x00,0x01,0x00,0xA1,0x00,0x00,
184 0x6F,0x6F,0x6F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
185 /*0x21,0xFF,0x0B,'N','E','T','S','C','A','P','E','2','.','0',*/
186 0x21,0xFF,0x0B,'A','N','I','M','E','X','T','S','1','.','0',
187 0x03,0x01,0x05,0x00,0x00,
188 0x21,0xFE,0x0C,'H','e','l','l','o',' ','W','o','r','l','d','!',0x00,
189 0x21,0x01,0x0D,'a','n','i','m','a','t','i','o','n','.','g','i','f',0x00,
190 0x21,0xF9,0x04,0x00,0x0A,0x00,0xFF,0x00,0x2C,
191 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
192 0xDE,0xDE,0xDE,0x00,0x00,0x00,
193 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x4C,0x01,0x00,
194 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','1',0x00,
195 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','1',0x00,
196 0x21,0xF9,0x04,0x01,0x0A,0x00,0x01,0x00,0x2C,
197 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x81,
198 0x4D,0x4D,0x4D,0x00,0x00,0x00,
199 0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x44,0x01,0x00,
200 0x21,0xFE,0x08,'i','m','a','g','e',' ','#','2',0x00,
201 0x21,0x01,0x0C,'p','l','a','i','n','t','e','x','t',' ','#','2',0x00,0x3B
202 };
203 
204 static IStream *create_stream(const char *data, int data_size)
205 {
206  HRESULT hr;
207  IStream *stream;
208  HGLOBAL hdata;
209  void *locked_data;
210 
211  hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
212  ok(hdata != 0, "GlobalAlloc failed\n");
213  if (!hdata) return NULL;
214 
215  locked_data = GlobalLock(hdata);
216  memcpy(locked_data, data, data_size);
217  GlobalUnlock(hdata);
218 
219  hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
220  ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
221 
222  return stream;
223 }
224 
225 static void load_stream(IUnknown *reader, const char *data, int data_size, DWORD persist_options)
226 {
227  HRESULT hr;
228  IWICPersistStream *persist;
229  IStream *stream;
231  ULARGE_INTEGER cur_pos;
232 
233  stream = create_stream(data, data_size);
234  if (!stream)
235  return;
236 
237  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
238  ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
239 
240  if (SUCCEEDED(hr))
241  {
242  hr = IWICPersistStream_LoadEx(persist, stream, NULL, persist_options);
243  ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
244 
245  IWICPersistStream_Release(persist);
246  }
247 
248  pos.QuadPart = 0;
249  hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos);
250  ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
251  /* IFD metadata reader doesn't rewind the stream to the start */
252  ok(cur_pos.QuadPart == 0 || cur_pos.QuadPart <= data_size,
253  "current stream pos is at %x/%x, data size %x\n", cur_pos.u.LowPart, cur_pos.u.HighPart, data_size);
254 
255  IStream_Release(stream);
256 }
257 
258 static void test_metadata_unknown(void)
259 {
260  HRESULT hr;
262  IWICEnumMetadataItem *enumerator;
263  IWICMetadataBlockReader *blockreader;
264  PROPVARIANT schema, id, value;
265  ULONG items_returned;
266 
267  hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
268  &IID_IWICMetadataReader, (void**)&reader);
269  ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
270  if (FAILED(hr)) return;
271 
273 
274  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
275  ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
276 
277  if (SUCCEEDED(hr))
278  {
279  PropVariantInit(&schema);
280  PropVariantInit(&id);
281  PropVariantInit(&value);
282 
283  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
284  ok(hr == S_OK, "Next failed, hr=%x\n", hr);
285  ok(items_returned == 1, "unexpected item count %i\n", items_returned);
286 
287  if (hr == S_OK && items_returned == 1)
288  {
289  ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
290  ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
292 
294  PropVariantClear(&id);
296  }
297 
298  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
299  ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
300  ok(items_returned == 0, "unexpected item count %i\n", items_returned);
301 
302  IWICEnumMetadataItem_Release(enumerator);
303  }
304 
305  hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
306  ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
307 
308  if (SUCCEEDED(hr))
309  IWICMetadataBlockReader_Release(blockreader);
310 
311  IWICMetadataReader_Release(reader);
312 }
313 
314 static void test_metadata_tEXt(void)
315 {
316  HRESULT hr;
318  IWICEnumMetadataItem *enumerator;
319  PROPVARIANT schema, id, value;
320  ULONG items_returned, count;
321  GUID format;
322 
323  PropVariantInit(&schema);
324  PropVariantInit(&id);
325  PropVariantInit(&value);
326 
327  hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
328  &IID_IWICMetadataReader, (void**)&reader);
329  ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
330  if (FAILED(hr)) return;
331 
332  hr = IWICMetadataReader_GetCount(reader, NULL);
333  ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
334 
335  hr = IWICMetadataReader_GetCount(reader, &count);
336  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
337  ok(count == 0, "unexpected count %i\n", count);
338 
340 
341  hr = IWICMetadataReader_GetCount(reader, &count);
342  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
343  ok(count == 1, "unexpected count %i\n", count);
344 
345  hr = IWICMetadataReader_GetEnumerator(reader, NULL);
346  ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
347 
348  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
349  ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
350 
351  if (SUCCEEDED(hr))
352  {
353  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
354  ok(hr == S_OK, "Next failed, hr=%x\n", hr);
355  ok(items_returned == 1, "unexpected item count %i\n", items_returned);
356 
357  if (hr == S_OK && items_returned == 1)
358  {
359  ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
360  ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
361  ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
362  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
363  ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
364 
366  PropVariantClear(&id);
368  }
369 
370  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
371  ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
372  ok(items_returned == 0, "unexpected item count %i\n", items_returned);
373 
374  IWICEnumMetadataItem_Release(enumerator);
375  }
376 
377  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
378  ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
379  ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", wine_dbgstr_guid(&format));
380 
381  hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
382  ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
383 
384  id.vt = VT_LPSTR;
385  U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
386  strcpy(U(id).pszVal, "winetest");
387 
388  hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
389  ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
390 
391  hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
392  ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
393 
394  hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
395  ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
396  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
397  ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
399 
400  strcpy(U(id).pszVal, "test");
401 
402  hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
403  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
404 
405  PropVariantClear(&id);
406 
407  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
408  ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
409 
410  hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
411  ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
412  ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
413 
414  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
415  ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
416  ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
417  ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
418  PropVariantClear(&id);
419 
420  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
421  ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
422  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
423  ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
425 
426  hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
427  ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
428 
429  IWICMetadataReader_Release(reader);
430 }
431 
432 static void test_metadata_gAMA(void)
433 {
434  HRESULT hr;
436  PROPVARIANT schema, id, value;
437  ULONG count;
438  GUID format;
439  static const WCHAR ImageGamma[] = {'I','m','a','g','e','G','a','m','m','a',0};
440 
441  PropVariantInit(&schema);
442  PropVariantInit(&id);
443  PropVariantInit(&value);
444 
445  hr = CoCreateInstance(&CLSID_WICPngGamaMetadataReader, NULL, CLSCTX_INPROC_SERVER,
446  &IID_IWICMetadataReader, (void**)&reader);
447  ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%x\n", hr);
448  if (FAILED(hr)) return;
449 
451 
452  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
453  ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
454  ok(IsEqualGUID(&format, &GUID_MetadataFormatChunkgAMA), "unexpected format %s\n", wine_dbgstr_guid(&format));
455 
456  hr = IWICMetadataReader_GetCount(reader, &count);
457  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
458  ok(count == 1, "unexpected count %i\n", count);
459 
460  hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, &id, &value);
461  ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
462 
463  ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
465 
466  ok(id.vt == VT_LPWSTR, "unexpected vt: %i\n", id.vt);
467  ok(!lstrcmpW(U(id).pwszVal, ImageGamma), "unexpected value: %s\n", wine_dbgstr_w(U(id).pwszVal));
468  PropVariantClear(&id);
469 
470  ok(value.vt == VT_UI4, "unexpected vt: %i\n", value.vt);
471  ok(U(value).ulVal == 33333, "unexpected value: %u\n", U(value).ulVal);
473 
474  IWICMetadataReader_Release(reader);
475 }
476 
477 static void test_metadata_cHRM(void)
478 {
479  HRESULT hr;
481  PROPVARIANT schema, id, value;
482  ULONG count;
483  GUID format;
484  int i;
485  static const WCHAR expected_names[8][12] = {
486  {'W','h','i','t','e','P','o','i','n','t','X',0},
487  {'W','h','i','t','e','P','o','i','n','t','Y',0},
488  {'R','e','d','X',0},
489  {'R','e','d','Y',0},
490  {'G','r','e','e','n','X',0},
491  {'G','r','e','e','n','Y',0},
492  {'B','l','u','e','X',0},
493  {'B','l','u','e','Y',0},
494  };
495  static const ULONG expected_vals[8] = {
496  31270,32900, 64000,33000, 30000,60000, 15000,6000
497  };
498 
499  PropVariantInit(&schema);
500  PropVariantInit(&id);
501  PropVariantInit(&value);
502 
503  hr = CoCreateInstance(&CLSID_WICPngChrmMetadataReader, NULL, CLSCTX_INPROC_SERVER,
504  &IID_IWICMetadataReader, (void**)&reader);
505  ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%x\n", hr);
506  if (FAILED(hr)) return;
507 
509 
510  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
511  ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
512  ok(IsEqualGUID(&format, &GUID_MetadataFormatChunkcHRM), "unexpected format %s\n", wine_dbgstr_guid(&format));
513 
514  hr = IWICMetadataReader_GetCount(reader, &count);
515  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
516  ok(count == 8, "unexpected count %i\n", count);
517 
518  for (i=0; i<8; i++)
519  {
520  hr = IWICMetadataReader_GetValueByIndex(reader, i, &schema, &id, &value);
521  ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
522 
523  ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
525 
526  ok(id.vt == VT_LPWSTR, "unexpected vt: %i\n", id.vt);
527  ok(!lstrcmpW(U(id).pwszVal, expected_names[i]), "got %s, expected %s\n", wine_dbgstr_w(U(id).pwszVal), wine_dbgstr_w(expected_names[i]));
528  PropVariantClear(&id);
529 
530  ok(value.vt == VT_UI4, "unexpected vt: %i\n", value.vt);
531  ok(U(value).ulVal == expected_vals[i], "got %u, expected %u\n", U(value).ulVal, expected_vals[i]);
533  }
534 
535  IWICMetadataReader_Release(reader);
536 }
537 
538 static inline USHORT ushort_bswap(USHORT s)
539 {
540  return (s >> 8) | (s << 8);
541 }
542 
543 static inline ULONG ulong_bswap(ULONG l)
544 {
545  return ((ULONG)ushort_bswap((USHORT)l) << 16) | ushort_bswap((USHORT)(l >> 16));
546 }
547 
549 {
550  return ((ULONGLONG)ulong_bswap((ULONG)ll) << 32) | ulong_bswap((ULONG)(ll >> 32));
551 }
552 
553 static void byte_swap_ifd_data(char *data)
554 {
555  USHORT number_of_entries, i;
556  struct IFD_entry *entry;
557  char *data_start = data;
558 
559  number_of_entries = *(USHORT *)data;
560  *(USHORT *)data = ushort_bswap(*(USHORT *)data);
561  data += sizeof(USHORT);
562 
563  for (i = 0; i < number_of_entries; i++)
564  {
565  entry = (struct IFD_entry *)data;
566 
567  switch (entry->type)
568  {
569  case IFD_BYTE:
570  case IFD_SBYTE:
571  case IFD_ASCII:
572  case IFD_UNDEFINED:
573  if (entry->count > 4)
574  entry->value = ulong_bswap(entry->value);
575  break;
576 
577  case IFD_SHORT:
578  case IFD_SSHORT:
579  if (entry->count > 2)
580  {
581  ULONG j, count = entry->count;
582  USHORT *us = (USHORT *)(data_start + entry->value);
583  if (!count) count = 1;
584  for (j = 0; j < count; j++)
585  us[j] = ushort_bswap(us[j]);
586 
587  entry->value = ulong_bswap(entry->value);
588  }
589  else
590  {
591  ULONG j, count = entry->count;
592  USHORT *us = (USHORT *)&entry->value;
593  if (!count) count = 1;
594  for (j = 0; j < count; j++)
595  us[j] = ushort_bswap(us[j]);
596  }
597  break;
598 
599  case IFD_LONG:
600  case IFD_SLONG:
601  case IFD_FLOAT:
602  if (entry->count > 1)
603  {
604  ULONG j, count = entry->count;
605  ULONG *ul = (ULONG *)(data_start + entry->value);
606  if (!count) count = 1;
607  for (j = 0; j < count; j++)
608  ul[j] = ulong_bswap(ul[j]);
609  }
610  entry->value = ulong_bswap(entry->value);
611  break;
612 
613  case IFD_RATIONAL:
614  case IFD_SRATIONAL:
615  {
616  ULONG j;
617  ULONG *ul = (ULONG *)(data_start + entry->value);
618  for (j = 0; j < entry->count * 2; j++)
619  ul[j] = ulong_bswap(ul[j]);
620  }
621  entry->value = ulong_bswap(entry->value);
622  break;
623 
624  case IFD_DOUBLE:
625  {
626  ULONG j;
627  ULONGLONG *ull = (ULONGLONG *)(data_start + entry->value);
628  for (j = 0; j < entry->count; j++)
629  ull[j] = ulonglong_bswap(ull[j]);
630  }
631  entry->value = ulong_bswap(entry->value);
632  break;
633 
634  default:
635  assert(0);
636  break;
637  }
638 
639  entry->id = ushort_bswap(entry->id);
640  entry->type = ushort_bswap(entry->type);
641  entry->count = ulong_bswap(entry->count);
642  data += sizeof(*entry);
643  }
644 }
645 
646 struct test_data
647 {
649  int count; /* if VT_VECTOR */
651  const char *string;
652  const WCHAR id_string[32];
653 };
654 
656 {
657  HRESULT hr;
658  IWICEnumMetadataItem *enumerator;
659  PROPVARIANT schema, id, value;
660  ULONG items_returned, i;
661 
662  hr = IWICMetadataReader_GetEnumerator(reader, NULL);
663  ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
664 
665  hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
666  ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
667 
668  PropVariantInit(&schema);
669  PropVariantInit(&id);
670  PropVariantInit(&value);
671 
672  for (i = 0; i < count; i++)
673  {
674  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
675  ok(hr == S_OK, "Next error %#x\n", hr);
676  ok(items_returned == 1, "unexpected item count %u\n", items_returned);
677 
678  ok(schema.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, schema.vt);
679  ok(id.vt == VT_UI2 || id.vt == VT_LPWSTR || id.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, id.vt);
680  if (id.vt == VT_UI2)
681  ok(U(id).uiVal == td[i].id, "%u: expected id %#x, got %#x\n", i, td[i].id, U(id).uiVal);
682  else if (id.vt == VT_LPWSTR)
683  ok(!lstrcmpW(td[i].id_string, U(id).pwszVal),
684  "%u: expected %s, got %s\n", i, wine_dbgstr_w(td[i].id_string), wine_dbgstr_w(U(id).pwszVal));
685 
686  ok(value.vt == td[i].type, "%u: expected vt %#x, got %#x\n", i, td[i].type, value.vt);
687  if (value.vt & VT_VECTOR)
688  {
689  ULONG j;
690  switch (value.vt & ~VT_VECTOR)
691  {
692  case VT_I1:
693  case VT_UI1:
694  ok(td[i].count == U(value).caub.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
695  for (j = 0; j < U(value).caub.cElems; j++)
696  ok(td[i].value[j] == U(value).caub.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caub.pElems[j]);
697  break;
698  case VT_I2:
699  case VT_UI2:
700  ok(td[i].count == U(value).caui.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caui.cElems);
701  for (j = 0; j < U(value).caui.cElems; j++)
702  ok(td[i].value[j] == U(value).caui.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caui.pElems[j]);
703  break;
704  case VT_I4:
705  case VT_UI4:
706  case VT_R4:
707  ok(td[i].count == U(value).caul.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caul.cElems);
708  for (j = 0; j < U(value).caul.cElems; j++)
709  ok(td[i].value[j] == U(value).caul.pElems[j], "%u: expected value[%d] %#x/%#x, got %#x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).caul.pElems[j]);
710  break;
711  case VT_I8:
712  case VT_UI8:
713  case VT_R8:
714  ok(td[i].count == U(value).cauh.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).cauh.cElems);
715  for (j = 0; j < U(value).cauh.cElems; j++)
716  ok(td[i].value[j] == U(value).cauh.pElems[j].QuadPart, "%u: expected value[%d] %08x/%08x, got %08x/%08x\n", i, j, (ULONG)td[i].value[j], (ULONG)(td[i].value[j] >> 32), U(value).cauh.pElems[j].u.LowPart, U(value).cauh.pElems[j].u.HighPart);
717  break;
718  case VT_LPSTR:
719  ok(td[i].count == U(value).calpstr.cElems, "%u: expected cElems %d, got %d\n", i, td[i].count, U(value).caub.cElems);
720  for (j = 0; j < U(value).calpstr.cElems; j++)
721  trace("%u: %s\n", j, U(value).calpstr.pElems[j]);
722  /* fall through to not handled message */
723  default:
724  ok(0, "%u: array of type %d is not handled\n", i, value.vt & ~VT_VECTOR);
725  break;
726  }
727  }
728  else if (value.vt == VT_LPSTR)
729  {
730  ok(td[i].count == strlen(U(value).pszVal) ||
731  broken(td[i].count == strlen(U(value).pszVal) + 1), /* before Win7 */
732  "%u: expected count %d, got %d\n", i, td[i].count, lstrlenA(U(value).pszVal));
733  if (td[i].count == strlen(U(value).pszVal))
734  ok(!strcmp(td[i].string, U(value).pszVal),
735  "%u: expected %s, got %s\n", i, td[i].string, U(value).pszVal);
736  }
737  else if (value.vt == VT_BLOB)
738  {
739  ok(td[i].count == U(value).blob.cbSize, "%u: expected count %d, got %d\n", i, td[i].count, U(value).blob.cbSize);
740  ok(!memcmp(td[i].string, U(value).blob.pBlobData, td[i].count), "%u: expected %s, got %s\n", i, td[i].string, U(value).blob.pBlobData);
741  }
742  else
743  ok(U(value).uhVal.QuadPart == td[i].value[0], "%u: expected value %#x/%#x got %#x/%#x\n",
744  i, (UINT)td[i].value[0], (UINT)(td[i].value[0] >> 32), U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
745 
747  PropVariantClear(&id);
749  }
750 
751  hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
752  ok(hr == S_FALSE, "Next should fail\n");
753  ok(items_returned == 0, "unexpected item count %u\n", items_returned);
754 
755  IWICEnumMetadataItem_Release(enumerator);
756 }
757 
758 static void test_metadata_IFD(void)
759 {
760  static const struct test_data td[28] =
761  {
762  { VT_UI2, 0xfe, 0, { 1 } },
763  { VT_UI4, 0x100, 0, { 222 } },
764  { VT_UI4, 0x101, 0, { 333 } },
765  { VT_UI2, 0x102, 0, { 24 } },
766  { VT_UI4, 0x103, 0, { 32773 } },
767  { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
768  { VT_UI1, 0xf001, 0, { 0x44 } },
769  { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
770  { VT_I1, 0xf003, 0, { 0x44 } },
771  { VT_I2, 0xf004, 0, { 0x3344 } },
772  { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
773  { VT_I4, 0xf006, 0, { 0x11223344 } },
774  { VT_R4, 0xf007, 0, { 0x11223344 } },
775  { VT_R8, 0xf008, 0, { ((LONGLONG)0x41d26580 << 32) | 0xb486522c } },
776  { VT_I8, 0xf009, 0, { ((LONGLONG)0x5a6b7c8d << 32) | 0x1a2b3c4d } },
777  { VT_UI1|VT_VECTOR, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
778  { VT_I2|VT_VECTOR, 0xf00b, 4, { 0x0101, 0x0202, 0x0303, 0x0404 } },
779  { VT_I4|VT_VECTOR, 0xf00c, 2, { 0x11223344, 0x55667788 } },
780  { VT_R4|VT_VECTOR, 0xf00d, 2, { 0x449a522b, 0x4608f5ba } },
781  { VT_LPSTR, 0xf00e, 12, { 0 }, "Hello World!" },
782  { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
783  { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
784  { VT_BLOB, 0xf011, 4, { 0 }, "abcd" },
785  { VT_UI1, 0xf012, 0, { 0x44 } },
786  { VT_UI2, 0xf013, 0, { 0x3344 } },
787  { VT_UI4, 0xf014, 0, { 0x11223344 } },
788  { VT_R4, 0xf015, 0, { 0x11223344 } },
789  { VT_I8|VT_VECTOR, 0xf016, 3,
790  { ((LONGLONG)0x05060708 << 32) | 0x01020304,
791  ((LONGLONG)0x50607080 << 32) | 0x10203040,
792  ((LONGLONG)0x55667788 << 32) | 0x11223344 } },
793  };
794  HRESULT hr;
796  IWICMetadataBlockReader *blockreader;
797  PROPVARIANT schema, id, value;
798  ULONG count;
799  GUID format;
800  char *IFD_data_swapped;
801 #ifdef WORDS_BIGENDIAN
802  DWORD persist_options = WICPersistOptionBigEndian;
803 #else
804  DWORD persist_options = WICPersistOptionLittleEndian;
805 #endif
806 
807  hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
808  &IID_IWICMetadataReader, (void**)&reader);
809  ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
810 
811  hr = IWICMetadataReader_GetCount(reader, NULL);
812  ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
813 
814  hr = IWICMetadataReader_GetCount(reader, &count);
815  ok(hr == S_OK, "GetCount error %#x\n", hr);
816  ok(count == 0, "unexpected count %u\n", count);
817 
818  load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data), persist_options);
819 
820  hr = IWICMetadataReader_GetCount(reader, &count);
821  ok(hr == S_OK, "GetCount error %#x\n", hr);
822  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
823 
825 
826  /* test IFD data with different endianness */
827  if (persist_options == WICPersistOptionLittleEndian)
828  persist_options = WICPersistOptionBigEndian;
829  else
830  persist_options = WICPersistOptionLittleEndian;
831 
832  IFD_data_swapped = HeapAlloc(GetProcessHeap(), 0, sizeof(IFD_data));
833  memcpy(IFD_data_swapped, &IFD_data, sizeof(IFD_data));
834  byte_swap_ifd_data(IFD_data_swapped);
835  load_stream((IUnknown *)reader, IFD_data_swapped, sizeof(IFD_data), persist_options);
836  hr = IWICMetadataReader_GetCount(reader, &count);
837  ok(hr == S_OK, "GetCount error %#x\n", hr);
838  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
840  HeapFree(GetProcessHeap(), 0, IFD_data_swapped);
841 
842  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
843  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
844  ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", wine_dbgstr_guid(&format));
845 
846  hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
847  ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
848 
849  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
850  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
851 
852  PropVariantInit(&schema);
853  PropVariantInit(&id);
854  PropVariantInit(&value);
855 
856  hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
857  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
858 
859  hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
860  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
861  ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
862 
863  hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
864  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
865  ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
866 
867  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
868  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
869  ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
870  ok(U(id).uiVal == 0xfe, "unexpected id: %#x\n", U(id).uiVal);
871  PropVariantClear(&id);
872 
873  hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
874  ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
875  ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
876  ok(U(value).uiVal == 1, "unexpected id: %#x\n", U(value).uiVal);
878 
879  hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
880  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
881 
882  PropVariantInit(&schema);
883  PropVariantInit(&id);
884  PropVariantInit(&value);
885 
886  hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
887  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
888 
889  hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
890  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
891 
892  hr = IWICMetadataReader_GetValue(reader, &schema, NULL, NULL);
893  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
894 
895  hr = IWICMetadataReader_GetValue(reader, &schema, &id, NULL);
896  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "expected WINCODEC_ERR_PROPERTYNOTFOUND, got %#x\n", hr);
897 
898  hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
899  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
900 
901  id.vt = VT_UI2;
902  U(id).uiVal = 0xf00e;
903  hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
904  ok(hr == S_OK, "GetValue error %#x\n", hr);
905 
906  /* schema is ignored by Ifd metadata reader */
907  schema.vt = VT_UI4;
908  U(schema).ulVal = 0xdeadbeef;
909  hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
910  ok(hr == S_OK, "GetValue error %#x\n", hr);
911  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
912  ok(!strcmp(U(value).pszVal, "Hello World!"), "unexpected value: %s\n", U(value).pszVal);
914 
915  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
916  ok(hr == S_OK, "GetValue error %#x\n", hr);
917  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
918  ok(!strcmp(U(value).pszVal, "Hello World!"), "unexpected value: %s\n", U(value).pszVal);
920 
921  hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
922  ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
923 
924  if (SUCCEEDED(hr))
925  IWICMetadataBlockReader_Release(blockreader);
926 
927  IWICMetadataReader_Release(reader);
928 }
929 
930 static void test_metadata_Exif(void)
931 {
932  HRESULT hr;
934  IWICMetadataBlockReader *blockreader;
935  UINT count=0;
936 
937  hr = CoCreateInstance(&CLSID_WICExifMetadataReader, NULL, CLSCTX_INPROC_SERVER,
938  &IID_IWICMetadataReader, (void**)&reader);
939  todo_wine ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
940  if (FAILED(hr)) return;
941 
942  hr = IWICMetadataReader_GetCount(reader, NULL);
943  ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
944 
945  hr = IWICMetadataReader_GetCount(reader, &count);
946  ok(hr == S_OK, "GetCount error %#x\n", hr);
947  ok(count == 0, "unexpected count %u\n", count);
948 
949  hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICMetadataBlockReader, (void**)&blockreader);
950  ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
951 
952  if (SUCCEEDED(hr))
953  IWICMetadataBlockReader_Release(blockreader);
954 
955  IWICMetadataReader_Release(reader);
956 }
957 
958 static void test_create_reader(void)
959 {
960  HRESULT hr;
962  IStream *stream;
964  UINT count=0;
965  GUID format;
966 
967  hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
968  &IID_IWICComponentFactory, (void**)&factory);
969  ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
970 
972 
973  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
975  stream, &reader);
976  ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
977 
978  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
979  &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
980  NULL, &reader);
981  ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
982 
983  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
984  &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
985  stream, NULL);
986  ok(hr == E_INVALIDARG, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
987 
988  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
989  &GUID_ContainerFormatPng, NULL, WICPersistOptionDefault,
990  stream, &reader);
991  ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
992 
993  if (SUCCEEDED(hr))
994  {
995  hr = IWICMetadataReader_GetCount(reader, &count);
996  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
997  ok(count == 1, "unexpected count %i\n", count);
998 
999  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1000  ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
1001  ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", wine_dbgstr_guid(&format));
1002 
1003  IWICMetadataReader_Release(reader);
1004  }
1005 
1006  hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
1007  &GUID_ContainerFormatWmp, NULL, WICPersistOptionDefault,
1008  stream, &reader);
1009  ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
1010 
1011  if (SUCCEEDED(hr))
1012  {
1013  hr = IWICMetadataReader_GetCount(reader, &count);
1014  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
1015  ok(count == 1, "unexpected count %i\n", count);
1016 
1017  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1018  ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
1019  ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", wine_dbgstr_guid(&format));
1020 
1021  IWICMetadataReader_Release(reader);
1022  }
1023 
1024  IStream_Release(stream);
1025 
1026  IWICComponentFactory_Release(factory);
1027 }
1028 
1029 static void test_metadata_png(void)
1030 {
1031  static const struct test_data td[6] =
1032  {
1033  { VT_UI2, 0, 0, { 2005 }, NULL, { 'Y','e','a','r',0 } },
1034  { VT_UI1, 0, 0, { 6 }, NULL, { 'M','o','n','t','h',0 } },
1035  { VT_UI1, 0, 0, { 3 }, NULL, { 'D','a','y',0 } },
1036  { VT_UI1, 0, 0, { 15 }, NULL, { 'H','o','u','r',0 } },
1037  { VT_UI1, 0, 0, { 7 }, NULL, { 'M','i','n','u','t','e',0 } },
1038  { VT_UI1, 0, 0, { 45 }, NULL, { 'S','e','c','o','n','d',0 } }
1039  };
1040  IStream *stream;
1041  IWICBitmapDecoder *decoder;
1042  IWICBitmapFrameDecode *frame;
1043  IWICMetadataBlockReader *blockreader;
1045  IWICMetadataQueryReader *queryreader;
1047  GUID containerformat;
1048  HRESULT hr;
1049  UINT count=0xdeadbeef;
1050 
1051  hr = CoCreateInstance(&CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER,
1052  &IID_IWICBitmapDecoder, (void**)&decoder);
1053  ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
1054 
1055  if (FAILED(hr)) return;
1056 
1057  stream = create_stream(pngimage, sizeof(pngimage));
1058 
1059  hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1060  ok(hr == S_OK, "Initialize failed, hr=%x\n", hr);
1061 
1062  hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1063  ok(hr == E_NOINTERFACE, "QueryInterface failed, hr=%x\n", hr);
1064 
1065  hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1066  ok(hr == S_OK, "GetFrame failed, hr=%x\n", hr);
1067 
1068  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void**)&blockreader);
1069  ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
1070 
1071  if (SUCCEEDED(hr))
1072  {
1073  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1074  ok(hr == E_INVALIDARG, "GetContainerFormat failed, hr=%x\n", hr);
1075 
1076  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &containerformat);
1077  ok(hr == S_OK, "GetContainerFormat failed, hr=%x\n", hr);
1078  ok(IsEqualGUID(&containerformat, &GUID_ContainerFormatPng), "unexpected container format\n");
1079 
1080  hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1081  ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
1082 
1083  hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1084  ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
1085  ok(count == 1, "unexpected count %d\n", count);
1086 
1087  if (0)
1088  {
1089  /* Crashes on Windows XP */
1090  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, NULL);
1091  ok(hr == E_INVALIDARG, "GetReaderByIndex failed, hr=%x\n", hr);
1092  }
1093 
1094  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1095  ok(hr == S_OK, "GetReaderByIndex failed, hr=%x\n", hr);
1096 
1097  if (SUCCEEDED(hr))
1098  {
1099  hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
1100  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1101  todo_wine ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
1102  broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
1103  "unexpected container format\n");
1104 
1105  hr = IWICMetadataReader_GetCount(reader, &count);
1106  ok(hr == S_OK, "GetCount error %#x\n", hr);
1107  todo_wine ok(count == 6 || broken(count == 1) /* XP */, "expected 6, got %u\n", count);
1108  if (count == 6)
1110 
1111  IWICMetadataReader_Release(reader);
1112  }
1113 
1114  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1115  todo_wine ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "GetReaderByIndex failed, hr=%x\n", hr);
1116 
1117  hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1118  &IID_IWICComponentFactory, (void**)&factory);
1119  ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
1120 
1121  hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, NULL, &queryreader);
1122  ok(hr == E_INVALIDARG, "CreateQueryReaderFromBlockReader should have failed: %08x\n", hr);
1123 
1124  hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, blockreader, NULL);
1125  ok(hr == E_INVALIDARG, "CreateQueryReaderFromBlockReader should have failed: %08x\n", hr);
1126 
1127  hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, blockreader, &queryreader);
1128  ok(hr == S_OK, "CreateQueryReaderFromBlockReader failed: %08x\n", hr);
1129 
1130  IWICMetadataQueryReader_Release(queryreader);
1131 
1132  IWICComponentFactory_Release(factory);
1133 
1134  IWICMetadataBlockReader_Release(blockreader);
1135  }
1136 
1137  hr = IWICBitmapFrameDecode_GetMetadataQueryReader(frame, &queryreader);
1138  ok(hr == S_OK, "GetMetadataQueryReader failed: %08x\n", hr);
1139 
1140  if (SUCCEEDED(hr))
1141  {
1142  IWICMetadataQueryReader_Release(queryreader);
1143  }
1144 
1145  IWICBitmapFrameDecode_Release(frame);
1146 
1147  IWICBitmapDecoder_Release(decoder);
1148 
1149  IStream_Release(stream);
1150 }
1151 
1152 static void test_metadata_gif(void)
1153 {
1154  static const struct test_data gif_LSD[9] =
1155  {
1156  { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','7','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1157  { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1158  { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1159  { 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 } },
1160  { VT_UI1, 0, 0, { 0 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1161  { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1162  { 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 } },
1163  { 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 } },
1164  { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1165  };
1166  static const struct test_data gif_IMD[8] =
1167  {
1168  { VT_UI2, 0, 0, { 0 }, NULL, { 'L','e','f','t',0 } },
1169  { VT_UI2, 0, 0, { 0 }, NULL, { 'T','o','p',0 } },
1170  { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1171  { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1172  { 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 } },
1173  { VT_BOOL, 0, 0, { 0 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1174  { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1175  { 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 } }
1176  };
1177  static const struct test_data animated_gif_LSD[9] =
1178  {
1179  { VT_UI1|VT_VECTOR, 0, 6, {'G','I','F','8','9','a'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1180  { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1181  { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1182  { 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 } },
1183  { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1184  { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1185  { 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 } },
1186  { 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 } },
1187  { VT_UI1, 0, 0, { 0 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1188  };
1189  static const struct test_data animated_gif_IMD[8] =
1190  {
1191  { VT_UI2, 0, 0, { 0 }, NULL, { 'L','e','f','t',0 } },
1192  { VT_UI2, 0, 0, { 0 }, NULL, { 'T','o','p',0 } },
1193  { VT_UI2, 0, 0, { 1 }, NULL, { 'W','i','d','t','h',0 } },
1194  { VT_UI2, 0, 0, { 1 }, NULL, { 'H','e','i','g','h','t',0 } },
1195  { 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 } },
1196  { VT_BOOL, 0, 0, { 0 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1197  { VT_BOOL, 0, 0, { 0 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1198  { 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 } }
1199  };
1200  static const struct test_data animated_gif_GCE[5] =
1201  {
1202  { VT_UI1, 0, 0, { 0 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
1203  { VT_BOOL, 0, 0, { 0 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
1204  { VT_BOOL, 0, 0, { 1 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
1205  { VT_UI2, 0, 0, { 10 }, NULL, { 'D','e','l','a','y',0 } },
1206  { 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 } }
1207  };
1208  static const struct test_data animated_gif_APE[2] =
1209  {
1210  { 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 } },
1211  { VT_UI1|VT_VECTOR, 0, 4, { 0x03,0x01,0x05,0x00 }, NULL, { 'D','a','t','a',0 } }
1212  };
1213  static const struct test_data animated_gif_comment_1[1] =
1214  {
1215  { VT_LPSTR, 0, 12, { 0 }, "Hello World!", { 'T','e','x','t','E','n','t','r','y',0 } }
1216  };
1217  static const struct test_data animated_gif_comment_2[1] =
1218  {
1219  { VT_LPSTR, 0, 8, { 0 }, "image #1", { 'T','e','x','t','E','n','t','r','y',0 } }
1220  };
1221  static const struct test_data animated_gif_plain_1[1] =
1222  {
1223  { VT_BLOB, 0, 17, { 0 }, "\x21\x01\x0d\x61nimation.gif" }
1224  };
1225  static const struct test_data animated_gif_plain_2[1] =
1226  {
1227  { VT_BLOB, 0, 16, { 0 }, "\x21\x01\x0cplaintext #1" }
1228  };
1229  IStream *stream;
1230  IWICBitmapDecoder *decoder;
1231  IWICBitmapFrameDecode *frame;
1232  IWICMetadataBlockReader *blockreader;
1234  IWICMetadataQueryReader *queryreader;
1235  GUID format;
1236  HRESULT hr;
1237  UINT count;
1238 
1239  /* 1x1 pixel gif */
1240  stream = create_stream(gifimage, sizeof(gifimage));
1241 
1242  hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1243  &IID_IWICBitmapDecoder, (void **)&decoder);
1244  ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
1245  hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1246  ok(hr == S_OK, "Initialize error %#x\n", hr);
1247 
1248  IStream_Release(stream);
1249 
1250  /* global metadata block */
1251  hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1252  ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1253 
1254  if (SUCCEEDED(hr))
1255  {
1256  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1257  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1258  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1259  "wrong container format %s\n", wine_dbgstr_guid(&format));
1260 
1261  hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1262  ok(hr == S_OK, "GetCount error %#x\n", hr);
1263  ok(count == 1, "expected 1, got %u\n", count);
1264 
1265  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1266  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1267 
1268  if (SUCCEEDED(hr))
1269  {
1270  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1271  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1272  ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1273  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1274 
1275  hr = IWICMetadataReader_GetCount(reader, &count);
1276  ok(hr == S_OK, "GetCount error %#x\n", hr);
1277  ok(count == ARRAY_SIZE(gif_LSD), "unexpected count %u\n", count);
1278 
1279  compare_metadata(reader, gif_LSD, count);
1280 
1281  IWICMetadataReader_Release(reader);
1282  }
1283 
1284  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1285  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1286 
1287  IWICMetadataBlockReader_Release(blockreader);
1288  }
1289 
1290  /* frame metadata block */
1291  hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
1292  ok(hr == S_OK, "GetFrame error %#x\n", hr);
1293 
1294  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1295  ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1296 
1297  if (SUCCEEDED(hr))
1298  {
1299  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1300  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1301 
1302  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1303  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1304  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1305  "wrong container format %s\n", wine_dbgstr_guid(&format));
1306 
1307  hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1308  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1309 
1310  hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1311  ok(hr == S_OK, "GetCount error %#x\n", hr);
1312  ok(count == 1, "expected 1, got %u\n", count);
1313 
1314  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1315  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1316 
1317  if (SUCCEEDED(hr))
1318  {
1319  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1320  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1321  ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1322  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1323 
1324  hr = IWICMetadataReader_GetCount(reader, &count);
1325  ok(hr == S_OK, "GetCount error %#x\n", hr);
1326  ok(count == ARRAY_SIZE(gif_IMD), "unexpected count %u\n", count);
1327 
1328  compare_metadata(reader, gif_IMD, count);
1329 
1330  IWICMetadataReader_Release(reader);
1331  }
1332 
1333  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1334  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1335 
1336  IWICMetadataBlockReader_Release(blockreader);
1337  }
1338 
1339  IWICBitmapFrameDecode_Release(frame);
1340  IWICBitmapDecoder_Release(decoder);
1341 
1342  /* 1x1 pixel gif, 2 frames */
1344 
1345  hr = CoCreateInstance(&CLSID_WICGifDecoder, NULL, CLSCTX_INPROC_SERVER,
1346  &IID_IWICBitmapDecoder, (void **)&decoder);
1347  ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
1348  hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
1349  ok(hr == S_OK, "Initialize error %#x\n", hr);
1350 
1351  IStream_Release(stream);
1352 
1353  /* global metadata block */
1354  hr = IWICBitmapDecoder_QueryInterface(decoder, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1355  ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1356 
1357  if (SUCCEEDED(hr))
1358  {
1359  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1360  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1361  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1362  "wrong container format %s\n", wine_dbgstr_guid(&format));
1363 
1364  hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1365  ok(hr == S_OK, "GetCount error %#x\n", hr);
1366  ok(count == 4, "expected 4, got %u\n", count);
1367 
1368  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1369  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1370 
1371  if (SUCCEEDED(hr))
1372  {
1373  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1374  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1375  ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), /* Logical Screen Descriptor */
1376  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1377 
1378  hr = IWICMetadataReader_GetCount(reader, &count);
1379  ok(hr == S_OK, "GetCount error %#x\n", hr);
1380  ok(count == ARRAY_SIZE(animated_gif_LSD), "unexpected count %u\n", count);
1381 
1382  compare_metadata(reader, animated_gif_LSD, count);
1383 
1384  IWICMetadataReader_Release(reader);
1385  }
1386 
1387  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1388  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1389 
1390  if (SUCCEEDED(hr))
1391  {
1392  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1393  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1394  ok(IsEqualGUID(&format, &GUID_MetadataFormatAPE), /* Application Extension */
1395  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1396 
1397  hr = IWICMetadataReader_GetCount(reader, &count);
1398  ok(hr == S_OK, "GetCount error %#x\n", hr);
1399  ok(count == ARRAY_SIZE(animated_gif_APE), "unexpected count %u\n", count);
1400 
1401  compare_metadata(reader, animated_gif_APE, count);
1402 
1403  IWICMetadataReader_Release(reader);
1404  }
1405 
1406  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 2, &reader);
1407  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1408 
1409  if (SUCCEEDED(hr))
1410  {
1411  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1412  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1413  ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), /* Comment Extension */
1414  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1415 
1416  hr = IWICMetadataReader_GetCount(reader, &count);
1417  ok(hr == S_OK, "GetCount error %#x\n", hr);
1418  ok(count == ARRAY_SIZE(animated_gif_comment_1), "unexpected count %u\n", count);
1419 
1420  compare_metadata(reader, animated_gif_comment_1, count);
1421 
1422  IWICMetadataReader_Release(reader);
1423  }
1424 
1425  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 3, &reader);
1426  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1427 
1428  if (SUCCEEDED(hr))
1429  {
1430  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1431  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1432  ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown),
1433  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1434 
1435  hr = IWICMetadataReader_GetCount(reader, &count);
1436  ok(hr == S_OK, "GetCount error %#x\n", hr);
1437  ok(count == ARRAY_SIZE(animated_gif_plain_1), "unexpected count %u\n", count);
1438 
1439  compare_metadata(reader, animated_gif_plain_1, count);
1440 
1441  IWICMetadataReader_Release(reader);
1442  }
1443 
1444  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 4, &reader);
1445  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1446 
1447  IWICMetadataBlockReader_Release(blockreader);
1448  }
1449 
1450  /* frame metadata block */
1451  hr = IWICBitmapDecoder_GetFrame(decoder, 1, &frame);
1452  ok(hr == S_OK, "GetFrame error %#x\n", hr);
1453 
1454  hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader);
1455  ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr);
1456 
1457  if (SUCCEEDED(hr))
1458  {
1459  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, NULL);
1460  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1461 
1462  hr = IWICMetadataBlockReader_GetContainerFormat(blockreader, &format);
1463  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1464  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1465  "wrong container format %s\n", wine_dbgstr_guid(&format));
1466 
1467  hr = IWICMetadataBlockReader_GetCount(blockreader, NULL);
1468  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1469 
1470  hr = IWICMetadataBlockReader_GetCount(blockreader, &count);
1471  ok(hr == S_OK, "GetCount error %#x\n", hr);
1472  ok(count == 4, "expected 4, got %u\n", count);
1473 
1474  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader);
1475  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1476 
1477  if (SUCCEEDED(hr))
1478  {
1479  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1480  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1481  ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), /* Image Descriptor */
1482  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1483 
1484  hr = IWICMetadataReader_GetCount(reader, &count);
1485  ok(hr == S_OK, "GetCount error %#x\n", hr);
1486  ok(count == ARRAY_SIZE(animated_gif_IMD), "unexpected count %u\n", count);
1487 
1488  compare_metadata(reader, animated_gif_IMD, count);
1489 
1490  IWICMetadataReader_Release(reader);
1491  }
1492 
1493  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader);
1494  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1495 
1496  if (SUCCEEDED(hr))
1497  {
1498  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1499  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1500  ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), /* Comment Extension */
1501  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1502 
1503  hr = IWICMetadataReader_GetCount(reader, &count);
1504  ok(hr == S_OK, "GetCount error %#x\n", hr);
1505  ok(count == ARRAY_SIZE(animated_gif_comment_2), "unexpected count %u\n", count);
1506 
1507  if (count == 1)
1508  compare_metadata(reader, animated_gif_comment_2, count);
1509 
1510  IWICMetadataReader_Release(reader);
1511  }
1512 
1513  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 2, &reader);
1514  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1515 
1516  if (SUCCEEDED(hr))
1517  {
1518  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1519  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1520  ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown),
1521  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1522 
1523  hr = IWICMetadataReader_GetCount(reader, &count);
1524  ok(hr == S_OK, "GetCount error %#x\n", hr);
1525  ok(count == ARRAY_SIZE(animated_gif_plain_2), "unexpected count %u\n", count);
1526 
1527  compare_metadata(reader, animated_gif_plain_2, count);
1528 
1529  IWICMetadataReader_Release(reader);
1530  }
1531 
1532  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 3, &reader);
1533  ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr);
1534 
1535  if (SUCCEEDED(hr))
1536  {
1537  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1538  ok(hr == S_OK, "GetMetadataFormat failed, hr=%#x\n", hr);
1539  ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), /* Graphic Control Extension */
1540  "wrong metadata format %s\n", wine_dbgstr_guid(&format));
1541 
1542  hr = IWICMetadataReader_GetCount(reader, &count);
1543  ok(hr == S_OK, "GetCount error %#x\n", hr);
1544  ok(count == ARRAY_SIZE(animated_gif_GCE), "unexpected count %u\n", count);
1545 
1546  compare_metadata(reader, animated_gif_GCE, count);
1547 
1548  IWICMetadataReader_Release(reader);
1549  }
1550 
1551  hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 4, &reader);
1552  ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got %#x\n", hr);
1553 
1554  IWICMetadataBlockReader_Release(blockreader);
1555  }
1556 
1557  hr = IWICBitmapDecoder_GetMetadataQueryReader(decoder, &queryreader);
1558  ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
1559  "GetMetadataQueryReader error %#x\n", hr);
1560  if (SUCCEEDED(hr))
1561  {
1562  static const struct
1563  {
1564  const char *query;
1565  HRESULT hr;
1566  UINT vt;
1567  } decoder_data[] =
1568  {
1569  { "/logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
1570  { "/[0]logscrdesc/Signature", S_OK, VT_UI1 | VT_VECTOR },
1571  { "/logscrdesc/\\Signature", S_OK, VT_UI1 | VT_VECTOR },
1572  { "/Logscrdesc/\\signature", S_OK, VT_UI1 | VT_VECTOR },
1573  { "/logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
1574  { "/[0]logscrdesc/{str=signature}", S_OK, VT_UI1 | VT_VECTOR },
1575  { "/logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
1576  { "/[0]logscrdesc/{wstr=signature}", S_OK, VT_UI1 | VT_VECTOR },
1577  { "/appext/Application", S_OK, VT_UI1 | VT_VECTOR },
1578  { "/appext/{STR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
1579  { "/appext/{WSTR=APPlication}", S_OK, VT_UI1 | VT_VECTOR },
1580  { "/LogSCRdesC", S_OK, VT_UNKNOWN },
1581  { "/[0]LogSCRdesC", S_OK, VT_UNKNOWN },
1582  { "/appEXT", S_OK, VT_UNKNOWN },
1583  { "/[0]appEXT", S_OK, VT_UNKNOWN },
1584  { "grctlext", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
1585  { "/imgdesc", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1586  };
1587  static const WCHAR rootW[] = {'/',0};
1588  WCHAR name[256];
1589  UINT len, i, j;
1590  PROPVARIANT value;
1591  IWICMetadataQueryReader *meta_reader;
1592 
1593  hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
1594  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1595  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1596  "wrong container format %s\n", wine_dbgstr_guid(&format));
1597 
1598  name[0] = 0;
1599  len = 0xdeadbeef;
1600  hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
1601  ok(hr == S_OK, "GetLocation error %#x\n", hr);
1602  ok(len == 2, "expected 2, got %u\n", len);
1603  ok(!lstrcmpW(name, rootW), "expected '/', got %s\n", wine_dbgstr_w(name));
1604 
1605  for (i = 0; i < ARRAY_SIZE(decoder_data); i++)
1606  {
1607  WCHAR queryW[256];
1608 
1609  if (winetest_debug > 1)
1610  trace("query: %s\n", decoder_data[i].query);
1611  MultiByteToWideChar(CP_ACP, 0, decoder_data[i].query, -1, queryW, 256);
1612 
1613  hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, NULL);
1614  ok(hr == decoder_data[i].hr, "GetMetadataByName(%s) returned %#x, expected %#x\n", wine_dbgstr_w(queryW), hr, decoder_data[i].hr);
1615 
1616  PropVariantInit(&value);
1617  hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1618  ok(hr == decoder_data[i].hr, "GetMetadataByName(%s) returned %#x, expected %#x\n", wine_dbgstr_w(queryW), hr, decoder_data[i].hr);
1619  ok(value.vt == decoder_data[i].vt, "expected %#x, got %#x\n", decoder_data[i].vt, value.vt);
1620  if (hr == S_OK && value.vt == VT_UNKNOWN)
1621  {
1622  hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&meta_reader);
1623  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1624 
1625  name[0] = 0;
1626  len = 0xdeadbeef;
1627  hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name, &len);
1628  ok(hr == S_OK, "GetLocation error %#x\n", hr);
1629  ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
1630  ok(!lstrcmpW(name, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(name));
1631 
1632  for (j = 0; j < ARRAY_SIZE(decoder_data); j++)
1633  {
1634  MultiByteToWideChar(CP_ACP, 0, decoder_data[j].query, -1, queryW, 256);
1635 
1636  if (CompareStringW(LOCALE_NEUTRAL, NORM_IGNORECASE, queryW, len-1, name, len-1) == CSTR_EQUAL && decoder_data[j].query[len - 1] != 0)
1637  {
1638  if (winetest_debug > 1)
1639  trace("query: %s\n", wine_dbgstr_w(queryW + len - 1));
1641  hr = IWICMetadataQueryReader_GetMetadataByName(meta_reader, queryW + len - 1, &value);
1642  ok(hr == decoder_data[j].hr, "GetMetadataByName(%s) returned %#x, expected %#x\n", wine_dbgstr_w(queryW + len - 1), hr, decoder_data[j].hr);
1643  ok(value.vt == decoder_data[j].vt, "expected %#x, got %#x\n", decoder_data[j].vt, value.vt);
1644  }
1645  }
1646 
1647  IWICMetadataQueryReader_Release(meta_reader);
1648  }
1649 
1651  }
1652 
1653  IWICMetadataQueryReader_Release(queryreader);
1654  }
1655 
1656  hr = IWICBitmapFrameDecode_GetMetadataQueryReader(frame, &queryreader);
1657  ok(hr == S_OK || broken(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) /* before Vista */,
1658  "GetMetadataQueryReader error %#x\n", hr);
1659  if (SUCCEEDED(hr))
1660  {
1661  static const struct
1662  {
1663  const char *query;
1664  HRESULT hr;
1665  UINT vt;
1666  } frame_data[] =
1667  {
1668  { "/grctlext/Delay", S_OK, VT_UI2 },
1669  { "/[0]grctlext/Delay", S_OK, VT_UI2 },
1670  { "/grctlext/{str=delay}", S_OK, VT_UI2 },
1671  { "/[0]grctlext/{str=delay}", S_OK, VT_UI2 },
1672  { "/grctlext/{wstr=delay}", S_OK, VT_UI2 },
1673  { "/[0]grctlext/{wstr=delay}", S_OK, VT_UI2 },
1674  { "/imgdesc/InterlaceFlag", S_OK, VT_BOOL },
1675  { "/imgdesc/{STR=interlaceFLAG}", S_OK, VT_BOOL },
1676  { "/imgdesc/{WSTR=interlaceFLAG}", S_OK, VT_BOOL },
1677  { "/grctlext", S_OK, VT_UNKNOWN },
1678  { "/[0]grctlext", S_OK, VT_UNKNOWN },
1679  { "/imgdesc", S_OK, VT_UNKNOWN },
1680  { "/[0]imgdesc", S_OK, VT_UNKNOWN },
1681  { "/LogSCRdesC", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1682  { "/appEXT", WINCODEC_ERR_PROPERTYNOTFOUND, 0 },
1683  { "/grctlext/{\\str=delay}", WINCODEC_ERR_WRONGSTATE, 0 },
1684  { "/grctlext/{str=\\delay}", S_OK, VT_UI2 },
1685  { "grctlext/Delay", WINCODEC_ERR_PROPERTYNOTSUPPORTED, 0 },
1686  };
1687  static const WCHAR rootW[] = {'/',0};
1688  static const WCHAR guidW[] = {'/','{','g','u','i','d','=','\\',0};
1689  static const WCHAR imgdescW[] = {'i','m','g','d','e','s','c',0};
1690  static const WCHAR ImgDescW[] = {'I','m','g','D','e','s','c',0};
1691  WCHAR name[256], queryW[256];
1692  UINT len, i;
1693  PROPVARIANT value;
1694  IWICMetadataQueryReader *meta_reader;
1695 
1696  hr = IWICMetadataQueryReader_GetContainerFormat(queryreader, &format);
1697  ok(hr == S_OK, "GetContainerFormat error %#x\n", hr);
1698  ok(IsEqualGUID(&format, &GUID_ContainerFormatGif),
1699  "wrong container format %s\n", wine_dbgstr_guid(&format));
1700 
1701  name[0] = 0;
1702  len = 0xdeadbeef;
1703  hr = IWICMetadataQueryReader_GetLocation(queryreader, 256, name, &len);
1704  ok(hr == S_OK, "GetLocation error %#x\n", hr);
1705  ok(len == 2, "expected 2, got %u\n", len);
1706  ok(!lstrcmpW(name, rootW), "expected '/', got %s\n", wine_dbgstr_w(name));
1707 
1708  for (i = 0; i < ARRAY_SIZE(frame_data); i++)
1709  {
1710  if (winetest_debug > 1)
1711  trace("query: %s\n", frame_data[i].query);
1712  MultiByteToWideChar(CP_ACP, 0, frame_data[i].query, -1, queryW, 256);
1713  PropVariantInit(&value);
1714  hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1715  ok(hr == frame_data[i].hr, "GetMetadataByName(%s) returned %#x, expected %#x\n", wine_dbgstr_w(queryW), hr, frame_data[i].hr);
1716  ok(value.vt == frame_data[i].vt, "expected %#x, got %#x\n", frame_data[i].vt, value.vt);
1717  if (hr == S_OK && value.vt == VT_UNKNOWN)
1718  {
1719  hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&meta_reader);
1720  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1721 
1722  name[0] = 0;
1723  len = 0xdeadbeef;
1724  hr = IWICMetadataQueryReader_GetLocation(meta_reader, 256, name, &len);
1725  ok(hr == S_OK, "GetLocation error %#x\n", hr);
1726  ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
1727  ok(!lstrcmpW(name, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(name));
1728 
1729  IWICMetadataQueryReader_Release(meta_reader);
1730  }
1731 
1733  }
1734 
1735  name[0] = 0;
1736  len = 0xdeadbeef;
1737  hr = WICMapGuidToShortName(&GUID_MetadataFormatIMD, 256, name, &len);
1738  ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
1739  ok(!lstrcmpW(name, imgdescW), "wrong short name %s\n", wine_dbgstr_w(name));
1740 
1741  format = GUID_NULL;
1743  ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
1744  ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid %s\n", wine_dbgstr_guid(&format));
1745 
1746  format = GUID_NULL;
1747  hr = WICMapShortNameToGuid(ImgDescW, &format);
1748  ok(hr == S_OK, "WICMapGuidToShortName error %#x\n", hr);
1749  ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong guid %s\n", wine_dbgstr_guid(&format));
1750 
1751  lstrcpyW(queryW, guidW);
1752  StringFromGUID2(&GUID_MetadataFormatIMD, queryW + lstrlenW(queryW) - 1, 39);
1753  memcpy(queryW, guidW, sizeof(guidW) - 2);
1754  if (winetest_debug > 1)
1755  trace("query: %s\n", wine_dbgstr_w(queryW));
1756  PropVariantInit(&value);
1757  hr = IWICMetadataQueryReader_GetMetadataByName(queryreader, queryW, &value);
1758  ok(hr == S_OK, "GetMetadataByName(%s) error %#x\n", wine_dbgstr_w(queryW), hr);
1759  ok(value.vt == VT_UNKNOWN, "expected VT_UNKNOWN, got %#x\n", value.vt);
1761 
1762  IWICMetadataQueryReader_Release(queryreader);
1763  }
1764 
1765  IWICBitmapFrameDecode_Release(frame);
1766  IWICBitmapDecoder_Release(decoder);
1767 }
1768 
1769 static void test_metadata_LSD(void)
1770 {
1771  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};
1772  static const char LSD_data[] = "hello world!\x1\x2\x3\x4\xab\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf";
1773  static const struct test_data td[9] =
1774  {
1775  { VT_UI1|VT_VECTOR, 0, 6, {'w','o','r','l','d','!'}, NULL, { 'S','i','g','n','a','t','u','r','e',0 } },
1776  { VT_UI2, 0, 0, { 0x201 }, NULL, { 'W','i','d','t','h',0 } },
1777  { VT_UI2, 0, 0, { 0x403 }, NULL, { 'H','e','i','g','h','t',0 } },
1778  { 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 } },
1779  { VT_UI1, 0, 0, { 2 }, NULL, { 'C','o','l','o','r','R','e','s','o','l','u','t','i','o','n',0 } },
1780  { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1781  { 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 } },
1782  { 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 } },
1783  { VT_UI1, 0, 0, { 7 }, NULL, { 'P','i','x','e','l','A','s','p','e','c','t','R','a','t','i','o',0 } }
1784  };
1786  HRESULT hr;
1787  IStream *stream;
1788  IWICPersistStream *persist;
1791  WCHAR name[64];
1792  UINT count, dummy;
1793  GUID format;
1794  CLSID id;
1795 
1796  hr = CoCreateInstance(&CLSID_WICLSDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1797  &IID_IWICMetadataReader, (void **)&reader);
1798  ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1799  "CoCreateInstance error %#x\n", hr);
1800 
1801  stream = create_stream(LSD_data, sizeof(LSD_data));
1802 
1803  if (SUCCEEDED(hr))
1804  {
1805  pos.QuadPart = 6;
1806  hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1807  ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1808 
1809  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1810  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1811 
1812  hr = IWICPersistStream_Load(persist, stream);
1813  ok(hr == S_OK, "Load error %#x\n", hr);
1814 
1815  IWICPersistStream_Release(persist);
1816  }
1817 
1818  if (SUCCEEDED(hr))
1819  {
1820  hr = IWICMetadataReader_GetCount(reader, &count);
1821  ok(hr == S_OK, "GetCount error %#x\n", hr);
1822  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
1823 
1825 
1826  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1827  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1828  ok(IsEqualGUID(&format, &GUID_MetadataFormatLSD), "wrong format %s\n", wine_dbgstr_guid(&format));
1829 
1830  hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1831  ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1832 
1833  hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1834  ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1835  ok(IsEqualGUID(&id, &CLSID_WICLSDMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
1836 
1837  hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1838  ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1839  ok(lstrcmpW(name, LSD_name) == 0, "wrong LSD reader name %s\n", wine_dbgstr_w(name));
1840 
1841  IWICMetadataHandlerInfo_Release(info);
1842  IWICMetadataReader_Release(reader);
1843  }
1844 
1845  IStream_Release(stream);
1846 }
1847 
1848 static void test_metadata_IMD(void)
1849 {
1850  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};
1851  static const char IMD_data[] = "hello world!\x1\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
1852  static const struct test_data td[8] =
1853  {
1854  { VT_UI2, 0, 0, { 0x201 }, NULL, { 'L','e','f','t',0 } },
1855  { VT_UI2, 0, 0, { 0x403 }, NULL, { 'T','o','p',0 } },
1856  { VT_UI2, 0, 0, { 0x605 }, NULL, { 'W','i','d','t','h',0 } },
1857  { VT_UI2, 0, 0, { 0x807 }, NULL, { 'H','e','i','g','h','t',0 } },
1858  { 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 } },
1859  { VT_BOOL, 0, 0, { 1 }, NULL, { 'I','n','t','e','r','l','a','c','e','F','l','a','g',0 } },
1860  { VT_BOOL, 0, 0, { 1 }, NULL, { 'S','o','r','t','F','l','a','g',0 } },
1861  { 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 } }
1862  };
1864  HRESULT hr;
1865  IStream *stream;
1866  IWICPersistStream *persist;
1869  WCHAR name[64];
1870  UINT count, dummy;
1871  GUID format;
1872  CLSID id;
1873 
1874  hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1875  &IID_IWICMetadataReader, (void **)&reader);
1876  ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1877  "CoCreateInstance error %#x\n", hr);
1878 
1879  stream = create_stream(IMD_data, sizeof(IMD_data));
1880 
1881  if (SUCCEEDED(hr))
1882  {
1883  pos.QuadPart = 12;
1884  hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1885  ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1886 
1887  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1888  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1889 
1890  hr = IWICPersistStream_Load(persist, stream);
1891  ok(hr == S_OK, "Load error %#x\n", hr);
1892 
1893  IWICPersistStream_Release(persist);
1894  }
1895 
1896  if (SUCCEEDED(hr))
1897  {
1898  hr = IWICMetadataReader_GetCount(reader, &count);
1899  ok(hr == S_OK, "GetCount error %#x\n", hr);
1900  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
1901 
1903 
1904  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1905  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1906  ok(IsEqualGUID(&format, &GUID_MetadataFormatIMD), "wrong format %s\n", wine_dbgstr_guid(&format));
1907 
1908  hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1909  ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1910 
1911  hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1912  ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1913  ok(IsEqualGUID(&id, &CLSID_WICIMDMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
1914 
1915  hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1916  ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1917  ok(lstrcmpW(name, IMD_name) == 0, "wrong IMD reader name %s\n", wine_dbgstr_w(name));
1918 
1919  IWICMetadataHandlerInfo_Release(info);
1920  IWICMetadataReader_Release(reader);
1921  }
1922 
1923  IStream_Release(stream);
1924 }
1925 
1926 static void test_metadata_GCE(void)
1927 {
1928  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};
1929  static const char GCE_data[] = "hello world!\xa\x2\x3\x4\x5\x6\x7\x8\xed\xa\xb\xc\xd\xe\xf";
1930  static const struct test_data td[5] =
1931  {
1932  { VT_UI1, 0, 0, { 2 }, NULL, { 'D','i','s','p','o','s','a','l',0 } },
1933  { VT_BOOL, 0, 0, { 1 }, NULL, { 'U','s','e','r','I','n','p','u','t','F','l','a','g',0 } },
1934  { VT_BOOL, 0, 0, { 0 }, NULL, { 'T','r','a','n','s','p','a','r','e','n','c','y','F','l','a','g',0 } },
1935  { VT_UI2, 0, 0, { 0x302 }, NULL, { 'D','e','l','a','y',0 } },
1936  { 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 } }
1937  };
1939  HRESULT hr;
1940  IStream *stream;
1941  IWICPersistStream *persist;
1944  WCHAR name[64];
1945  UINT count, dummy;
1946  GUID format;
1947  CLSID id;
1948 
1949  hr = CoCreateInstance(&CLSID_WICGCEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
1950  &IID_IWICMetadataReader, (void **)&reader);
1951  ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
1952  "CoCreateInstance error %#x\n", hr);
1953 
1954  stream = create_stream(GCE_data, sizeof(GCE_data));
1955 
1956  if (SUCCEEDED(hr))
1957  {
1958  pos.QuadPart = 12;
1959  hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
1960  ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
1961 
1962  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
1963  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
1964 
1965  hr = IWICPersistStream_Load(persist, stream);
1966  ok(hr == S_OK, "Load error %#x\n", hr);
1967 
1968  IWICPersistStream_Release(persist);
1969  }
1970 
1971  if (SUCCEEDED(hr))
1972  {
1973  hr = IWICMetadataReader_GetCount(reader, &count);
1974  ok(hr == S_OK, "GetCount error %#x\n", hr);
1975  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
1976 
1978 
1979  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
1980  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
1981  ok(IsEqualGUID(&format, &GUID_MetadataFormatGCE), "wrong format %s\n", wine_dbgstr_guid(&format));
1982 
1983  hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
1984  ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
1985 
1986  hr = IWICMetadataHandlerInfo_GetCLSID(info, &id);
1987  ok(hr == S_OK, "GetCLSID error %#x\n", hr);
1988  ok(IsEqualGUID(&id, &CLSID_WICGCEMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&id));
1989 
1990  hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
1991  ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
1992  ok(lstrcmpW(name, GCE_name) == 0, "wrong GCE reader name %s\n", wine_dbgstr_w(name));
1993 
1994  IWICMetadataHandlerInfo_Release(info);
1995  IWICMetadataReader_Release(reader);
1996  }
1997 
1998  IStream_Release(stream);
1999 }
2000 
2001 static void test_metadata_APE(void)
2002 {
2003  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};
2004  static const char APE_data[] = { 0x21,0xff,0x0b,'H','e','l','l','o',' ','W','o','r','l','d',
2005  /*sub-block*/1,0x11,
2006  /*sub-block*/2,0x22,0x33,
2007  /*sub-block*/4,0x44,0x55,0x66,0x77,
2008  /*terminator*/0 };
2009  static const struct test_data td[2] =
2010  {
2011  { 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 } },
2012  { VT_UI1|VT_VECTOR, 0, 10, { 1,0x11,2,0x22,0x33,4,0x44,0x55,0x66,0x77 }, NULL, { 'D','a','t','a',0 } }
2013  };
2014  WCHAR dataW[] = { 'd','a','t','a',0 };
2015  HRESULT hr;
2016  IStream *stream;
2017  IWICPersistStream *persist;
2020  WCHAR name[64];
2021  UINT count, dummy, i;
2022  GUID format;
2023  CLSID clsid;
2024  PROPVARIANT id, value;
2025 
2026  hr = CoCreateInstance(&CLSID_WICAPEMetadataReader, NULL, CLSCTX_INPROC_SERVER,
2027  &IID_IWICMetadataReader, (void **)&reader);
2028  ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
2029  "CoCreateInstance error %#x\n", hr);
2030 
2031  stream = create_stream(APE_data, sizeof(APE_data));
2032 
2033  if (SUCCEEDED(hr))
2034  {
2035  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2036  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
2037 
2038  hr = IWICPersistStream_Load(persist, stream);
2039  ok(hr == S_OK, "Load error %#x\n", hr);
2040 
2041  IWICPersistStream_Release(persist);
2042  }
2043 
2044  if (SUCCEEDED(hr))
2045  {
2046  hr = IWICMetadataReader_GetCount(reader, &count);
2047  ok(hr == S_OK, "GetCount error %#x\n", hr);
2048  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2049 
2051 
2052  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2053  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
2054  ok(IsEqualGUID(&format, &GUID_MetadataFormatAPE), "wrong format %s\n", wine_dbgstr_guid(&format));
2055 
2056  PropVariantInit(&value);
2057  id.vt = VT_LPWSTR;
2058  U(id).pwszVal = dataW;
2059 
2060  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2061  ok(hr == S_OK, "GetValue error %#x\n", hr);
2062  ok(value.vt == (VT_UI1|VT_VECTOR), "unexpected vt: %i\n", id.vt);
2063  ok(td[1].count == U(value).caub.cElems, "expected cElems %d, got %d\n", td[1].count, U(value).caub.cElems);
2064  for (i = 0; i < U(value).caub.cElems; i++)
2065  ok(td[1].value[i] == U(value).caub.pElems[i], "%u: expected value %#x/%#x, got %#x\n", i, (ULONG)td[1].value[i], (ULONG)(td[1].value[i] >> 32), U(value).caub.pElems[i]);
2067 
2068  hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2069  ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
2070 
2071  hr = IWICMetadataHandlerInfo_GetCLSID(info, &clsid);
2072  ok(hr == S_OK, "GetCLSID error %#x\n", hr);
2073  ok(IsEqualGUID(&clsid, &CLSID_WICAPEMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&clsid));
2074 
2075  hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2076  ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
2077  ok(lstrcmpW(name, APE_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
2078 
2079  IWICMetadataHandlerInfo_Release(info);
2080  IWICMetadataReader_Release(reader);
2081  }
2082 
2083  IStream_Release(stream);
2084 }
2085 
2086 static void test_metadata_GIF_comment(void)
2087 {
2088  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};
2089  static const char GIF_comment_data[] = { 0x21,0xfe,
2090  /*sub-block*/5,'H','e','l','l','o',
2091  /*sub-block*/1,' ',
2092  /*sub-block*/6,'W','o','r','l','d','!',
2093  /*terminator*/0 };
2094  static const struct test_data td[1] =
2095  {
2096  { VT_LPSTR, 0, 12, { 0 }, "Hello World!", { 'T','e','x','t','E','n','t','r','y',0 } }
2097  };
2098  WCHAR text_entryW[] = { 'T','E','X','T','E','N','T','R','Y',0 };
2099  HRESULT hr;
2100  IStream *stream;
2101  IWICPersistStream *persist;
2104  WCHAR name[64];
2105  UINT count, dummy;
2106  GUID format;
2107  CLSID clsid;
2108  PROPVARIANT id, value;
2109 
2110  hr = CoCreateInstance(&CLSID_WICGifCommentMetadataReader, NULL, CLSCTX_INPROC_SERVER,
2111  &IID_IWICMetadataReader, (void **)&reader);
2112  ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */,
2113  "CoCreateInstance error %#x\n", hr);
2114 
2115  stream = create_stream(GIF_comment_data, sizeof(GIF_comment_data));
2116 
2117  if (SUCCEEDED(hr))
2118  {
2119  hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void **)&persist);
2120  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
2121 
2122  hr = IWICPersistStream_Load(persist, stream);
2123  ok(hr == S_OK, "Load error %#x\n", hr);
2124 
2125  IWICPersistStream_Release(persist);
2126  }
2127 
2128  if (SUCCEEDED(hr))
2129  {
2130  hr = IWICMetadataReader_GetCount(reader, &count);
2131  ok(hr == S_OK, "GetCount error %#x\n", hr);
2132  ok(count == ARRAY_SIZE(td), "unexpected count %u\n", count);
2133 
2135 
2136  hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
2137  ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
2138  ok(IsEqualGUID(&format, &GUID_MetadataFormatGifComment), "wrong format %s\n", wine_dbgstr_guid(&format));
2139 
2140  PropVariantInit(&value);
2141  id.vt = VT_LPWSTR;
2142  U(id).pwszVal = text_entryW;
2143 
2144  hr = IWICMetadataReader_GetValue(reader, NULL, &id, &value);
2145  ok(hr == S_OK, "GetValue error %#x\n", hr);
2146  ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
2147  ok(!strcmp(U(value).pszVal, "Hello World!"), "unexpected value: %s\n", U(value).pszVal);
2149 
2150  hr = IWICMetadataReader_GetMetadataHandlerInfo(reader, &info);
2151  ok(hr == S_OK, "GetMetadataHandlerInfo error %#x\n", hr);
2152 
2153  hr = IWICMetadataHandlerInfo_GetCLSID(info, &clsid);
2154  ok(hr == S_OK, "GetCLSID error %#x\n", hr);
2155  ok(IsEqualGUID(&clsid, &CLSID_WICGifCommentMetadataReader), "wrong CLSID %s\n", wine_dbgstr_guid(&clsid));
2156 
2157  hr = IWICMetadataHandlerInfo_GetFriendlyName(info, 64, name, &dummy);
2158  ok(hr == S_OK, "GetFriendlyName error %#x\n", hr);
2159  ok(lstrcmpW(name, GIF_comment_name) == 0, "wrong APE reader name %s\n", wine_dbgstr_w(name));
2160 
2161  IWICMetadataHandlerInfo_Release(info);
2162  IWICMetadataReader_Release(reader);
2163  }
2164 
2165  IStream_Release(stream);
2166 }
2167 
2169 {
2170  static const WCHAR unkW[] = { 'u','n','k',0 };
2171  static const WCHAR unknownW[] = { 'u','n','k','n','o','w','n',0 };
2172  HRESULT hr;
2173  UINT len;
2174  WCHAR name[16];
2175 
2176  name[0] = 0;
2177  len = 0xdeadbeef;
2178  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, name, &len);
2179  ok(hr == S_OK, "got %#x\n", hr);
2180  ok(len == 8, "got %u\n", len);
2181  ok(!lstrcmpW(name, unknownW), "got %s\n", wine_dbgstr_w(name));
2182 
2183  name[0] = 0;
2184  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, name, NULL);
2185  ok(hr == S_OK, "got %#x\n", hr);
2186  ok(!lstrcmpW(name, unknownW), "got %s\n", wine_dbgstr_w(name));
2187 
2188  len = 0xdeadbeef;
2189  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, NULL, &len);
2190  ok(hr == S_OK, "got %#x\n", hr);
2191  ok(len == 8, "got %u\n", len);
2192 
2193  len = 0xdeadbeef;
2194  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, NULL, &len);
2195  ok(hr == S_OK, "got %#x\n", hr);
2196  ok(len == 8, "got %u\n", len);
2197 
2198  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, NULL, NULL);
2199  ok(hr == S_OK, "got %#x\n", hr);
2200 
2201  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 8, NULL, NULL);
2202  ok(hr == S_OK, "got %#x\n", hr);
2203 
2205  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#x\n", hr);
2206 
2207  name[0] = 0;
2208  len = 0xdeadbeef;
2209  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 4, name, &len);
2211  ok(len == 0xdeadbeef, "got %u\n", len);
2212  ok(!lstrcmpW(name, unkW), "got %s\n", wine_dbgstr_w(name));
2213 
2214  name[0] = 0;
2215  len = 0xdeadbeef;
2216  hr = WICMapGuidToShortName(&GUID_MetadataFormatUnknown, 0, name, &len);
2217  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2218  ok(len == 0xdeadbeef, "got %u\n", len);
2219  ok(!name[0], "got %s\n", wine_dbgstr_w(name));
2220 
2222  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2223 }
2224 
2226 {
2227  static const WCHAR unkW[] = { 'u','n','k',0 };
2228  static const WCHAR xmpW[] = { 'x','m','p',0 };
2229  static const WCHAR XmPW[] = { 'X','m','P',0 };
2230  static const WCHAR unknownW[] = { 'u','n','k','n','o','w','n',0 };
2231  HRESULT hr;
2232  GUID guid;
2233 
2235  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2236 
2238  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2239 
2241  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2242 
2243  hr = WICMapShortNameToGuid(unkW, &guid);
2244  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#x\n", hr);
2245 
2247  ok(hr == S_OK, "got %#x\n", hr);
2248  ok(IsEqualGUID(&guid, &GUID_MetadataFormatUnknown), "got %s\n", wine_dbgstr_guid(&guid));
2249 
2251  ok(hr == S_OK, "got %#x\n", hr);
2252  ok(IsEqualGUID(&guid, &GUID_MetadataFormatXMP), "got %s\n", wine_dbgstr_guid(&guid));
2253 
2254  guid = GUID_NULL;
2255  hr = WICMapShortNameToGuid(XmPW, &guid);
2256  ok(hr == S_OK, "got %#x\n", hr);
2257  ok(IsEqualGUID(&guid, &GUID_MetadataFormatXMP), "got %s\n", wine_dbgstr_guid(&guid));
2258 }
2259 
2260 static const GUID *guid_list[] =
2261 {
2262  &GUID_ContainerFormatBmp,
2263  &GUID_ContainerFormatPng,
2264  &GUID_ContainerFormatIco,
2265  &GUID_ContainerFormatJpeg,
2266  &GUID_ContainerFormatTiff,
2267  &GUID_ContainerFormatGif,
2268  &GUID_ContainerFormatWmp,
2269  &GUID_MetadataFormatUnknown,
2270  &GUID_MetadataFormatIfd,
2271  &GUID_MetadataFormatSubIfd,
2272  &GUID_MetadataFormatExif,
2273  &GUID_MetadataFormatGps,
2274  &GUID_MetadataFormatInterop,
2275  &GUID_MetadataFormatApp0,
2276  &GUID_MetadataFormatApp1,
2277  &GUID_MetadataFormatApp13,
2278  &GUID_MetadataFormatIPTC,
2279  &GUID_MetadataFormatIRB,
2280  &GUID_MetadataFormat8BIMIPTC,
2281  &GUID_MetadataFormat8BIMResolutionInfo,
2282  &GUID_MetadataFormat8BIMIPTCDigest,
2283  &GUID_MetadataFormatXMP,
2284  &GUID_MetadataFormatThumbnail,
2285  &GUID_MetadataFormatChunktEXt,
2286  &GUID_MetadataFormatXMPStruct,
2287  &GUID_MetadataFormatXMPBag,
2288  &GUID_MetadataFormatXMPSeq,
2289  &GUID_MetadataFormatXMPAlt,
2290  &GUID_MetadataFormatLSD,
2291  &GUID_MetadataFormatIMD,
2292  &GUID_MetadataFormatGCE,
2293  &GUID_MetadataFormatAPE,
2294  &GUID_MetadataFormatJpegChrominance,
2295  &GUID_MetadataFormatJpegLuminance,
2296  &GUID_MetadataFormatJpegComment,
2297  &GUID_MetadataFormatGifComment,
2298  &GUID_MetadataFormatChunkgAMA,
2299  &GUID_MetadataFormatChunkbKGD,
2300  &GUID_MetadataFormatChunkiTXt,
2301  &GUID_MetadataFormatChunkcHRM,
2302  &GUID_MetadataFormatChunkhIST,
2303  &GUID_MetadataFormatChunkiCCP,
2304  &GUID_MetadataFormatChunksRGB,
2305  &GUID_MetadataFormatChunktIME
2306 };
2307 
2308 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 };
2309 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 };
2310 static WCHAR xmp_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2311 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 };
2312 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 };
2313 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 };
2314 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 };
2315 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 };
2316 static WCHAR pdf_scheme[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','p','d','f','/','1','.','3','/',0 };
2317 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 };
2318 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 };
2319 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 };
2320 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 };
2321 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 };
2322 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 };
2323 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 };
2324 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 };
2325 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 };
2326 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 };
2327 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 };
2328 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 };
2329 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 };
2330 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 };
2331 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 };
2332 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 };
2333 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 };
2334 
2335 static WCHAR *schema_list[] =
2336 {
2337  aux_scheme,
2338  rdf_scheme,
2339  dc_scheme,
2340  xmp_scheme,
2341  xmpidq_scheme,
2343  xmpMM_scheme,
2344  xmpBJ_scheme,
2345  xmpTPg_scheme,
2346  pdf_scheme,
2348  tiff_scheme,
2349  exif_scheme,
2350  stDim_scheme,
2352  stEvt_scheme,
2353  stRef_scheme,
2354  stVer_scheme,
2355  stJob_scheme,
2356  crs_scheme,
2357  xmpDM_scheme,
2360  MP_scheme,
2361  MPRI_scheme,
2362  MPReg_scheme
2363 };
2364 
2365 static void test_WICMapSchemaToName(void)
2366 {
2367  static const WCHAR xmW[] = { 'x','m',0 };
2368  static const WCHAR xmpW[] = { 'x','m','p',0 };
2369  static WCHAR schemaW[] = { 'h','t','t','p',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2370  static WCHAR SCHEMAW[] = { 'H','T','T','P',':','/','/','n','s','.','a','d','o','b','e','.','c','o','m','/','x','a','p','/','1','.','0','/',0 };
2371  HRESULT hr;
2372  UINT len, i, j;
2373  WCHAR name[16];
2374 
2375  hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, NULL, 0, NULL, NULL);
2376  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2377 
2378  hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, schemaW, 0, NULL, NULL);
2379  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2380 
2381  hr = WICMapSchemaToName(&GUID_MetadataFormatUnknown, schemaW, 0, NULL, &len);
2382  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#x\n", hr);
2383 
2384  hr = WICMapSchemaToName(NULL, schemaW, 0, NULL, &len);
2385  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2386 
2387  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, NULL, NULL);
2388  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2389 
2390  len = 0xdeadbeef;
2391  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, NULL, &len);
2392  ok(hr == S_OK, "got %#x\n", hr);
2393  ok(len == 4, "got %u\n", len);
2394 
2395  len = 0xdeadbeef;
2396  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, NULL, &len);
2397  ok(hr == S_OK, "got %#x\n", hr);
2398  ok(len == 4, "got %u\n", len);
2399 
2400  len = 0xdeadbeef;
2401  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, SCHEMAW, 0, NULL, &len);
2402  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "got %#x\n", hr);
2403  ok(len == 0xdeadbeef, "got %u\n", len);
2404 
2405  name[0] = 0;
2406  len = 0xdeadbeef;
2407  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, name, &len);
2408  ok(hr == S_OK, "got %#x\n", hr);
2409  ok(len == 4, "got %u\n", len);
2410  ok(!lstrcmpW(name, xmpW), "got %s\n", wine_dbgstr_w(name));
2411 
2412  len = 0xdeadbeef;
2413  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 0, name, &len);
2414  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2415  ok(len == 0xdeadbeef, "got %u\n", len);
2416 
2417  name[0] = 0;
2418  len = 0xdeadbeef;
2419  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 3, name, &len);
2421  ok(len == 0xdeadbeef, "got %u\n", len);
2422  ok(!lstrcmpW(name, xmW), "got %s\n", wine_dbgstr_w(name));
2423 
2424  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schemaW, 4, name, NULL);
2425  ok(hr == E_INVALIDARG, "got %#x\n", hr);
2426 
2427  /* Check whether modern schemas are supported */
2428  hr = WICMapSchemaToName(&GUID_MetadataFormatXMP, schema_list[0], 0, NULL, &len);
2430  {
2431  win_skip("Modern schemas are not supported\n");
2432  return;
2433  }
2434 
2435  for (i = 0; i < ARRAY_SIZE(guid_list); i++)
2436  {
2437  for (j = 0; j < ARRAY_SIZE(schema_list); j++)
2438  {
2440  if (IsEqualGUID(guid_list[i], &GUID_MetadataFormatXMP) ||
2441  IsEqualGUID(guid_list[i], &GUID_MetadataFormatXMPStruct))
2442  {
2443  ok(hr == S_OK, "%u: %u: format %s does not support schema %s\n",
2445  }
2446  else
2447  {
2448  ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "%u: %u: format %s supports schema %s\n",
2450  }
2451  }
2452  }
2453 }
2454 
2456 {
2457  const char *schema, *id_str;
2459 };
2460 
2462 {
2465  const struct metadata_item *item;
2466 };
2467 
2468 struct metadata
2469 {
2472  const struct metadata_block *block;
2473 };
2474 
2475 static const struct metadata *current_metadata;
2477 
2478 static char the_best[] = "The Best";
2479 static char the_worst[] = "The Worst";
2480 
2482 {
2483  trace("%p,%s,%p\n", iface, wine_dbgstr_guid(iid), out);
2484 
2485  if (IsEqualIID(iid, &IID_IUnknown) ||
2486  IsEqualIID(iid, &IID_IWICMetadataReader))
2487  {
2488  *out = iface;
2489  return S_OK;
2490  }
2491 
2492  ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid));
2493 
2494  *out = NULL;
2495  return E_NOINTERFACE;
2496 }
2497 
2499 {
2500  return 2;
2501 }
2502 
2504 {
2505  return 1;
2506 }
2507 
2509 {
2510  trace("%p,%p\n", iface, format);
2511 
2512  ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2513  if (!current_metadata_block) return E_POINTER;
2514 
2515  *format = *current_metadata_block->metadata_format;
2516  return S_OK;
2517 }
2518 
2520 {
2521  ok(0, "not implemented\n");
2522  return E_NOTIMPL;
2523 }
2524 
2526 {
2527  trace("%p,%p\n", iface, count);
2528 
2529  ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2530  if (!current_metadata_block) return E_POINTER;
2531 
2532  *count = current_metadata_block->count;
2533  return S_OK;
2534 }
2535 
2536 static HRESULT WINAPI mdr_GetValueByIndex(IWICMetadataReader *iface, UINT index, PROPVARIANT *schema, PROPVARIANT *id, PROPVARIANT *value)
2537 {
2538  ok(0, "not implemented\n");
2539  return E_NOTIMPL;
2540 }
2541 
2542 static char *get_temp_buffer(int size)
2543 {
2544  static char buf[16][256];
2545  static int idx;
2546  char *p;
2547 
2548  assert(size < 256);
2549 
2550  p = buf[idx & 0x0f];
2551  idx++;
2552  return p;
2553 }
2554 
2555 static const char *wine_dbgstr_propvariant(const PROPVARIANT *var)
2556 {
2557  char *ret;
2558 
2559  if (!var) return "(null)";
2560 
2561  switch (var->vt)
2562  {
2563  case VT_LPWSTR:
2564  ret = get_temp_buffer(lstrlenW(U(*var).pwszVal) + 16);
2565  sprintf(ret, "(VT_LPWSTR:%s)", wine_dbgstr_w(U(*var).pwszVal));
2566  break;
2567 
2568  case VT_LPSTR:
2569  ret = get_temp_buffer(lstrlenA(U(*var).pszVal) + 16);
2570  sprintf(ret, "(VT_LPSTR:%s)", U(*var).pszVal);
2571  break;
2572 
2573  default:
2574  ret = get_temp_buffer(16);
2575  sprintf(ret, "(vt:%u)", var->vt);
2576  break;
2577  }
2578 
2579  return ret;
2580 }
2581 
2582 static int propvar_cmp(const PROPVARIANT *v1, LONGLONG value2)
2583 {
2584  LONGLONG value1;
2585 
2586  if (PropVariantToInt64(v1, &value1) != S_OK) return -1;
2587 
2588  value1 -= value2;
2589  if (value1) return value1 < 0 ? -1 : 1;
2590  return 0;
2591 }
2592 
2593 static HRESULT WINAPI mdr_GetValue(IWICMetadataReader *iface, const PROPVARIANT *schema, const PROPVARIANT *id, PROPVARIANT *value)
2594 {
2595  UINT i;
2596 
2598 
2599  ok(current_metadata_block != NULL, "current_metadata_block can't be NULL\n");
2600  if (!current_metadata_block) return E_POINTER;
2601 
2602  ok(schema != NULL && id != NULL && value != NULL, "%p, %p, %p should not be NULL\n", schema, id, value);
2603 
2604  for (i = 0; i < current_metadata_block->count; i++)
2605  {
2606  if (schema->vt != VT_EMPTY)
2607  {
2608  if (!current_metadata_block->item[i].schema)
2609  continue;
2610 
2611  switch (schema->vt)
2612  {
2613  case VT_LPSTR:
2614  if (lstrcmpA(U(*schema).pszVal, current_metadata_block->item[i].schema) != 0)
2615  continue;
2616  break;
2617 
2618  case VT_LPWSTR:
2619  {
2620  char schemaA[256];
2621  WideCharToMultiByte(CP_ACP, 0, U(*schema).pwszVal, -1, schemaA, sizeof(schemaA), NULL, NULL);
2622  if (lstrcmpA(schemaA, current_metadata_block->item[i].schema) != 0)
2623  continue;
2624  break;
2625  }
2626 
2627  default:
2628  ok(0, "unsupported schema vt %u\n", schema->vt);
2629  continue;
2630  }
2631  }
2632  else if (current_metadata_block->item[i].schema)
2633  continue;
2634 
2635  switch (id->vt)
2636  {
2637  case VT_LPSTR:
2638  if (current_metadata_block->item[i].id_str)
2639  {
2640  if (!lstrcmpA(U(*id).pszVal, current_metadata_block->item[i].id_str))
2641  {
2642  value->vt = VT_LPSTR;
2643  U(*value).pszVal = the_best;
2644  return S_OK;
2645  }
2646  break;
2647  }
2648  break;
2649 
2650  case VT_LPWSTR:
2651  if (current_metadata_block->item[i].id_str)
2652  {
2653  char idA[256];
2654  WideCharToMultiByte(CP_ACP, 0, U(*id).pwszVal, -1, idA, sizeof(idA), NULL, NULL);
2655  if (!lstrcmpA(idA, current_metadata_block->item[i].id_str))
2656  {
2657  value->vt = VT_LPSTR;
2658  U(*value).pszVal = the_worst;
2659  return S_OK;
2660  }
2661  break;
2662  }
2663  break;
2664 
2665  case VT_CLSID:
2666  if (IsEqualGUID(U(*id).puuid, &GUID_MetadataFormatXMP) ||
2667  IsEqualGUID(U(*id).puuid, &GUID_ContainerFormatTiff))
2668  {
2669  value->vt = VT_UNKNOWN;
2670  value->punkVal = (IUnknown *)iface;
2671  return S_OK;
2672  }
2673  break;
2674 
2675  default:
2676  if (!propvar_cmp(id, current_metadata_block->item[i].id))
2677  {
2678  value->vt = current_metadata_block->item[i].type;
2679  U(*value).uiVal = current_metadata_block->item[i].value;
2680  return S_OK;
2681  }
2682  break;
2683  }
2684  }
2685 
2686  return 0xdeadbeef;
2687 }
2688 
2690 {
2691  ok(0, "not implemented\n");
2692  return E_NOTIMPL;
2693 }
2694 
2695 static const IWICMetadataReaderVtbl mdr_vtbl =
2696 {
2698  mdr_AddRef,
2699  mdr_Release,
2702  mdr_GetCount,
2704  mdr_GetValue,
2706 };
2707 
2709 
2711 {
2712  if (IsEqualIID(iid, &IID_IUnknown) ||
2713  IsEqualIID(iid, &IID_IWICMetadataBlockReader))
2714  {
2715  *out = iface;
2716  return S_OK;
2717  }
2718 
2719  /* Windows 8/10 query for some undocumented IID */
2720  if (!IsEqualIID(iid, &IID_MdbrUnknown))
2721  ok(0, "unknown iid %s\n", wine_dbgstr_guid(iid));
2722 
2723  *out = NULL;
2724  return E_NOINTERFACE;
2725 }
2726 
2728 {
2729  return 2;
2730 }
2731 
2733 {
2734  return 1;
2735 }
2736 
2738 {
2739  trace("%p,%p\n", iface, format);
2740 
2741  ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2742  if (!current_metadata) return E_POINTER;
2743 
2744  *format = *current_metadata->container_format;
2745  return S_OK;
2746 }
2747 
2749 {
2750  trace("%p,%p\n", iface, count);
2751 
2752  ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2753  if (!current_metadata) return E_POINTER;
2754 
2755  *count = current_metadata->count;
2756  return S_OK;
2757 }
2758 
2760 {
2761  trace("%p,%u,%p\n", iface, index, out);
2762 
2763  *out = NULL;
2764 
2765  ok(current_metadata != NULL, "current_metadata can't be NULL\n");
2766  if (!current_metadata) return E_POINTER;
2767 
2769  {
2771  *out = &mdr;
2772  return S_OK;
2773  }
2774 
2776  return E_INVALIDARG;
2777 }
2778 
2780 {
2781  ok(0, "not implemented\n");
2782  return E_NOTIMPL;
2783 }
2784 
2785 static const IWICMetadataBlockReaderVtbl mdbr_vtbl =
2786 {
2788  mdbr_AddRef,
2789  mdbr_Release,
2791  mdbr_GetCount,
2794 };
2795 
2797 
2798 static const char xmp[] = "http://ns.adobe.com/xap/1.0/";
2799 static const char dc[] = "http://purl.org/dc/elements/1.1/";
2800 static const char tiff[] = "http://ns.adobe.com/tiff/1.0/";
2801 
2802 static const struct metadata_item item1[] =
2803 {
2804  { NULL, NULL, 1, 2, 3 }
2805 };
2806 
2807 static const struct metadata_item item2[] =
2808 {
2809  { NULL, NULL, 1, 2, 3 },
2810  { "xmp", "Rating", 4, 5, 6 },
2811  { NULL, "Rating", 7, 8, 9 }
2812 };
2813 
2814 static const struct metadata_item item3[] =
2815 {
2816  { NULL, NULL, 1, 2, 3 },
2817  { NULL, NULL, 4, 5, 6 },
2818  { NULL, NULL, 7, 8, 9 },
2819  { NULL, NULL, 10, 11, 12 }
2820 };
2821 
2822 static const struct metadata_item item4[] =
2823 {
2824  { NULL, NULL, 1, 2, 3 },
2825  { xmp, "Rating", 4, 5, 6 },
2826  { dc, NULL, 7, 8, 9 },
2827  { tiff, NULL, 10, 11, 12 },
2828  { NULL, "RATING", 13, 14, 15 },
2829  { NULL, "R}ATING", 16, 17, 18 },
2830  { NULL, "xmp", 19, 20, 21 }
2831 };
2832 
2833 static const struct metadata_block block1[] =
2834 {
2835  { &GUID_MetadataFormatIfd, 1, item1 }
2836 };
2837 
2838 static const struct metadata_block block2[] =
2839 {
2840  { &GUID_MetadataFormatXMP, 1, item1 },
2841  { &GUID_MetadataFormatIfd, 3, item2 }
2842 };
2843 
2844 static const struct metadata_block block3[] =
2845 {
2846  { &GUID_MetadataFormatXMP, 1, item1 },
2847  { &GUID_MetadataFormatIfd, 3, item2 },
2848  { &GUID_MetadataFormatXMP, 4, item3 },
2849  { &GUID_MetadataFormatXMP, 7, item4 },
2850  { &GUID_MetadataFormatIfd, 7, item4 }
2851 };
2852 
2853 static const struct metadata data1 =
2854 {
2855  &GUID_ContainerFormatGif,
2856  1, block1
2857 };
2858 
2859 static const struct metadata data2 =
2860 {
2861  &GUID_ContainerFormatTiff,
2862  2, block2
2863 };
2864 
2865 static const struct metadata data3 =
2866 {
2867  &GUID_ContainerFormatPng,
2868  5, block3
2869 };
2870 
2871 static void test_queryreader(void)
2872 {
2873  static const char q1[] = "/ifd/{uchar=1}";
2874  static const char q2[] = "/ifd/xmp:{long=4}";
2875  static const char q3[] = "/ifd/{str=xmp}:{uint=4}";
2876  static const char q4[] = "/xmp/{char=7}";
2877  static const char q5[] = "/[1]xmp/{short=7}";
2878  static const char q6[] = "/[1]ifd/{str=dc}:{uint=7}";
2879  static const char q7[] = "/[1]ifd/{str=http://purl.org/dc/elements/1.1/}:{longlong=7}";
2880  static const char q8[] = "/[1]ifd/{str=http://ns.adobe.com/tiff/1.0/}:{int=10}";
2881  static const char q9[] = "/[2]xmp/xmp:{ulong=4}";
2882  static const char q10[] = "/[2]xmp/{str=xmp}:{ulong=4}";
2883  static const char q11[] = "/xmp";
2884  static const char q12[] = "/ifd/xmp";
2885  static const char q13[] = "/ifd/xmp/tiff";
2886  static const char q14[] = "/[0]ifd/[0]xmp/[0]tiff";
2887  static const char q15[] = "/[*]xmp";
2888 
2889  static const char q20[] = "/ifd/\\Rating";
2890  static const char q21[] = "/[0]ifd/Rating";
2891  static const char q22[] = "/[2]xmp/xmp:{str=Rating}";
2892  static const char q23[] = "/[2]xmp/xmp:Rating";
2893 
2894  static const char q24[] = "/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:Rating";
2895  static const char q25[] = "/[1]ifd/{str=http://ns.adobe.com/xap/1.0/}:{str=Rating}";
2896  static const char q26[] = "/[1]ifd/{wstr=\\RATING}";
2897  static const char q27[] = "/[1]ifd/{str=R\\ATING}";
2898  static const char q28[] = "/[1]ifd/{str=R\\}ATING}";
2899 
2900  static const char q40[] = "[0]/ifd/Rating";
2901  static const char q41[] = "/[+1]ifd/Rating";
2902  static const char q42[] = "/[-1]ifd/Rating";
2903  static const char q43[] = "/ifd/{\\str=Rating}";
2904  static const char q44[] = "/ifd/{badtype=0}";
2905  static const char q45[] = "/ifd/{uint=0x1234}";
2906  static const char q46[] = "/ifd/[0]Rating";
2907  static const char q47[] = "/ifd/[*]Rating";
2908  static const struct
2909  {
2910  BOOL todo;
2911  const struct metadata *data;
2912  const char *query;
2913  HRESULT hr;
2914  UINT vt, value;
2915  const char *str_value;
2916  } test_data[] =
2917  {
2918  { FALSE, &data1, q1, S_OK, 2, 3, NULL },
2919  { FALSE, &data2, q2, S_OK, 5, 6, NULL },
2920  { FALSE, &data2, q3, S_OK, 5, 6, NULL },
2921  { FALSE, &data3, q4, 0xdeadbeef },
2922  { FALSE, &data3, q5, S_OK, 8, 9, NULL },
2923  { FALSE, &data3, q6, 0xdeadbeef },
2924  { FALSE, &data3, q7, S_OK, 8, 9, NULL },
2925  { FALSE, &data3, q8, S_OK, 11, 12, NULL },
2926  { FALSE, &data3, q9, S_OK, 5, 6, NULL },
2927  { FALSE, &data3, q10, 0xdeadbeef },
2928 
2929  { FALSE, &data3, q11, S_OK, VT_UNKNOWN, 0, NULL },
2930  { FALSE, &data3, q12, S_OK, VT_UNKNOWN, 0, NULL },
2931  { FALSE, &data3, q13, S_OK, VT_UNKNOWN, 0, NULL },
2932  { FALSE, &data3, q14, S_OK, VT_UNKNOWN, 0, NULL },
2933  { TRUE, &data3, q15, S_OK, VT_LPSTR, 0, the_worst },
2934 
2935  { FALSE, &data3, q20, S_OK, VT_LPSTR, 0, the_worst },
2936  { FALSE, &data3, q21, S_OK, VT_LPSTR, 0, the_worst },
2937  { FALSE, &data3, q22, S_OK, VT_LPSTR, 0, the_best },
2938  { FALSE, &data3, q23, S_OK, VT_LPSTR, 0, the_worst },
2939  { FALSE, &data3, q24, S_OK, VT_LPSTR, 0, the_worst },
2940  { FALSE, &data3, q25, S_OK, VT_LPSTR, 0, the_best },
2941  { FALSE, &data3, q26, S_OK, VT_LPSTR, 0, the_worst },
2942  { FALSE, &data3, q27, S_OK, VT_LPSTR, 0, the_best },
2943  { FALSE, &data3, q28, S_OK, VT_LPSTR, 0, the_best },
2944 
2948  { FALSE, &data1, q43, WINCODEC_ERR_WRONGSTATE },
2949  { FALSE, &data1, q44, WINCODEC_ERR_WRONGSTATE },
2950  { TRUE, &data1, q45, DISP_E_TYPEMISMATCH },
2951  { TRUE, &data1, q46, E_INVALIDARG },
2953  };
2954  WCHAR queryW[256];
2955  HRESULT hr;
2958  GUID format;
2959  PROPVARIANT value;
2960  UINT i;
2961 
2962  hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
2963  &IID_IWICComponentFactory, (void **)&factory);
2964  ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
2965 
2966  hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &mdbr, &reader);
2967  ok(hr == S_OK, "CreateQueryReaderFromBlockReader error %#x\n", hr);
2968 
2969  for (i = 0; i < ARRAY_SIZE(test_data); i++)
2970  {
2971  current_metadata = test_data[i].data;
2972 
2973  hr = IWICMetadataQueryReader_GetContainerFormat(reader, &format);
2974  ok(hr == S_OK, "%u: GetContainerFormat error %#x\n", i, hr);
2975  ok(IsEqualGUID(&format, test_data[i].data->container_format), "%u: expected %s, got %s\n",
2976  i, wine_dbgstr_guid(test_data[i].data->container_format), wine_dbgstr_guid(&format));
2977 
2978  MultiByteToWideChar(CP_ACP, 0, test_data[i].query, -1, queryW, 256);
2979  PropVariantInit(&value);
2980  hr = IWICMetadataQueryReader_GetMetadataByName(reader, queryW, &value);
2982  ok(hr == test_data[i].hr, "%u: expected %#x, got %#x\n", i, test_data[i].hr, hr);
2983  if (hr == S_OK)
2984  {
2985  ok(value.vt == test_data[i].vt, "%u: expected %u, got %u\n", i, test_data[i].vt, value.vt);
2986  if (test_data[i].vt == value.vt)
2987  {
2988  if (value.vt == VT_UNKNOWN)
2989  {
2990  IWICMetadataQueryReader *new_reader;
2991  WCHAR location[256];
2992  UINT len;
2993 
2994  hr = IUnknown_QueryInterface(value.punkVal, &IID_IWICMetadataQueryReader, (void **)&new_reader);
2995  ok(hr == S_OK, "QueryInterface error %#x\n", hr);
2996 
2997  location[0] = 0;
2998  len = 0xdeadbeef;
2999  hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location, &len);
3000  ok(hr == S_OK, "GetLocation error %#x\n", hr);
3001  ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3002  ok(!lstrcmpW(location, queryW), "expected %s, got %s\n", wine_dbgstr_w(queryW), wine_dbgstr_w(location));
3003 
3004  hr = IWICMetadataQueryReader_GetLocation(new_reader, 256, location, NULL);
3005  ok(hr == E_INVALIDARG, "got %#x\n", hr);
3006 
3007  location[0] = 0;
3008  len = 0xdeadbeef;
3009  hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, location, &len);
3010  ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#x\n", hr);
3011  ok(len == 0xdeadbeef, "got %u\n", len);
3012  ok(!location[0], "got %s\n", wine_dbgstr_w(location));
3013 
3014  location[0] = 0;
3015  len = 0xdeadbeef;
3016  hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, location, &len);
3017  ok(hr == WINCODEC_ERR_INSUFFICIENTBUFFER, "got %#x\n", hr);
3018  ok(len == 0xdeadbeef, "got %u\n", len);
3019  ok(!location[0], "got %s\n", wine_dbgstr_w(location));
3020 
3021  len = 0xdeadbeef;
3022  hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL, &len);
3023  ok(hr == S_OK, "GetLocation error %#x\n", hr);
3024  ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3025 
3026  len = 0xdeadbeef;
3027  hr = IWICMetadataQueryReader_GetLocation(new_reader, 3, NULL, &len);
3028  ok(hr == S_OK, "GetLocation error %#x\n", hr);
3029  ok(len == lstrlenW(queryW) + 1, "expected %u, got %u\n", lstrlenW(queryW) + 1, len);
3030 
3031  hr = IWICMetadataQueryReader_GetLocation(new_reader, 0, NULL, NULL);
3032  ok(hr == E_INVALIDARG, "got %#x\n", hr);
3033 
3034  IWICMetadataQueryReader_Release(new_reader);
3035  }
3036  else if (value.vt == VT_LPSTR)
3037  ok(!lstrcmpA(U(value).pszVal, test_data[i].str_value), "%u: expected %s, got %s\n",
3038  i, test_data[i].str_value, U(value).pszVal);
3039  else
3040  ok(U(value).uiVal == test_data[i].value, "%u: expected %u, got %u\n",
3041  i, test_data[i].value, U(value).uiVal);
3042  }
3043 
3044  /*
3045  * Do NOT call PropVariantClear(&value) for fake value types.
3046  */
3047  }
3048  }
3049 
3050  IWICMetadataQueryReader_Release(reader);
3051  IWICComponentFactory_Release(factory);
3052 }
3053 
3055 {
3057 
3058  test_queryreader();
3076 
3077  CoUninitialize();
3078 }
static char the_worst[]
Definition: metadata.c:2479
static WCHAR xmpidq_scheme[]
Definition: metadata.c:2311
static const WCHAR imgdescW[]
static HRESULT WINAPI mdbr_GetContainerFormat(IWICMetadataBlockReader *iface, GUID *format)
Definition: metadata.c:2737
static WCHAR rdf_scheme[]
Definition: metadata.c:2308
struct _ULARGE_INTEGER::@3736 u
USHORT number_of_entries
Definition: metadata.c:81
static WCHAR * schema_list[]
Definition: metadata.c:2335
static const struct metadata_block * current_metadata_block
Definition: metadata.c:2476
static const IWICMetadataBlockReaderVtbl mdbr_vtbl
Definition: metadata.c:2785
#define WINCODEC_ERR_INVALIDQUERYCHARACTER
Definition: winerror.h:3310
static void test_metadata_GCE(void)
Definition: metadata.c:1926
#define SEEK_CUR
Definition: util.h:63
#define trace(...)
Definition: kmt_test.h:217
ULONG count
const struct metadata_item * item
Definition: metadata.c:2465
static void test_WICMapGuidToShortName(void)
Definition: metadata.c:2168
#define REFIID
Definition: