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