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
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
)
50 ULONG name_len
, value_len
;
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)
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
)
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
);
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
;
103 static const MetadataHandlerVtbl TextReader_Vtbl
= {
105 &CLSID_WICPngTextMetadataReader
,
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
)
123 MetadataItem
*result
;
125 hr
= read_png_chunk(stream
, type
, &data
, &data_size
);
126 if (FAILED(hr
)) return hr
;
134 gamma
= read_ulong_be(data
);
138 result
= calloc(1, sizeof(MetadataItem
));
139 SHStrDupW(L
"ImageGamma", &name
);
140 if (!result
|| !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
;
162 static const MetadataHandlerVtbl GamaReader_Vtbl
= {
164 &CLSID_WICPngGamaMetadataReader
,
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
)
180 static const WCHAR names
[8][12] = {
190 LPWSTR dyn_names
[8] = {0};
191 MetadataItem
*result
;
194 hr
= read_png_chunk(stream
, type
, &data
, &data_size
);
195 if (FAILED(hr
)) return hr
;
203 result
= calloc(8, sizeof(MetadataItem
));
206 SHStrDupW(names
[i
], &dyn_names
[i
]);
207 if (!dyn_names
[i
]) break;
209 if (!result
|| i
< 8)
213 CoTaskMemFree(dyn_names
[i
]);
215 return E_OUTOFMEMORY
;
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]);
239 static const MetadataHandlerVtbl ChrmReader_Vtbl
= {
241 &CLSID_WICPngChrmMetadataReader
,
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
)
256 ULONG data_size
, element_count
, i
;
258 MetadataItem
*result
;
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
));
269 return E_OUTOFMEMORY
;
271 for (i
= 0; i
< element_count
; i
++)
272 elements
[i
] = read_ushort_be(data
+ i
* 2);
276 result
= calloc(1, sizeof(MetadataItem
));
277 SHStrDupW(L
"Frequencies", &name
);
278 if (!result
|| !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
;
302 static const MetadataHandlerVtbl HistReader_Vtbl
= {
304 &CLSID_WICPngHistMetadataReader
,
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
)
320 MetadataItem
*result
;
321 static const WCHAR
*names
[6] =
330 LPWSTR id_values
[6] = {0};
333 hr
= read_png_chunk(stream
, type
, &data
, &data_size
);
334 if (FAILED(hr
)) return hr
;
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)
351 for (i
= 0; i
< 6; i
++)
352 CoTaskMemFree(id_values
[i
]);
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];
388 static const MetadataHandlerVtbl TimeReader_Vtbl
= {
390 &CLSID_WICPngTimeMetadataReader
,
394 HRESULT
PngTimeReader_CreateInstance(REFIID iid
, void** ppv
)
396 return MetadataReader_Create(&TimeReader_Vtbl
, iid
, ppv
);
399 HRESULT
PngDecoder_CreateInstance(REFIID iid
, void** ppv
)
402 struct decoder
*decoder
;
403 struct decoder_info decoder_info
;
405 hr
= png_decoder_create(&decoder_info
, &decoder
);
408 hr
= CommonDecoder_CreateInstance(decoder
, &decoder_info
, iid
, ppv
);
413 HRESULT
PngEncoder_CreateInstance(REFIID iid
, void** ppv
)
416 struct encoder
*encoder
;
417 struct encoder_info encoder_info
;
419 hr
= png_encoder_create(&encoder_info
, &encoder
);
422 hr
= CommonEncoder_CreateInstance(encoder
, &encoder_info
, iid
, ppv
);