diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c index a42aeab84b..61ddfd94ff 100644 --- a/dlls/windowscodecs/clsfactory.c +++ b/dlls/windowscodecs/clsfactory.c @@ -65,6 +65,7 @@ static const classinfo wic_classes[] = { {&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance}, {&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance}, {&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance}, + {&CLSID_WICAPEMetadataReader, APEReader_CreateInstance}, {0}}; typedef struct { diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c index a814c1a7e6..14d7d01a2a 100644 --- a/dlls/windowscodecs/gifformat.c +++ b/dlls/windowscodecs/gifformat.c @@ -325,6 +325,115 @@ HRESULT GCEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) return MetadataReader_Create(&GCEReader_Vtbl, pUnkOuter, iid, ppv); } +static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options, + MetadataItem **items, DWORD *count) +{ +#include "pshpack1.h" + struct application_extenstion + { + BYTE extension_introducer; + BYTE extension_label; + BYTE block_size; + BYTE application[11]; + } ape_data; +#include "poppack.h" + HRESULT hr; + ULONG bytesread, data_size, i; + MetadataItem *result; + BYTE subblock_size; + BYTE *data; + + *items = NULL; + *count = 0; + + hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread); + if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK; + if (ape_data.extension_introducer != 0x21 || ape_data.extension_label != 0xff || + ape_data.block_size != 11) + return S_OK; + + data = NULL; + data_size = 0; + + for (;;) + { + hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread); + if (FAILED(hr) || bytesread != sizeof(subblock_size)) + { + HeapFree(GetProcessHeap(), 0, data); + return S_OK; + } + if (!subblock_size) break; + + if (!data) + data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1); + else + { + BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1); + if (!new_data) + { + HeapFree(GetProcessHeap(), 0, data); + return S_OK; + } + data = new_data; + } + data[data_size] = subblock_size; + hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread); + if (FAILED(hr) || bytesread != subblock_size) + { + HeapFree(GetProcessHeap(), 0, data); + return S_OK; + } + data_size += subblock_size + 1; + } + + result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 2); + if (!result) + { + HeapFree(GetProcessHeap(), 0, data); + return E_OUTOFMEMORY; + } + + for (i = 0; i < 2; i++) + { + PropVariantInit(&result[i].schema); + PropVariantInit(&result[i].id); + PropVariantInit(&result[i].value); + } + + result[0].id.vt = VT_LPWSTR; + result[0].id.u.pwszVal = strdupAtoW("Application"); + result[0].value.vt = VT_UI1|VT_VECTOR; + result[0].value.u.caub.cElems = sizeof(ape_data.application); + result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application)); + memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application)); + + result[1].id.vt = VT_LPWSTR; + result[1].id.u.pwszVal = strdupAtoW("Data"); + result[1].value.vt = VT_UI1|VT_VECTOR; + result[1].value.u.caub.cElems = data_size; + result[1].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, data_size); + memcpy(result[1].value.u.caub.pElems, data, data_size); + + HeapFree(GetProcessHeap(), 0, data); + + *items = result; + *count = 2; + + return S_OK; +} + +static const MetadataHandlerVtbl APEReader_Vtbl = { + 0, + &CLSID_WICAPEMetadataReader, + load_APE_metadata +}; + +HRESULT APEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) +{ + return MetadataReader_Create(&APEReader_Vtbl, pUnkOuter, iid, ppv); +} + static IStream *create_stream(const void *data, int data_size) { HRESULT hr; diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c index a7ac4b2a44..47e522c356 100644 --- a/dlls/windowscodecs/regsvr.c +++ b/dlls/windowscodecs/regsvr.c @@ -1562,6 +1562,21 @@ static const struct reader_containers gce_containers[] = { { NULL } /* list terminator */ }; +static const BYTE ape_magic[] = { 0x21, 0xff, 0x0b }; + +static const struct metadata_pattern ape_metadata_pattern[] = { + { 0, 3, ape_magic, mask_all, 0 }, + { 0 } +}; + +static const struct reader_containers ape_containers[] = { + { + &GUID_ContainerFormatGif, + ape_metadata_pattern + }, + { NULL } /* list terminator */ +}; + static struct regsvr_metadatareader const metadatareader_list[] = { { &CLSID_WICUnknownMetadataReader, "The Wine Project", @@ -1623,6 +1638,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = { 0, 0, 0, gce_containers }, + { &CLSID_WICAPEMetadataReader, + "The Wine Project", + "Application Extension Reader", + "1.0.0.0", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_MetadataFormatAPE, + 0, 0, 0, + ape_containers + }, { NULL } /* list terminator */ }; diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index b62b96e4e7..27a8dcf6f5 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -1657,7 +1657,6 @@ static void test_metadata_APE(void) hr = CoCreateInstance(&CLSID_WICAPEMetadataReader, NULL, CLSCTX_INPROC_SERVER, &IID_IWICMetadataReader, (void **)&reader); -todo_wine ok(hr == S_OK || broken(hr == E_NOINTERFACE || hr == REGDB_E_CLASSNOTREG) /* before Win7 */, "CoCreateInstance error %#x\n", hr); diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index b712b2f9f2..406a3fadf6 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -98,5 +98,6 @@ extern HRESULT PngTextReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, voi extern HRESULT LSDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN; extern HRESULT IMDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN; extern HRESULT GCEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN; +extern HRESULT APEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN; #endif /* WINCODECS_PRIVATE_H */ diff --git a/dlls/windowscodecs/windowscodecs_wincodec.idl b/dlls/windowscodecs/windowscodecs_wincodec.idl index e109bf2b23..7ca2235c13 100644 --- a/dlls/windowscodecs/windowscodecs_wincodec.idl +++ b/dlls/windowscodecs/windowscodecs_wincodec.idl @@ -163,3 +163,10 @@ coclass WICIMDMetadataReader { interface IWICMetadataReader; } uuid(b92e345d-f52d-41f3-b562-081bc772e3b9) ] coclass WICGCEMetadataReader { interface IWICMetadataReader; } + +[ + helpstring("WIC Application Extension Reader"), + threading(both), + uuid(1767b93a-b021-44ea-920f-863c11f4f768) +] +coclass WICAPEMetadataReader { interface IWICMetadataReader; }