1 /*
2  * Copyright 2010 Damjan Jovanovic
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #include <stdarg.h>
20 #include <math.h>
21 
22 #define COBJMACROS
23 
24 #include "windef.h"
25 #include "objbase.h"
26 #include "wincodec.h"
27 #include "wine/test.h"
28 
29 #include "pshpack1.h"
30 
31 struct ICONHEADER
32 {
33     WORD idReserved;
34     WORD idType;
35     WORD idCount;
36 };
37 
38 struct ICONDIRENTRY
39 {
40     BYTE bWidth;
41     BYTE bHeight;
42     BYTE bColorCount;
43     BYTE bReserved;
44     WORD wPlanes;
45     WORD wBitCount;
46     DWORD dwDIBSize;
47     DWORD dwDIBOffset;
48 };
49 
50 struct test_ico
51 {
52     struct ICONHEADER header;
53     struct ICONDIRENTRY direntry;
54     BITMAPINFOHEADER bmi;
55     unsigned char data[512];
56 };
57 
58 static const struct test_ico ico_1 =
59 {
60     /* ICONHEADER */
61     {
62       0, /* reserved */
63       1, /* type */
64       1, /* count */
65     },
66     /* ICONDIRENTRY */
67     {
68       16, /* width */
69       16, /* height */
70       2, /* color count */
71       0, /* reserved */
72       1, /* planes */
73       8, /* bitcount*/
74       40 + 2*4 + 16 * 16 + 16 * 4, /* data size */
75       22 /* data offset */
76     },
77     /* BITMAPINFOHEADER */
78     {
79       sizeof(BITMAPINFOHEADER), /* header size */
80       16, /* width */
81       2*16, /* height (XOR+AND rows) */
82       1, /* planes */
83       8, /* bit count */
84       0, /* compression */
85       0, /* sizeImage */
86       0, /* x pels per meter */
87       0, /* y pels per meter */
88       2, /* clrUsed */
89       0, /* clrImportant */
90     },
91     {
92       /* palette */
93       0,0,0,0,
94       0xFF,0xFF,0xFF,0,
95       /* XOR mask */
96       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98       0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
99       0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
100       0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
101       0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,
102       0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,
103       0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,
104       0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
105       0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
106       0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,
107       0,0,0,0,1,0,1,0,1,0,1,0,0,0,0,0,
108       0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,
109       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
110       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
111       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
112       /* AND mask */
113       0,0,0,0,
114       0,0,0,0,
115       0,0,0,0,
116       0,0,0,0,
117       0,0,0,0,
118       0,0,0,0,
119       0,0,0,0,
120       0,0,0,0,
121       0,0,0,0,
122       0,0,0,0,
123       0,0,0,0,
124       0,0,0,0,
125       0,0,0,0,
126       0,0,0,0,
127       0,0,0,0,
128       0,0,0,0
129     }
130 };
131 
132 #include "poppack.h"
133 
134 #define test_ico_data(a, b, c) test_ico_data_(a, b, c,  0, __LINE__)
135 #define test_ico_data_todo(a, b, c) test_ico_data_(a, b, c, 1, __LINE__)
136 static void test_ico_data_(void *data, DWORD data_size, HRESULT init_hr, int todo, unsigned int line)
137 {
138     IWICBitmapDecoder *decoder;
139     IWICImagingFactory *factory;
140     HRESULT hr;
141     IWICStream *icostream;
142     IWICBitmapFrameDecode *framedecode = NULL;
143 
144     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
145         &IID_IWICImagingFactory, (void**)&factory);
146     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
147     if (FAILED(hr)) return;
148 
149     hr = IWICImagingFactory_CreateStream(factory, &icostream);
150     ok(hr == S_OK, "CreateStream failed, hr=%x\n", hr);
151     if (SUCCEEDED(hr))
152     {
153         hr = IWICStream_InitializeFromMemory(icostream, data, data_size);
154         ok(hr == S_OK, "InitializeFromMemory failed, hr=%x\n", hr);
155 
156         if (SUCCEEDED(hr))
157         {
158             hr = CoCreateInstance(&CLSID_WICIcoDecoder, NULL, CLSCTX_INPROC_SERVER,
159                 &IID_IWICBitmapDecoder, (void**)&decoder);
160             ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
161         }
162 
163         if (SUCCEEDED(hr))
164         {
165             hr = IWICBitmapDecoder_Initialize(decoder, (IStream*)icostream,
166                 WICDecodeMetadataCacheOnDemand);
167         todo_wine_if(todo)
168             ok_(__FILE__, line)(hr == init_hr, "Initialize failed, hr=%x\n", hr);
169 
170             if (SUCCEEDED(hr))
171             {
172                 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
173                 ok(hr == S_OK, "GetFrame failed, hr=%x\n", hr);
174             }
175 
176             if (SUCCEEDED(hr))
177             {
178                 UINT width, height;
179                 IWICBitmapSource *thumbnail;
180 
181                 width = height = 0;
182                 hr = IWICBitmapFrameDecode_GetSize(framedecode, &width, &height);
183                 ok(hr == S_OK, "GetFrameSize failed, hr=%x\n", hr);
184                 ok(width == 16 && height == 16, "framesize=%ux%u\n", width, height);
185 
186                 hr = IWICBitmapFrameDecode_GetThumbnail(framedecode, &thumbnail);
187                 ok(hr == S_OK, "GetThumbnail failed, hr=%x\n", hr);
188                 if (hr == S_OK)
189                 {
190                     width = height = 0;
191                     hr = IWICBitmapSource_GetSize(thumbnail, &width, &height);
192                     ok(hr == S_OK, "GetFrameSize failed, hr=%x\n", hr);
193                     ok(width == 16 && height == 16, "framesize=%ux%u\n", width, height);
194                     IWICBitmapSource_Release(thumbnail);
195                 }
196                 IWICBitmapFrameDecode_Release(framedecode);
197             }
198 
199             IWICBitmapDecoder_Release(decoder);
200         }
201 
202         IWICStream_Release(icostream);
203     }
204 
205     IWICImagingFactory_Release(factory);
206 }
207 
208 static void test_decoder(void)
209 {
210     struct test_ico ico;
211 
212     /* Icon size specified in ICONDIRENTRY does not match bitmap header. */
213     ico = ico_1;
214     ico.direntry.bWidth = 2;
215     ico.direntry.bHeight = 2;
216     test_ico_data(&ico, sizeof(ico), S_OK);
217 
218     /* Invalid DIRENTRY data size/offset. */
219     ico = ico_1;
220     ico.direntry.dwDIBOffset = sizeof(ico);
221     test_ico_data(&ico, sizeof(ico), WINCODEC_ERR_BADIMAGE);
222 
223     ico = ico_1;
224     ico.direntry.dwDIBSize = sizeof(ico);
225     test_ico_data(&ico, sizeof(ico), WINCODEC_ERR_BADIMAGE);
226 
227     /* Header fields validation. */
228     ico = ico_1;
229     ico.header.idReserved = 1;
230     test_ico_data_todo(&ico, sizeof(ico), S_OK);
231     ico.header.idReserved = 0;
232     ico.header.idType = 100;
233     test_ico_data_todo(&ico, sizeof(ico), S_OK);
234 
235     /* Premature end of data. */
236     ico = ico_1;
237     test_ico_data(&ico, sizeof(ico.header) - 1, WINCODEC_ERR_STREAMREAD);
238     test_ico_data(&ico, sizeof(ico.header) + sizeof(ico.direntry) - 1, WINCODEC_ERR_BADIMAGE);
239 }
240 
241 START_TEST(icoformat)
242 {
243     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
244 
245     test_decoder();
246 
247     CoUninitialize();
248 }
249