windowscodecs: Implement PNG tEXt metadata reader.
This commit is contained in:
parent
4038cb79b4
commit
1a032a94df
|
@ -61,6 +61,7 @@ static const classinfo wic_classes[] = {
|
||||||
{&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance},
|
{&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance},
|
||||||
{&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance},
|
{&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance},
|
||||||
{&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance},
|
{&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance},
|
||||||
|
{&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance},
|
||||||
{0}};
|
{0}};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -255,6 +255,11 @@ static int propvar_cmp(const PROPVARIANT *v1, const PROPVARIANT *v2)
|
||||||
{
|
{
|
||||||
LONGLONG value1, value2;
|
LONGLONG value1, value2;
|
||||||
|
|
||||||
|
if (v1->vt == VT_LPSTR && v2->vt == VT_LPSTR)
|
||||||
|
{
|
||||||
|
return lstrcmpA(v1->u.pszVal, v2->u.pszVal);
|
||||||
|
}
|
||||||
|
|
||||||
if (!get_int_value(v1, &value1)) return -1;
|
if (!get_int_value(v1, &value1)) return -1;
|
||||||
if (!get_int_value(v2, &value2)) return -1;
|
if (!get_int_value(v2, &value2)) return -1;
|
||||||
|
|
||||||
|
@ -446,7 +451,7 @@ static const IWICPersistStreamVtbl MetadataHandler_PersistStream_Vtbl = {
|
||||||
MetadataHandler_SaveEx
|
MetadataHandler_SaveEx
|
||||||
};
|
};
|
||||||
|
|
||||||
static HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv)
|
HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv)
|
||||||
{
|
{
|
||||||
MetadataHandler *This;
|
MetadataHandler *This;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
|
@ -40,6 +40,118 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
|
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
|
||||||
|
|
||||||
|
static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size)
|
||||||
|
{
|
||||||
|
BYTE header[8];
|
||||||
|
HRESULT hr;
|
||||||
|
ULONG bytesread;
|
||||||
|
|
||||||
|
hr = IStream_Read(stream, header, 8, &bytesread);
|
||||||
|
if (FAILED(hr) || bytesread < 8)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = E_FAIL;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data_size = header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3];
|
||||||
|
|
||||||
|
memcpy(type, &header[4], 4);
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
*data = HeapAlloc(GetProcessHeap(), 0, *data_size);
|
||||||
|
if (!*data)
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
hr = IStream_Read(stream, *data, *data_size, &bytesread);
|
||||||
|
|
||||||
|
if (FAILED(hr) || bytesread < *data_size)
|
||||||
|
{
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = E_FAIL;
|
||||||
|
HeapFree(GetProcessHeap(), 0, *data);
|
||||||
|
*data = NULL;
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Verify the CRC? */
|
||||||
|
}
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor,
|
||||||
|
DWORD persist_options, MetadataItem **items, DWORD *item_count)
|
||||||
|
{
|
||||||
|
HRESULT hr;
|
||||||
|
BYTE type[4];
|
||||||
|
BYTE *data;
|
||||||
|
ULONG data_size;
|
||||||
|
ULONG name_len, value_len;
|
||||||
|
BYTE *name_end_ptr;
|
||||||
|
LPSTR name, value;
|
||||||
|
MetadataItem *result;
|
||||||
|
|
||||||
|
hr = read_png_chunk(stream, type, &data, &data_size);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
|
name_end_ptr = memchr(data, 0, data_size);
|
||||||
|
|
||||||
|
name_len = name_end_ptr - data;
|
||||||
|
|
||||||
|
if (!name_end_ptr || name_len > 79)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_len = data_size - name_len - 1;
|
||||||
|
|
||||||
|
result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem));
|
||||||
|
name = HeapAlloc(GetProcessHeap(), 0, name_len + 1);
|
||||||
|
value = HeapAlloc(GetProcessHeap(), 0, value_len + 1);
|
||||||
|
if (!result || !name || !value)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
|
HeapFree(GetProcessHeap(), 0, result);
|
||||||
|
HeapFree(GetProcessHeap(), 0, name);
|
||||||
|
HeapFree(GetProcessHeap(), 0, value);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropVariantInit(&result[0].schema);
|
||||||
|
PropVariantInit(&result[0].id);
|
||||||
|
PropVariantInit(&result[0].value);
|
||||||
|
|
||||||
|
memcpy(name, data, name_len + 1);
|
||||||
|
memcpy(value, name_end_ptr + 1, value_len);
|
||||||
|
value[value_len] = 0;
|
||||||
|
|
||||||
|
result[0].id.vt = VT_LPSTR;
|
||||||
|
result[0].id.pszVal = name;
|
||||||
|
result[0].value.vt = VT_LPSTR;
|
||||||
|
result[0].value.pszVal = value;
|
||||||
|
|
||||||
|
*items = result;
|
||||||
|
*item_count = 1;
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, data);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MetadataHandlerVtbl TextReader_Vtbl = {
|
||||||
|
0,
|
||||||
|
&CLSID_WICPngTextMetadataReader,
|
||||||
|
LoadTextMetadata
|
||||||
|
};
|
||||||
|
|
||||||
|
HRESULT PngTextReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
|
||||||
|
{
|
||||||
|
return MetadataReader_Create(&TextReader_Vtbl, pUnkOuter, iid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SONAME_LIBPNG
|
#ifdef SONAME_LIBPNG
|
||||||
|
|
||||||
static void *libpng_handle;
|
static void *libpng_handle;
|
||||||
|
|
|
@ -1503,6 +1503,21 @@ static const struct reader_containers ifd_containers[] = {
|
||||||
{ NULL } /* list terminator */
|
{ NULL } /* list terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const BYTE tEXt[] = "tEXt";
|
||||||
|
|
||||||
|
static const struct metadata_pattern pngtext_metadata_pattern[] = {
|
||||||
|
{ 4, 4, tEXt, mask_all, 4 },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct reader_containers pngtext_containers[] = {
|
||||||
|
{
|
||||||
|
&GUID_ContainerFormatPng,
|
||||||
|
pngtext_metadata_pattern
|
||||||
|
},
|
||||||
|
{ NULL } /* list terminator */
|
||||||
|
};
|
||||||
|
|
||||||
static struct regsvr_metadatareader const metadatareader_list[] = {
|
static struct regsvr_metadatareader const metadatareader_list[] = {
|
||||||
{ &CLSID_WICUnknownMetadataReader,
|
{ &CLSID_WICUnknownMetadataReader,
|
||||||
"The Wine Project",
|
"The Wine Project",
|
||||||
|
@ -1525,6 +1540,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = {
|
||||||
1, 1, 0,
|
1, 1, 0,
|
||||||
ifd_containers
|
ifd_containers
|
||||||
},
|
},
|
||||||
|
{ &CLSID_WICPngTextMetadataReader,
|
||||||
|
"The Wine Project",
|
||||||
|
"Unknown Metadata Reader",
|
||||||
|
"1.0.0.0",
|
||||||
|
"1.0.0.0",
|
||||||
|
&GUID_VendorMicrosoft,
|
||||||
|
&GUID_MetadataFormatChunktEXt,
|
||||||
|
0, 0, 0,
|
||||||
|
pngtext_containers
|
||||||
|
},
|
||||||
{ NULL } /* list terminator */
|
{ NULL } /* list terminator */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -303,7 +303,7 @@ static void test_metadata_tEXt(void)
|
||||||
|
|
||||||
hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
|
hr = CoCreateInstance(&CLSID_WICPngTextMetadataReader, NULL, CLSCTX_INPROC_SERVER,
|
||||||
&IID_IWICMetadataReader, (void**)&reader);
|
&IID_IWICMetadataReader, (void**)&reader);
|
||||||
todo_wine ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
|
ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
|
||||||
if (FAILED(hr)) return;
|
if (FAILED(hr)) return;
|
||||||
|
|
||||||
hr = IWICMetadataReader_GetCount(reader, NULL);
|
hr = IWICMetadataReader_GetCount(reader, NULL);
|
||||||
|
|
|
@ -90,7 +90,11 @@ typedef struct _MetadataHandlerVtbl
|
||||||
ULARGE_INTEGER *size);
|
ULARGE_INTEGER *size);
|
||||||
} MetadataHandlerVtbl;
|
} MetadataHandlerVtbl;
|
||||||
|
|
||||||
|
extern HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, IUnknown *pUnkOuter, REFIID iid, void** ppv) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
extern HRESULT UnknownMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) DECLSPEC_HIDDEN;
|
extern HRESULT UnknownMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) DECLSPEC_HIDDEN;
|
||||||
extern HRESULT IfdMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN;
|
extern HRESULT IfdMetadataReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
extern HRESULT PngTextReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
#endif /* WINCODECS_PRIVATE_H */
|
#endif /* WINCODECS_PRIVATE_H */
|
||||||
|
|
|
@ -135,3 +135,10 @@ coclass WICUnknownMetadataReader { interface IWICMetadataReader; }
|
||||||
uuid(8f914656-9d0a-4eb2-9019-0bf96d8a9ee6)
|
uuid(8f914656-9d0a-4eb2-9019-0bf96d8a9ee6)
|
||||||
]
|
]
|
||||||
coclass WICIfdMetadataReader { interface IWICIfdMetadataReader; }
|
coclass WICIfdMetadataReader { interface IWICIfdMetadataReader; }
|
||||||
|
|
||||||
|
[
|
||||||
|
helpstring("WIC Png tEXt Metadata Reader"),
|
||||||
|
threading(both),
|
||||||
|
uuid(4b59afcc-b8c3-408a-b670-89e5fab6fda7)
|
||||||
|
]
|
||||||
|
coclass WICPngTextMetadataReader { interface IWICMetadataReader; }
|
||||||
|
|
Loading…
Reference in New Issue