windowscodecs: Add some tests for IFD metadata reader.
[wine/multimedia.git] / dlls / windowscodecs / tests / metadata.c
blobd4249f42691811f6d14f11a3b7aa9eabc9ea82de
1 /*
2 * Copyright 2011 Vincent Povirk for CodeWeavers
3 * Copyright 2012 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <math.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29 #include "wincodecsdk.h"
30 #include "wine/test.h"
32 #define expect_blob(propvar, data, length) do { \
33 ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
34 if ((propvar).vt == VT_BLOB) { \
35 ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
36 if (U(propvar).blob.cbSize == (length)) { \
37 ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
38 } \
39 } \
40 } while (0)
42 #define IFD_SHORT 3
43 #define IFD_LONG 4
44 #define IFD_RATIONAL 5
46 #include "pshpack2.h"
47 struct IFD_entry
49 SHORT id;
50 SHORT type;
51 ULONG length;
52 LONG value;
55 struct IFD_rational
57 ULONG numerator;
58 ULONG denominator;
61 static const struct
63 USHORT number_of_entries;
64 struct IFD_entry entry[6];
65 ULONG next_IFD;
66 struct IFD_rational rational;
67 } IFD_data =
71 { 0xfe, IFD_SHORT, 1, 1 },
72 { 0x100, IFD_LONG, 1, 222 },
73 { 0x101, IFD_LONG, 1, 333 },
74 { 0x102, IFD_SHORT, 1, 24 },
75 { 0x103, IFD_LONG, 1, 32773 },
76 { 0x11a, IFD_RATIONAL, 1, sizeof(USHORT) + sizeof(struct IFD_entry) * 6 + sizeof(ULONG) }
79 { 300, 1 }
81 #include "poppack.h"
83 static const char metadata_unknown[] = "lalala";
85 static const char metadata_tEXt[] = {
86 0,0,0,14, /* chunk length */
87 't','E','X','t', /* chunk type */
88 'w','i','n','e','t','e','s','t',0, /* keyword */
89 'v','a','l','u','e', /* text */
90 0x3f,0x64,0x19,0xf3 /* chunk CRC */
93 static const char *debugstr_guid(REFIID riid)
95 static char buf[50];
97 if(!riid)
98 return "(null)";
100 sprintf(buf, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
101 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0],
102 riid->Data4[1], riid->Data4[2], riid->Data4[3], riid->Data4[4],
103 riid->Data4[5], riid->Data4[6], riid->Data4[7]);
105 return buf;
108 static IStream *create_stream(const char *data, int data_size)
110 HRESULT hr;
111 IStream *stream;
112 HGLOBAL hdata;
113 void *locked_data;
115 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
116 ok(hdata != 0, "GlobalAlloc failed\n");
117 if (!hdata) return NULL;
119 locked_data = GlobalLock(hdata);
120 memcpy(locked_data, data, data_size);
121 GlobalUnlock(hdata);
123 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
124 ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
126 return stream;
129 static void load_stream(IUnknown *reader, const char *data, int data_size)
131 HRESULT hr;
132 IWICPersistStream *persist;
133 IStream *stream;
135 stream = create_stream(data, data_size);
136 if (!stream)
137 return;
139 hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
140 ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
142 if (SUCCEEDED(hr))
144 hr = IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
145 ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
147 IWICPersistStream_Release(persist);
150 IStream_Release(stream);
153 static void test_metadata_unknown(void)
155 HRESULT hr;
156 IWICMetadataReader *reader;
157 IWICEnumMetadataItem *enumerator;
158 PROPVARIANT schema, id, value;
159 ULONG items_returned;
161 hr = CoCreateInstance(&CLSID_WICUnknownMetadataReader, NULL, CLSCTX_INPROC_SERVER,
162 &IID_IWICMetadataReader, (void**)&reader);
163 ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
164 if (FAILED(hr)) return;
166 load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown));
168 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
169 ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
171 if (SUCCEEDED(hr))
173 PropVariantInit(&schema);
174 PropVariantInit(&id);
175 PropVariantInit(&value);
177 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
178 ok(hr == S_OK, "Next failed, hr=%x\n", hr);
179 ok(items_returned == 1, "unexpected item count %i\n", items_returned);
181 if (hr == S_OK && items_returned == 1)
183 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
184 ok(id.vt == VT_EMPTY, "unexpected vt: %i\n", id.vt);
185 expect_blob(value, metadata_unknown, sizeof(metadata_unknown));
187 PropVariantClear(&schema);
188 PropVariantClear(&id);
189 PropVariantClear(&value);
192 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
193 ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
194 ok(items_returned == 0, "unexpected item count %i\n", items_returned);
196 IWICEnumMetadataItem_Release(enumerator);
199 IWICMetadataReader_Release(reader);
202 static void test_metadata_tEXt(void)
204 HRESULT hr;
205 IWICMetadataReader *reader;
206 IWICEnumMetadataItem *enumerator;
207 PROPVARIANT schema, id, value;
208 ULONG items_returned, count;
209 GUID format;
211 PropVariantInit(&schema);
212 PropVariantInit(&id);
213 PropVariantInit(&value);
215 hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
216 &IID_IWICMetadataReader, (void**)&reader);
217 todo_wine ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
218 if (FAILED(hr)) return;
220 hr = IWICMetadataReader_GetCount(reader, NULL);
221 ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
223 hr = IWICMetadataReader_GetCount(reader, &count);
224 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
225 ok(count == 0, "unexpected count %i\n", count);
227 load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt));
229 hr = IWICMetadataReader_GetCount(reader, &count);
230 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
231 ok(count == 1, "unexpected count %i\n", count);
233 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
234 ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
236 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
237 ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
239 if (SUCCEEDED(hr))
241 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
242 ok(hr == S_OK, "Next failed, hr=%x\n", hr);
243 ok(items_returned == 1, "unexpected item count %i\n", items_returned);
245 if (hr == S_OK && items_returned == 1)
247 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
248 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
249 ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
250 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
251 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
253 PropVariantClear(&schema);
254 PropVariantClear(&id);
255 PropVariantClear(&value);
258 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
259 ok(hr == S_FALSE, "Next failed, hr=%x\n", hr);
260 ok(items_returned == 0, "unexpected item count %i\n", items_returned);
262 IWICEnumMetadataItem_Release(enumerator);
265 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
266 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
267 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
269 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
270 ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
272 id.vt = VT_LPSTR;
273 U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
274 strcpy(U(id).pszVal, "winetest");
276 hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
277 ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
279 hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
280 ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
282 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
283 ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
284 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
285 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
286 PropVariantClear(&value);
288 strcpy(U(id).pszVal, "test");
290 hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
291 ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
293 PropVariantClear(&id);
295 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
296 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
298 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
299 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
300 ok(schema.vt == VT_EMPTY, "unexpected vt: %i\n", schema.vt);
302 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
303 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
304 ok(id.vt == VT_LPSTR, "unexpected vt: %i\n", id.vt);
305 ok(!strcmp(U(id).pszVal, "winetest"), "unexpected id: %s\n", U(id).pszVal);
306 PropVariantClear(&id);
308 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
309 ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
310 ok(value.vt == VT_LPSTR, "unexpected vt: %i\n", value.vt);
311 ok(!strcmp(U(value).pszVal, "value"), "unexpected value: %s\n", U(value).pszVal);
312 PropVariantClear(&value);
314 hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
315 ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
317 IWICMetadataReader_Release(reader);
320 static void test_metadata_IFD(void)
322 static const struct test_data
324 ULONG type, id, value;
325 } td[6] =
327 { VT_UI2, 0xfe, 1 },
328 { VT_UI4, 0x100, 222 },
329 { VT_UI4, 0x101, 333 },
330 { VT_UI2, 0x102, 24 },
331 { VT_UI4, 0x103, 32773 },
332 { VT_UI8, 0x11a, 300 }
334 HRESULT hr;
335 IWICMetadataReader *reader;
336 IWICEnumMetadataItem *enumerator;
337 PROPVARIANT schema, id, value;
338 ULONG items_returned, count, i;
339 GUID format;
341 PropVariantInit(&schema);
342 PropVariantInit(&id);
343 PropVariantInit(&value);
345 hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
346 &IID_IWICMetadataReader, (void**)&reader);
347 todo_wine ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
348 if (FAILED(hr)) return;
350 hr = IWICMetadataReader_GetCount(reader, NULL);
351 ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
353 hr = IWICMetadataReader_GetCount(reader, &count);
354 ok(hr == S_OK, "GetCount error %#x\n", hr);
355 ok(count == 0, "unexpected count %u\n", count);
357 load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data));
359 hr = IWICMetadataReader_GetCount(reader, &count);
360 ok(hr == S_OK, "GetCount error %#x\n", hr);
361 ok(count == 6, "unexpected count %u\n", count);
363 hr = IWICMetadataReader_GetEnumerator(reader, NULL);
364 ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
366 hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
367 ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
369 for (i = 0; i < count; i++)
371 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
372 ok(hr == S_OK, "Next error %#x\n", hr);
373 ok(items_returned == 1, "unexpected item count %u\n", items_returned);
375 ok(schema.vt == VT_EMPTY, "%u: unexpected vt: %u\n", i, schema.vt);
376 ok(id.vt == VT_UI2, "%u: unexpected vt: %u\n", i, id.vt);
377 ok(U(id).uiVal == td[i].id, "%u: unexpected id: %#x\n", i, U(id).uiVal);
378 ok(value.vt == td[i].type, "%u: unexpected vt: %u\n", i, value.vt);
379 ok(U(value).ulVal == td[i].value, "%u: unexpected id: %u\n", i, U(value).ulVal);
381 PropVariantClear(&schema);
382 PropVariantClear(&id);
383 PropVariantClear(&value);
386 hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
387 ok(hr == S_FALSE, "Next should fail\n");
388 ok(items_returned == 0, "unexpected item count %u\n", items_returned);
390 IWICEnumMetadataItem_Release(enumerator);
392 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
393 ok(hr == S_OK, "GetMetadataFormat error %#x\n", hr);
394 ok(IsEqualGUID(&format, &GUID_MetadataFormatIfd), "unexpected format %s\n", debugstr_guid(&format));
396 hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
397 ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
399 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
400 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
402 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
403 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
405 hr = IWICMetadataReader_GetValueByIndex(reader, 0, &schema, NULL, NULL);
406 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
407 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
409 hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, &schema, NULL, NULL);
410 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
411 ok(schema.vt == VT_EMPTY, "unexpected vt: %u\n", schema.vt);
413 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, &id, NULL);
414 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
415 ok(id.vt == VT_UI2, "unexpected vt: %u\n", id.vt);
416 ok(U(id).uiVal == 0xfe, "unexpected id: %#x\n", U(id).uiVal);
417 PropVariantClear(&id);
419 hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
420 ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
421 ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
422 ok(U(value).ulVal == 1, "unexpected id: %u\n", U(value).ulVal);
423 PropVariantClear(&value);
425 hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
426 ok(hr == E_INVALIDARG, "GetValueByIndex should fail\n");
428 IWICMetadataReader_Release(reader);
431 static void test_create_reader(void)
433 HRESULT hr;
434 IWICComponentFactory *factory;
435 IStream *stream;
436 IWICMetadataReader *reader;
437 UINT count=0;
438 GUID format;
440 hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
441 &IID_IWICComponentFactory, (void**)&factory);
442 todo_wine ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
443 if (FAILED(hr)) return;
445 stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
447 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
448 &GUID_ContainerFormatPng, NULL, WICPersistOptionsDefault,
449 stream, &reader);
450 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
452 if (SUCCEEDED(hr))
454 hr = IWICMetadataReader_GetCount(reader, &count);
455 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
456 ok(count == 1, "unexpected count %i\n", count);
458 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
459 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
460 ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktEXt), "unexpected format %s\n", debugstr_guid(&format));
462 IWICMetadataReader_Release(reader);
465 hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
466 &GUID_ContainerFormatWmp, NULL, WICPersistOptionsDefault,
467 stream, &reader);
468 ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
470 if (SUCCEEDED(hr))
472 hr = IWICMetadataReader_GetCount(reader, &count);
473 ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
474 ok(count == 1, "unexpected count %i\n", count);
476 hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
477 ok(hr == S_OK, "GetMetadataFormat failed, hr=%x\n", hr);
478 ok(IsEqualGUID(&format, &GUID_MetadataFormatUnknown), "unexpected format %s\n", debugstr_guid(&format));
480 IWICMetadataReader_Release(reader);
483 IStream_Release(stream);
485 IWICComponentFactory_Release(factory);
488 START_TEST(metadata)
490 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
492 test_metadata_unknown();
493 test_metadata_tEXt();
494 test_metadata_IFD();
495 test_create_reader();
497 CoUninitialize();