Commit 432d8229 authored by Jeff Smith's avatar Jeff Smith Committed by Alexandre Julliard

windowscodecs: Handle PNG last-modification time (tIME) chunk type.

parent 60f6539f
......@@ -67,6 +67,7 @@ static const classinfo wic_classes[] = {
{&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance},
{&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance},
{&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance},
{&CLSID_WICPngTimeMetadataReader, PngTimeReader_CreateInstance},
{&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance},
{&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance},
{&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance},
......
......@@ -311,6 +311,92 @@ HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv)
return MetadataReader_Create(&HistReader_Vtbl, iid, ppv);
}
static HRESULT LoadTimeMetadata(IStream *stream, const GUID *preferred_vendor,
DWORD persist_options, MetadataItem **items, DWORD *item_count)
{
HRESULT hr;
BYTE type[4];
BYTE *data;
ULONG data_size, i;
MetadataItem *result;
static const WCHAR *names[6] =
{
L"Year",
L"Month",
L"Day",
L"Hour",
L"Minute",
L"Second",
};
LPWSTR id_values[6] = {0};
hr = read_png_chunk(stream, type, &data, &data_size);
if (FAILED(hr)) return hr;
if (data_size != 7)
{
HeapFree(GetProcessHeap(), 0, data);
return E_FAIL;
}
result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 6);
for (i = 0; i < 6; i++)
{
SHStrDupW(names[i], &id_values[i]);
if (!id_values[i]) break;
}
if (!result || i < 6)
{
HeapFree(GetProcessHeap(), 0, result);
for (i = 0; i < 6; i++)
CoTaskMemFree(id_values[i]);
HeapFree(GetProcessHeap(), 0, data);
return E_OUTOFMEMORY;
}
for (i = 0; i < 6; i++)
{
PropVariantInit(&result[i].schema);
PropVariantInit(&result[i].id);
PropVariantInit(&result[i].value);
result[i].id.vt = VT_LPWSTR;
result[i].id.pwszVal = id_values[i];
}
result[0].value.vt = VT_UI2;
result[0].value.uiVal = read_ushort_be(data);
result[1].value.vt = VT_UI1;
result[1].value.bVal = data[2];
result[2].value.vt = VT_UI1;
result[2].value.bVal = data[3];
result[3].value.vt = VT_UI1;
result[3].value.bVal = data[4];
result[4].value.vt = VT_UI1;
result[4].value.bVal = data[5];
result[5].value.vt = VT_UI1;
result[5].value.bVal = data[6];
*items = result;
*item_count = 6;
HeapFree(GetProcessHeap(), 0, data);
return S_OK;
}
static const MetadataHandlerVtbl TimeReader_Vtbl = {
0,
&CLSID_WICPngTimeMetadataReader,
LoadTimeMetadata
};
HRESULT PngTimeReader_CreateInstance(REFIID iid, void** ppv)
{
return MetadataReader_Create(&TimeReader_Vtbl, iid, ppv);
}
HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv)
{
HRESULT hr;
......
......@@ -1635,6 +1635,21 @@ static const struct reader_containers pnghist_containers[] = {
{ NULL } /* list terminator */
};
static const BYTE tIME[] = "tIME";
static const struct metadata_pattern pngtime_metadata_pattern[] = {
{ 4, 4, tIME, mask_all, 4 },
{ 0 }
};
static const struct reader_containers pngtime_containers[] = {
{
&GUID_ContainerFormatPng,
pngtime_metadata_pattern
},
{ NULL } /* list terminator */
};
static const struct metadata_pattern lsd_metadata_patterns[] = {
{ 0, 6, gif87a_magic, mask_all, 0 },
{ 0, 6, gif89a_magic, mask_all, 0 },
......@@ -1770,6 +1785,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = {
0, 0, 0,
pngtext_containers
},
{ &CLSID_WICPngTimeMetadataReader,
"The Wine Project",
"Chunk tIME Reader",
"1.0.0.0",
"1.0.0.0",
&GUID_VendorMicrosoft,
&GUID_MetadataFormatChunktIME,
0, 0, 0,
pngtime_containers
},
{ &CLSID_WICLSDMetadataReader,
"The Wine Project",
"Logical Screen Descriptor Reader",
......
......@@ -169,6 +169,14 @@ static const char metadata_hIST[] = {
0xff,0xff,0xff,0xff
};
static const char metadata_tIME[] = {
0,0,0,7, /* chunk length */
't','I','M','E', /* chunk type */
0x07,0xd0,0x01,0x02, /* year (2 bytes), month, day */
0x0c,0x22,0x38, /* hour, minute, second */
0xff,0xff,0xff,0xff
};
static const char pngimage[285] = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
......@@ -725,6 +733,42 @@ static void test_metadata_hIST(void)
IWICMetadataReader_Release(reader);
}
static void test_metadata_tIME(void)
{
HRESULT hr;
IWICMetadataReader *reader;
UINT count;
GUID format;
static const struct test_data td[] =
{
{ VT_UI2, 0, 0, { 2000 }, NULL, L"Year" },
{ VT_UI1, 0, 0, { 1 }, NULL, L"Month" },
{ VT_UI1, 0, 0, { 2 }, NULL, L"Day" },
{ VT_UI1, 0, 0, { 12 }, NULL, L"Hour" },
{ VT_UI1, 0, 0, { 34 }, NULL, L"Minute" },
{ VT_UI1, 0, 0, { 56 }, NULL, L"Second" },
};
hr = CoCreateInstance(&CLSID_WICPngTimeMetadataReader, NULL, CLSCTX_INPROC_SERVER,
&IID_IWICMetadataReader, (void**)&reader);
ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG) /*winxp*/, "CoCreateInstance failed, hr=%lx\n", hr);
if (FAILED(hr)) return;
load_stream((IUnknown*)reader, metadata_tIME, sizeof(metadata_tIME), WICPersistOptionDefault);
hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
ok(hr == S_OK, "GetMetadataFormat failed, hr=%lx\n", hr);
ok(IsEqualGUID(&format, &GUID_MetadataFormatChunktIME), "unexpected format %s\n", wine_dbgstr_guid(&format));
hr = IWICMetadataReader_GetCount(reader, &count);
ok(hr == S_OK, "GetCount failed, hr=%lx\n", hr);
ok(count == ARRAY_SIZE(td), "unexpected count %i\n", count);
compare_metadata(reader, td, count);
IWICMetadataReader_Release(reader);
}
static inline USHORT ushort_bswap(USHORT s)
{
return (s >> 8) | (s << 8);
......@@ -1108,12 +1152,12 @@ static void test_metadata_png(void)
{
static const struct test_data td[6] =
{
{ VT_UI2, 0, 0, { 2005 }, NULL, { 'Y','e','a','r',0 } },
{ VT_UI1, 0, 0, { 6 }, NULL, { 'M','o','n','t','h',0 } },
{ VT_UI1, 0, 0, { 3 }, NULL, { 'D','a','y',0 } },
{ VT_UI1, 0, 0, { 15 }, NULL, { 'H','o','u','r',0 } },
{ VT_UI1, 0, 0, { 7 }, NULL, { 'M','i','n','u','t','e',0 } },
{ VT_UI1, 0, 0, { 45 }, NULL, { 'S','e','c','o','n','d',0 } }
{ VT_UI2, 0, 0, { 2005 }, NULL, L"Year" },
{ VT_UI1, 0, 0, { 6 }, NULL, L"Month" },
{ VT_UI1, 0, 0, { 3 }, NULL, L"Day" },
{ VT_UI1, 0, 0, { 15 }, NULL, L"Hour" },
{ VT_UI1, 0, 0, { 7 }, NULL, L"Minute" },
{ VT_UI1, 0, 0, { 45 }, NULL, L"Second" }
};
IStream *stream;
IWICBitmapDecoder *decoder;
......@@ -1176,13 +1220,13 @@ static void test_metadata_png(void)
{
hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr);
todo_wine ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
ok(IsEqualGUID(&containerformat, &GUID_MetadataFormatChunktIME) ||
broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
"unexpected container format\n");
hr = IWICMetadataReader_GetCount(reader, &count);
ok(hr == S_OK, "GetCount error %#lx\n", hr);
todo_wine ok(count == 6 || broken(count == 1) /* XP */, "expected 6, got %u\n", count);
ok(count == 6 || broken(count == 1) /* XP */, "expected 6, got %u\n", count);
if (count == 6)
compare_metadata(reader, td, count);
......@@ -3272,6 +3316,7 @@ START_TEST(metadata)
test_metadata_gAMA();
test_metadata_cHRM();
test_metadata_hIST();
test_metadata_tIME();
test_metadata_IFD();
test_metadata_Exif();
test_create_reader();
......
......@@ -221,6 +221,7 @@ extern HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngTextReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngTimeReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv);
extern HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv);
extern HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv);
......
......@@ -190,6 +190,13 @@ coclass WICPngHistMetadataReader { interface IWICMetadataReader; }
coclass WICPngTextMetadataReader { interface IWICMetadataReader; }
[
helpstring("WIC Png tIME Metadata Reader"),
threading(both),
uuid(d94edf02-efe5-4f0d-85c8-f5a68b3000b1)
]
coclass WICPngTimeMetadataReader { interface IWICMetadataReader; }
[
helpstring("WIC LSD Metadata Reader"),
threading(both),
uuid(41070793-59e4-479a-a1f7-954adc2ef5fc)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment