include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / windowscodecs / pngformat.c
blob0e69671c9b83ab172c74eebe7497ca93d7055f35
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2016 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 <stdarg.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "winbase.h"
26 #include "objbase.h"
27 #include "shlwapi.h"
29 #include "wincodecs_private.h"
31 #include "wine/debug.h"
33 static inline USHORT read_ushort_be(BYTE* data)
35 return data[0] << 8 | data[1];
38 static inline ULONG read_ulong_be(BYTE* data)
40 return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
43 static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor,
44 DWORD persist_options, MetadataItem **items, DWORD *item_count)
46 HRESULT hr;
47 BYTE type[4];
48 BYTE *data;
49 ULONG data_size;
50 ULONG name_len, value_len;
51 BYTE *name_end_ptr;
52 LPSTR name, value;
53 MetadataItem *result;
55 hr = read_png_chunk(stream, type, &data, &data_size);
56 if (FAILED(hr)) return hr;
58 name_end_ptr = memchr(data, 0, data_size);
60 name_len = name_end_ptr - data;
62 if (!name_end_ptr || name_len > 79)
64 free(data);
65 return E_FAIL;
68 value_len = data_size - name_len - 1;
70 result = calloc(1, sizeof(MetadataItem));
71 name = CoTaskMemAlloc(name_len + 1);
72 value = CoTaskMemAlloc(value_len + 1);
73 if (!result || !name || !value)
75 free(data);
76 free(result);
77 CoTaskMemFree(name);
78 CoTaskMemFree(value);
79 return E_OUTOFMEMORY;
82 PropVariantInit(&result[0].schema);
83 PropVariantInit(&result[0].id);
84 PropVariantInit(&result[0].value);
86 memcpy(name, data, name_len + 1);
87 memcpy(value, name_end_ptr + 1, value_len);
88 value[value_len] = 0;
90 result[0].id.vt = VT_LPSTR;
91 result[0].id.pszVal = name;
92 result[0].value.vt = VT_LPSTR;
93 result[0].value.pszVal = value;
95 *items = result;
96 *item_count = 1;
98 free(data);
100 return S_OK;
103 static const MetadataHandlerVtbl TextReader_Vtbl = {
105 &CLSID_WICPngTextMetadataReader,
106 LoadTextMetadata
109 HRESULT PngTextReader_CreateInstance(REFIID iid, void** ppv)
111 return MetadataReader_Create(&TextReader_Vtbl, iid, ppv);
114 static HRESULT LoadGamaMetadata(IStream *stream, const GUID *preferred_vendor,
115 DWORD persist_options, MetadataItem **items, DWORD *item_count)
117 HRESULT hr;
118 BYTE type[4];
119 BYTE *data;
120 ULONG data_size;
121 ULONG gamma;
122 LPWSTR name;
123 MetadataItem *result;
125 hr = read_png_chunk(stream, type, &data, &data_size);
126 if (FAILED(hr)) return hr;
128 if (data_size < 4)
130 free(data);
131 return E_FAIL;
134 gamma = read_ulong_be(data);
136 free(data);
138 result = calloc(1, sizeof(MetadataItem));
139 SHStrDupW(L"ImageGamma", &name);
140 if (!result || !name)
142 free(result);
143 CoTaskMemFree(name);
144 return E_OUTOFMEMORY;
147 PropVariantInit(&result[0].schema);
148 PropVariantInit(&result[0].id);
149 PropVariantInit(&result[0].value);
151 result[0].id.vt = VT_LPWSTR;
152 result[0].id.pwszVal = name;
153 result[0].value.vt = VT_UI4;
154 result[0].value.ulVal = gamma;
156 *items = result;
157 *item_count = 1;
159 return S_OK;
162 static const MetadataHandlerVtbl GamaReader_Vtbl = {
164 &CLSID_WICPngGamaMetadataReader,
165 LoadGamaMetadata
168 HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv)
170 return MetadataReader_Create(&GamaReader_Vtbl, iid, ppv);
173 static HRESULT LoadChrmMetadata(IStream *stream, const GUID *preferred_vendor,
174 DWORD persist_options, MetadataItem **items, DWORD *item_count)
176 HRESULT hr;
177 BYTE type[4];
178 BYTE *data;
179 ULONG data_size;
180 static const WCHAR names[8][12] = {
181 L"WhitePointX",
182 L"WhitePointY",
183 L"RedX",
184 L"RedY",
185 L"GreenX",
186 L"GreenY",
187 L"BlueX",
188 L"BlueY",
190 LPWSTR dyn_names[8] = {0};
191 MetadataItem *result;
192 int i;
194 hr = read_png_chunk(stream, type, &data, &data_size);
195 if (FAILED(hr)) return hr;
197 if (data_size < 32)
199 free(data);
200 return E_FAIL;
203 result = calloc(8, sizeof(MetadataItem));
204 for (i=0; i<8; i++)
206 SHStrDupW(names[i], &dyn_names[i]);
207 if (!dyn_names[i]) break;
209 if (!result || i < 8)
211 free(result);
212 for (i=0; i<8; i++)
213 CoTaskMemFree(dyn_names[i]);
214 free(data);
215 return E_OUTOFMEMORY;
218 for (i=0; i<8; i++)
220 PropVariantInit(&result[i].schema);
222 PropVariantInit(&result[i].id);
223 result[i].id.vt = VT_LPWSTR;
224 result[i].id.pwszVal = dyn_names[i];
226 PropVariantInit(&result[i].value);
227 result[i].value.vt = VT_UI4;
228 result[i].value.ulVal = read_ulong_be(&data[i*4]);
231 *items = result;
232 *item_count = 8;
234 free(data);
236 return S_OK;
239 static const MetadataHandlerVtbl ChrmReader_Vtbl = {
241 &CLSID_WICPngChrmMetadataReader,
242 LoadChrmMetadata
245 HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv)
247 return MetadataReader_Create(&ChrmReader_Vtbl, iid, ppv);
250 static HRESULT LoadHistMetadata(IStream *stream, const GUID *preferred_vendor,
251 DWORD persist_options, MetadataItem **items, DWORD *item_count)
253 HRESULT hr;
254 BYTE type[4];
255 BYTE *data;
256 ULONG data_size, element_count, i;
257 LPWSTR name;
258 MetadataItem *result;
259 USHORT *elements;
261 hr = read_png_chunk(stream, type, &data, &data_size);
262 if (FAILED(hr)) return hr;
264 element_count = data_size / 2;
265 elements = CoTaskMemAlloc(element_count * sizeof(USHORT));
266 if (!elements)
268 free(data);
269 return E_OUTOFMEMORY;
271 for (i = 0; i < element_count; i++)
272 elements[i] = read_ushort_be(data + i * 2);
274 free(data);
276 result = calloc(1, sizeof(MetadataItem));
277 SHStrDupW(L"Frequencies", &name);
278 if (!result || !name) {
279 free(result);
280 CoTaskMemFree(name);
281 CoTaskMemFree(elements);
282 return E_OUTOFMEMORY;
285 PropVariantInit(&result[0].schema);
286 PropVariantInit(&result[0].id);
287 PropVariantInit(&result[0].value);
289 result[0].id.vt = VT_LPWSTR;
290 result[0].id.pwszVal = name;
292 result[0].value.vt = VT_UI2|VT_VECTOR;
293 result[0].value.caui.cElems = element_count;
294 result[0].value.caui.pElems = elements;
296 *items = result;
297 *item_count = 1;
299 return S_OK;
302 static const MetadataHandlerVtbl HistReader_Vtbl = {
304 &CLSID_WICPngHistMetadataReader,
305 LoadHistMetadata
308 HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv)
310 return MetadataReader_Create(&HistReader_Vtbl, iid, ppv);
313 static HRESULT LoadTimeMetadata(IStream *stream, const GUID *preferred_vendor,
314 DWORD persist_options, MetadataItem **items, DWORD *item_count)
316 HRESULT hr;
317 BYTE type[4];
318 BYTE *data;
319 ULONG data_size, i;
320 MetadataItem *result;
321 static const WCHAR *names[6] =
323 L"Year",
324 L"Month",
325 L"Day",
326 L"Hour",
327 L"Minute",
328 L"Second",
330 LPWSTR id_values[6] = {0};
333 hr = read_png_chunk(stream, type, &data, &data_size);
334 if (FAILED(hr)) return hr;
336 if (data_size != 7)
338 free(data);
339 return E_FAIL;
342 result = calloc(6, sizeof(MetadataItem));
343 for (i = 0; i < 6; i++)
345 SHStrDupW(names[i], &id_values[i]);
346 if (!id_values[i]) break;
348 if (!result || i < 6)
350 free(result);
351 for (i = 0; i < 6; i++)
352 CoTaskMemFree(id_values[i]);
353 free(data);
354 return E_OUTOFMEMORY;
357 for (i = 0; i < 6; i++)
359 PropVariantInit(&result[i].schema);
360 PropVariantInit(&result[i].id);
361 PropVariantInit(&result[i].value);
363 result[i].id.vt = VT_LPWSTR;
364 result[i].id.pwszVal = id_values[i];
367 result[0].value.vt = VT_UI2;
368 result[0].value.uiVal = read_ushort_be(data);
369 result[1].value.vt = VT_UI1;
370 result[1].value.bVal = data[2];
371 result[2].value.vt = VT_UI1;
372 result[2].value.bVal = data[3];
373 result[3].value.vt = VT_UI1;
374 result[3].value.bVal = data[4];
375 result[4].value.vt = VT_UI1;
376 result[4].value.bVal = data[5];
377 result[5].value.vt = VT_UI1;
378 result[5].value.bVal = data[6];
380 *items = result;
381 *item_count = 6;
383 free(data);
385 return S_OK;
388 static const MetadataHandlerVtbl TimeReader_Vtbl = {
390 &CLSID_WICPngTimeMetadataReader,
391 LoadTimeMetadata
394 HRESULT PngTimeReader_CreateInstance(REFIID iid, void** ppv)
396 return MetadataReader_Create(&TimeReader_Vtbl, iid, ppv);
399 HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv)
401 HRESULT hr;
402 struct decoder *decoder;
403 struct decoder_info decoder_info;
405 hr = png_decoder_create(&decoder_info, &decoder);
407 if (SUCCEEDED(hr))
408 hr = CommonDecoder_CreateInstance(decoder, &decoder_info, iid, ppv);
410 return hr;
413 HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv)
415 HRESULT hr;
416 struct encoder *encoder;
417 struct encoder_info encoder_info;
419 hr = png_encoder_create(&encoder_info, &encoder);
421 if (SUCCEEDED(hr))
422 hr = CommonEncoder_CreateInstance(encoder, &encoder_info, iid, ppv);
424 return hr;