wininet: Fixed grouping security error flags.
[wine] / dlls / windowscodecs / tests / metadata.c
1 /*
2  * Copyright 2011 Vincent Povirk for CodeWeavers
3  * Copyright 2012 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <math.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29 #include "wincodecsdk.h"
30 #include "wine/test.h"
31
32 #define expect_blob(propvar, data, length) do { \
33     ok((propvar).vt == VT_BLOB, "unexpected vt: %i\n", (propvar).vt); \
34     if ((propvar).vt == VT_BLOB) { \
35         ok(U(propvar).blob.cbSize == (length), "expected size %u, got %u\n", (ULONG)(length), U(propvar).blob.cbSize); \
36         if (U(propvar).blob.cbSize == (length)) { \
37             ok(!memcmp(U(propvar).blob.pBlobData, (data), (length)), "unexpected data\n"); \
38         } \
39     } \
40 } while (0)
41
42 #define IFD_SHORT 3
43 #define IFD_LONG 4
44 #define IFD_RATIONAL 5
45
46 #include "pshpack2.h"
47 struct IFD_entry
48 {
49     SHORT id;
50     SHORT type;
51     ULONG length;
52     LONG  value;
53 };
54
55 struct IFD_rational
56 {
57     ULONG numerator;
58     ULONG denominator;
59 };
60
61 static const struct
62 {
63     USHORT number_of_entries;
64     struct IFD_entry entry[6];
65     ULONG next_IFD;
66     struct IFD_rational rational;
67 } IFD_data =
68 {
69     6,
70     {
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) }
77     },
78     0,
79     { 300, 1 }
80 };
81 #include "poppack.h"
82
83 static const char metadata_unknown[] = "lalala";
84
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 */
91 };
92
93 static const char *debugstr_guid(REFIID riid)
94 {
95     static char buf[50];
96
97     if(!riid)
98         return "(null)";
99
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]);
104
105     return buf;
106 }
107
108 static IStream *create_stream(const char *data, int data_size)
109 {
110     HRESULT hr;
111     IStream *stream;
112     HGLOBAL hdata;
113     void *locked_data;
114
115     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
116     ok(hdata != 0, "GlobalAlloc failed\n");
117     if (!hdata) return NULL;
118
119     locked_data = GlobalLock(hdata);
120     memcpy(locked_data, data, data_size);
121     GlobalUnlock(hdata);
122
123     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
124     ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr);
125
126     return stream;
127 }
128
129 static void load_stream(IUnknown *reader, const char *data, int data_size)
130 {
131     HRESULT hr;
132     IWICPersistStream *persist;
133     IStream *stream;
134
135     stream = create_stream(data, data_size);
136     if (!stream)
137         return;
138
139     hr = IUnknown_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist);
140     ok(hr == S_OK, "QueryInterface failed, hr=%x\n", hr);
141
142     if (SUCCEEDED(hr))
143     {
144         hr = IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
145         ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
146
147         IWICPersistStream_Release(persist);
148     }
149
150     IStream_Release(stream);
151 }
152
153 static void test_metadata_unknown(void)
154 {
155     HRESULT hr;
156     IWICMetadataReader *reader;
157     IWICEnumMetadataItem *enumerator;
158     PROPVARIANT schema, id, value;
159     ULONG items_returned;
160
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;
165
166     load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown));
167
168     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
169     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
170
171     if (SUCCEEDED(hr))
172     {
173         PropVariantInit(&schema);
174         PropVariantInit(&id);
175         PropVariantInit(&value);
176
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);
180
181         if (hr == S_OK && items_returned == 1)
182         {
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));
186
187             PropVariantClear(&schema);
188             PropVariantClear(&id);
189             PropVariantClear(&value);
190         }
191
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);
195
196         IWICEnumMetadataItem_Release(enumerator);
197     }
198
199     IWICMetadataReader_Release(reader);
200 }
201
202 static void test_metadata_tEXt(void)
203 {
204     HRESULT hr;
205     IWICMetadataReader *reader;
206     IWICEnumMetadataItem *enumerator;
207     PROPVARIANT schema, id, value;
208     ULONG items_returned, count;
209     GUID format;
210
211     PropVariantInit(&schema);
212     PropVariantInit(&id);
213     PropVariantInit(&value);
214
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;
219
220     hr = IWICMetadataReader_GetCount(reader, NULL);
221     ok(hr == E_INVALIDARG, "GetCount failed, hr=%x\n", hr);
222
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);
226
227     load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt));
228
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);
232
233     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
234     ok(hr == E_INVALIDARG, "GetEnumerator failed, hr=%x\n", hr);
235
236     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
237     ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
238
239     if (SUCCEEDED(hr))
240     {
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);
244
245         if (hr == S_OK && items_returned == 1)
246         {
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);
252
253             PropVariantClear(&schema);
254             PropVariantClear(&id);
255             PropVariantClear(&value);
256         }
257
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);
261
262         IWICEnumMetadataItem_Release(enumerator);
263     }
264
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));
268
269     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
270     ok(hr == E_INVALIDARG, "GetMetadataFormat failed, hr=%x\n", hr);
271
272     id.vt = VT_LPSTR;
273     U(id).pszVal = CoTaskMemAlloc(strlen("winetest") + 1);
274     strcpy(U(id).pszVal, "winetest");
275
276     hr = IWICMetadataReader_GetValue(reader, NULL, &id, NULL);
277     ok(hr == S_OK, "GetValue failed, hr=%x\n", hr);
278
279     hr = IWICMetadataReader_GetValue(reader, &schema, NULL, &value);
280     ok(hr == E_INVALIDARG, "GetValue failed, hr=%x\n", hr);
281
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);
287
288     strcpy(U(id).pszVal, "test");
289
290     hr = IWICMetadataReader_GetValue(reader, &schema, &id, &value);
291     ok(hr == WINCODEC_ERR_PROPERTYNOTFOUND, "GetValue failed, hr=%x\n", hr);
292
293     PropVariantClear(&id);
294
295     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
296     ok(hr == S_OK, "GetValueByIndex failed, hr=%x\n", hr);
297
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);
301
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);
307
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);
313
314     hr = IWICMetadataReader_GetValueByIndex(reader, 1, NULL, NULL, NULL);
315     ok(hr == E_INVALIDARG, "GetValueByIndex failed, hr=%x\n", hr);
316
317     IWICMetadataReader_Release(reader);
318 }
319
320 static void test_metadata_IFD(void)
321 {
322     static const struct test_data
323     {
324         ULONG type, id, value;
325     } td[6] =
326     {
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 }
333     };
334     HRESULT hr;
335     IWICMetadataReader *reader;
336     IWICEnumMetadataItem *enumerator;
337     PROPVARIANT schema, id, value;
338     ULONG items_returned, count, i;
339     GUID format;
340
341     PropVariantInit(&schema);
342     PropVariantInit(&id);
343     PropVariantInit(&value);
344
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;
349
350     hr = IWICMetadataReader_GetCount(reader, NULL);
351     ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
352
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);
356
357     load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data));
358
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);
362
363     hr = IWICMetadataReader_GetEnumerator(reader, NULL);
364     ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
365
366     hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
367     ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
368
369     for (i = 0; i < count; i++)
370     {
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);
374
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);
380
381         PropVariantClear(&schema);
382         PropVariantClear(&id);
383         PropVariantClear(&value);
384     }
385
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);
389
390     IWICEnumMetadataItem_Release(enumerator);
391
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));
395
396     hr = IWICMetadataReader_GetMetadataFormat(reader, NULL);
397     ok(hr == E_INVALIDARG, "GetMetadataFormat should fail\n");
398
399     hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, NULL);
400     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
401
402     hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
403     ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
404
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);
408
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);
412
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);
418
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);
424
425     hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
426     ok(hr == E_INVALIDARG, "GetValueByIndex should fail\n");
427
428     IWICMetadataReader_Release(reader);
429 }
430
431 static void test_create_reader(void)
432 {
433     HRESULT hr;
434     IWICComponentFactory *factory;
435     IStream *stream;
436     IWICMetadataReader *reader;
437     UINT count=0;
438     GUID format;
439
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;
444
445     stream = create_stream(metadata_tEXt, sizeof(metadata_tEXt));
446
447     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
448         &GUID_ContainerFormatPng, NULL, WICPersistOptionsDefault,
449         stream, &reader);
450     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
451
452     if (SUCCEEDED(hr))
453     {
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);
457
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));
461
462         IWICMetadataReader_Release(reader);
463     }
464
465     hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory,
466         &GUID_ContainerFormatWmp, NULL, WICPersistOptionsDefault,
467         stream, &reader);
468     ok(hr == S_OK, "CreateMetadataReaderFromContainer failed, hr=%x\n", hr);
469
470     if (SUCCEEDED(hr))
471     {
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);
475
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));
479
480         IWICMetadataReader_Release(reader);
481     }
482
483     IStream_Release(stream);
484
485     IWICComponentFactory_Release(factory);
486 }
487
488 START_TEST(metadata)
489 {
490     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
491
492     test_metadata_unknown();
493     test_metadata_tEXt();
494     test_metadata_IFD();
495     test_create_reader();
496
497     CoUninitialize();
498 }