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[] = { ...@@ -67,6 +67,7 @@ static const classinfo wic_classes[] = {
{&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance}, {&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance},
{&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance}, {&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance},
{&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance}, {&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance},
{&CLSID_WICPngTimeMetadataReader, PngTimeReader_CreateInstance},
{&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance}, {&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance},
{&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance}, {&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance},
{&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance}, {&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance},
......
...@@ -311,6 +311,92 @@ HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv) ...@@ -311,6 +311,92 @@ HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv)
return MetadataReader_Create(&HistReader_Vtbl, iid, 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 PngDecoder_CreateInstance(REFIID iid, void** ppv)
{ {
HRESULT hr; HRESULT hr;
......
...@@ -1635,6 +1635,21 @@ static const struct reader_containers pnghist_containers[] = { ...@@ -1635,6 +1635,21 @@ static const struct reader_containers pnghist_containers[] = {
{ NULL } /* list terminator */ { 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[] = { static const struct metadata_pattern lsd_metadata_patterns[] = {
{ 0, 6, gif87a_magic, mask_all, 0 }, { 0, 6, gif87a_magic, mask_all, 0 },
{ 0, 6, gif89a_magic, mask_all, 0 }, { 0, 6, gif89a_magic, mask_all, 0 },
...@@ -1770,6 +1785,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = { ...@@ -1770,6 +1785,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = {
0, 0, 0, 0, 0, 0,
pngtext_containers 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, { &CLSID_WICLSDMetadataReader,
"The Wine Project", "The Wine Project",
"Logical Screen Descriptor Reader", "Logical Screen Descriptor Reader",
......
...@@ -169,6 +169,14 @@ static const char metadata_hIST[] = { ...@@ -169,6 +169,14 @@ static const char metadata_hIST[] = {
0xff,0xff,0xff,0xff 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] = { static const char pngimage[285] = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 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, 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) ...@@ -725,6 +733,42 @@ static void test_metadata_hIST(void)
IWICMetadataReader_Release(reader); 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) static inline USHORT ushort_bswap(USHORT s)
{ {
return (s >> 8) | (s << 8); return (s >> 8) | (s << 8);
...@@ -1108,12 +1152,12 @@ static void test_metadata_png(void) ...@@ -1108,12 +1152,12 @@ static void test_metadata_png(void)
{ {
static const struct test_data td[6] = static const struct test_data td[6] =
{ {
{ VT_UI2, 0, 0, { 2005 }, NULL, { 'Y','e','a','r',0 } }, { VT_UI2, 0, 0, { 2005 }, NULL, L"Year" },
{ VT_UI1, 0, 0, { 6 }, NULL, { 'M','o','n','t','h',0 } }, { VT_UI1, 0, 0, { 6 }, NULL, L"Month" },
{ VT_UI1, 0, 0, { 3 }, NULL, { 'D','a','y',0 } }, { VT_UI1, 0, 0, { 3 }, NULL, L"Day" },
{ VT_UI1, 0, 0, { 15 }, NULL, { 'H','o','u','r',0 } }, { VT_UI1, 0, 0, { 15 }, NULL, L"Hour" },
{ VT_UI1, 0, 0, { 7 }, NULL, { 'M','i','n','u','t','e',0 } }, { VT_UI1, 0, 0, { 7 }, NULL, L"Minute" },
{ VT_UI1, 0, 0, { 45 }, NULL, { 'S','e','c','o','n','d',0 } } { VT_UI1, 0, 0, { 45 }, NULL, L"Second" }
}; };
IStream *stream; IStream *stream;
IWICBitmapDecoder *decoder; IWICBitmapDecoder *decoder;
...@@ -1176,13 +1220,13 @@ static void test_metadata_png(void) ...@@ -1176,13 +1220,13 @@ static void test_metadata_png(void)
{ {
hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat); hr = IWICMetadataReader_GetMetadataFormat(reader, &containerformat);
ok(hr == S_OK, "GetMetadataFormat failed, hr=%#lx\n", hr); 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 */, broken(IsEqualGUID(&containerformat, &GUID_MetadataFormatUnknown)) /* Windows XP */,
"unexpected container format\n"); "unexpected container format\n");
hr = IWICMetadataReader_GetCount(reader, &count); hr = IWICMetadataReader_GetCount(reader, &count);
ok(hr == S_OK, "GetCount error %#lx\n", hr); 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) if (count == 6)
compare_metadata(reader, td, count); compare_metadata(reader, td, count);
...@@ -3272,6 +3316,7 @@ START_TEST(metadata) ...@@ -3272,6 +3316,7 @@ START_TEST(metadata)
test_metadata_gAMA(); test_metadata_gAMA();
test_metadata_cHRM(); test_metadata_cHRM();
test_metadata_hIST(); test_metadata_hIST();
test_metadata_tIME();
test_metadata_IFD(); test_metadata_IFD();
test_metadata_Exif(); test_metadata_Exif();
test_create_reader(); test_create_reader();
......
...@@ -221,6 +221,7 @@ extern HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv); ...@@ -221,6 +221,7 @@ extern HRESULT PngChrmReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv); extern HRESULT PngHistReader_CreateInstance(REFIID iid, void** ppv);
extern HRESULT PngTextReader_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 LSDReader_CreateInstance(REFIID iid, void **ppv);
extern HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv);
extern HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv); extern HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv);
......
...@@ -190,6 +190,13 @@ coclass WICPngHistMetadataReader { interface IWICMetadataReader; } ...@@ -190,6 +190,13 @@ coclass WICPngHistMetadataReader { interface IWICMetadataReader; }
coclass WICPngTextMetadataReader { 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"), helpstring("WIC LSD Metadata Reader"),
threading(both), threading(both),
uuid(41070793-59e4-479a-a1f7-954adc2ef5fc) 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