[7/8] windowscodecs: Add a test for endianness support in IFD metadata reader, fix handling of affected IFD field types.
Dmitry Timoshkov
dmitry at baikal.ru
Fri Jun 15 23:23:54 CDT 2012
---
dlls/windowscodecs/metadatahandler.c | 21 ++-
dlls/windowscodecs/tests/metadata.c | 276 ++++++++++++++++++++++++++--------
2 files changed, 229 insertions(+), 68 deletions(-)
diff --git a/dlls/windowscodecs/metadatahandler.c b/dlls/windowscodecs/metadatahandler.c
index a30f86d..b21c76f 100644
--- a/dlls/windowscodecs/metadatahandler.c
+++ b/dlls/windowscodecs/metadatahandler.c
@@ -725,10 +725,13 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry,
if (count <= 2)
{
- const SHORT *data = (const SHORT *)&value;
+ const SHORT *data = (const SHORT *)&entry->value;
if (count == 1)
+ {
item->value.u.uiVal = data[0];
+ SWAP_USHORT(item->value.u.uiVal);
+ }
else
{
item->value.vt |= VT_VECTOR;
@@ -806,16 +809,24 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry,
if (count == 1)
{
- struct IFD_rational rational;
+ ULONGLONG ull;
pos.QuadPart = value;
hr = IStream_Seek(input, pos, SEEK_SET, NULL);
if (FAILED(hr)) return hr;
- hr = IStream_Read(input, &rational, sizeof(rational), NULL);
+ hr = IStream_Read(input, &ull, sizeof(ull), NULL);
if (FAILED(hr)) return hr;
- item->value.u.uhVal.QuadPart = ((LONGLONG)rational.denominator << 32) | rational.numerator;
- SWAP_ULONGLONG(item->value.u.uhVal.QuadPart);
+
+ item->value.u.uhVal.QuadPart = ull;
+
+ if (type == IFD_DOUBLE)
+ SWAP_ULONGLONG(item->value.u.uhVal.QuadPart);
+ else
+ {
+ SWAP_ULONG(item->value.u.uhVal.u.LowPart);
+ SWAP_ULONG(item->value.u.uhVal.u.HighPart);
+ }
break;
}
FIXME("loading multiple rational fields is not implemented\n");
diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c
index 8ca2c01..97f90b1 100644
--- a/dlls/windowscodecs/tests/metadata.c
+++ b/dlls/windowscodecs/tests/metadata.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
+#include <assert.h>
#define COBJMACROS
@@ -177,7 +178,7 @@ static IStream *create_stream(const char *data, int data_size)
return stream;
}
-static void load_stream(IUnknown *reader, const char *data, int data_size)
+static void load_stream(IUnknown *reader, const char *data, int data_size, DWORD persist_options)
{
HRESULT hr;
IWICPersistStream *persist;
@@ -194,7 +195,7 @@ static void load_stream(IUnknown *reader, const char *data, int data_size)
if (SUCCEEDED(hr))
{
- hr = IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
+ hr = IWICPersistStream_LoadEx(persist, stream, NULL, persist_options);
ok(hr == S_OK, "LoadEx failed, hr=%x\n", hr);
IWICPersistStream_Release(persist);
@@ -224,7 +225,7 @@ static void test_metadata_unknown(void)
ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
if (FAILED(hr)) return;
- load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown));
+ load_stream((IUnknown*)reader, metadata_unknown, sizeof(metadata_unknown), WICPersistOptionsDefault);
hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
ok(hr == S_OK, "GetEnumerator failed, hr=%x\n", hr);
@@ -291,7 +292,7 @@ static void test_metadata_tEXt(void)
ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
ok(count == 0, "unexpected count %i\n", count);
- load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt));
+ load_stream((IUnknown*)reader, metadata_tEXt, sizeof(metadata_tEXt), WICPersistOptionsDefault);
hr = IWICMetadataReader_GetCount(reader, &count);
ok(hr == S_OK, "GetCount failed, hr=%x\n", hr);
@@ -384,71 +385,128 @@ static void test_metadata_tEXt(void)
IWICMetadataReader_Release(reader);
}
-static void test_metadata_IFD(void)
+static inline USHORT ushort_bswap(USHORT s)
{
- static const struct test_data
- {
- ULONG type, id;
- int count; /* if VT_VECTOR */
- LONGLONG value[13];
- const char *string;
- } td[26] =
+ return (s >> 8) | (s << 8);
+}
+
+static inline ULONG ulong_bswap(ULONG l)
+{
+ return ((ULONG)ushort_bswap((USHORT)l) << 16) | ushort_bswap((USHORT)(l >> 16));
+}
+
+static inline ULONGLONG ulonglong_bswap(ULONGLONG ll)
+{
+ return ((ULONGLONG)ulong_bswap((ULONG)ll) << 32) | ulong_bswap((ULONG)(ll >> 32));
+}
+
+static void byte_swap_ifd_data(char *data)
+{
+ USHORT number_of_entries, i;
+ struct IFD_entry *entry;
+ char *data_start = data;
+
+ number_of_entries = *(USHORT *)data;
+ *(USHORT *)data = ushort_bswap(*(USHORT *)data);
+ data += sizeof(USHORT);
+
+ for (i = 0; i < number_of_entries; i++)
{
- { VT_UI2, 0xfe, 0, { 1 } },
- { VT_UI4, 0x100, 0, { 222 } },
- { VT_UI4, 0x101, 0, { 333 } },
- { VT_UI2, 0x102, 0, { 24 } },
- { VT_UI4, 0x103, 0, { 32773 } },
- { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
- { VT_UI1, 0xf001, 0, { 0x44 } },
- { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
- { VT_I1, 0xf003, 0, { 0x44 } },
- { VT_I2, 0xf004, 0, { 0x3344 } },
- { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
- { VT_I4, 0xf006, 0, { 0x11223344 } },
- { VT_R4, 0xf007, 0, { 0x11223344 } },
- { VT_R8, 0xf008, 0, { ((LONGLONG)3 << 32) | 900 } },
- { VT_I8, 0xf009, 0, { ((LONGLONG)3 << 32) | 900 } },
- { VT_LPSTR, 0xf00a, 12, { 0 }, "Hello World!" },
- { VT_UI1|VT_VECTOR, 0xf00b, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
- { VT_I2|VT_VECTOR, 0xf00c, 4, { 900, 0, 3, 0 } },
- { VT_I4|VT_VECTOR, 0xf00d, 2, { 900, 3 } },
- { VT_R4|VT_VECTOR, 0xf00e, 2, { 900, 3 } },
- { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
- { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
- { VT_UI1, 0xf011, 0, { 0x44 } },
- { VT_UI2, 0xf012, 0, { 0x3344 } },
- { VT_UI4, 0xf013, 0, { 0x11223344 } },
- { VT_R4, 0xf014, 0, { 0x11223344 } },
- };
- HRESULT hr;
- IWICMetadataReader *reader;
- IWICMetadataBlockReader *blockreader;
- IWICEnumMetadataItem *enumerator;
- PROPVARIANT schema, id, value;
- ULONG items_returned, count, i;
- GUID format;
+ entry = (struct IFD_entry *)data;
- PropVariantInit(&schema);
- PropVariantInit(&id);
- PropVariantInit(&value);
+ switch (entry->type)
+ {
+ case IFD_BYTE:
+ case IFD_SBYTE:
+ case IFD_ASCII:
+ case IFD_UNDEFINED:
+ if (entry->count > 4)
+ entry->value = ulong_bswap(entry->value);
+ break;
+
+ case IFD_SHORT:
+ case IFD_SSHORT:
+ if (entry->count > 2)
+ {
+ ULONG j, count = entry->count;
+ USHORT *us = (USHORT *)(data_start + entry->value);
+ if (!count) count = 1;
+ for (j = 0; j < count; j++)
+ us[j] = ushort_bswap(us[j]);
- hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
- &IID_IWICMetadataReader, (void**)&reader);
- ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
+ entry->value = ulong_bswap(entry->value);
+ }
+ else
+ {
+ ULONG j, count = entry->count;
+ USHORT *us = (USHORT *)&entry->value;
+ if (!count) count = 1;
+ for (j = 0; j < count; j++)
+ us[j] = ushort_bswap(us[j]);
+ }
+ break;
- hr = IWICMetadataReader_GetCount(reader, NULL);
- ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
+ case IFD_LONG:
+ case IFD_SLONG:
+ case IFD_FLOAT:
+ if (entry->count > 1)
+ {
+ ULONG j, count = entry->count;
+ ULONG *ul = (ULONG *)(data_start + entry->value);
+ if (!count) count = 1;
+ for (j = 0; j < count; j++)
+ ul[j] = ulong_bswap(ulong_bswap(ul[j]));
+ }
+ entry->value = ulong_bswap(entry->value);
+ break;
- hr = IWICMetadataReader_GetCount(reader, &count);
- ok(hr == S_OK, "GetCount error %#x\n", hr);
- ok(count == 0, "unexpected count %u\n", count);
+ case IFD_RATIONAL:
+ case IFD_SRATIONAL:
+ {
+ ULONG j;
+ ULONG *ul = (ULONG *)(data_start + entry->value);
+ for (j = 0; j < entry->count * 2; j++)
+ ul[j] = ulong_bswap(ul[j]);
+ }
+ entry->value = ulong_bswap(entry->value);
+ break;
- load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data));
+ case IFD_DOUBLE:
+ {
+ ULONG j;
+ ULONGLONG *ull = (ULONGLONG *)(data_start + entry->value);
+ for (j = 0; j < entry->count; j++)
+ ull[j] = ulonglong_bswap(ull[j]);
+ }
+ entry->value = ulong_bswap(entry->value);
+ break;
- hr = IWICMetadataReader_GetCount(reader, &count);
- ok(hr == S_OK, "GetCount error %#x\n", hr);
- ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
+ default:
+ assert(0);
+ break;
+ }
+
+ entry->id = ushort_bswap(entry->id);
+ entry->type = ushort_bswap(entry->type);
+ entry->count = ulong_bswap(entry->count);
+ data += sizeof(*entry);
+ }
+}
+
+struct test_data
+{
+ ULONG type, id;
+ int count; /* if VT_VECTOR */
+ LONGLONG value[13];
+ const char *string;
+};
+
+static void compare_ifd_metadata(IWICMetadataReader *reader, const struct test_data *td, ULONG count)
+{
+ HRESULT hr;
+ IWICEnumMetadataItem *enumerator;
+ PROPVARIANT schema, id, value;
+ ULONG items_returned, i;
hr = IWICMetadataReader_GetEnumerator(reader, NULL);
ok(hr == E_INVALIDARG, "GetEnumerator error %#x\n", hr);
@@ -456,6 +514,10 @@ static void test_metadata_IFD(void)
hr = IWICMetadataReader_GetEnumerator(reader, &enumerator);
ok(hr == S_OK, "GetEnumerator error %#x\n", hr);
+ PropVariantInit(&schema);
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
for (i = 0; i < count; i++)
{
hr = IWICEnumMetadataItem_Next(enumerator, 1, &schema, &id, &value, &items_returned);
@@ -515,7 +577,8 @@ static void test_metadata_IFD(void)
ok(!memcmp(td[i].string, U(value).blob.pBlobData, td[i].count), "%u: expected %s, got %s\n", i, td[i].string, U(value).blob.pBlobData);
}
else
- ok(U(value).uhVal.QuadPart == td[i].value[0], "%u: unexpected value: %d/%d\n", i, U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
+ ok(U(value).uhVal.QuadPart == td[i].value[0], "%u: expected value %#x/%#x got %#x/%#x\n",
+ i, (UINT)td[i].value[0], (UINT)(td[i].value[0] >> 32), U(value).uhVal.u.LowPart, U(value).uhVal.u.HighPart);
PropVariantClear(&schema);
PropVariantClear(&id);
@@ -527,6 +590,89 @@ static void test_metadata_IFD(void)
ok(items_returned == 0, "unexpected item count %u\n", items_returned);
IWICEnumMetadataItem_Release(enumerator);
+}
+
+static void test_metadata_IFD(void)
+{
+ static const struct test_data td[26] =
+ {
+ { VT_UI2, 0xfe, 0, { 1 } },
+ { VT_UI4, 0x100, 0, { 222 } },
+ { VT_UI4, 0x101, 0, { 333 } },
+ { VT_UI2, 0x102, 0, { 24 } },
+ { VT_UI4, 0x103, 0, { 32773 } },
+ { VT_UI8, 0x11a, 0, { ((LONGLONG)3 << 32) | 900 } },
+ { VT_UI1, 0xf001, 0, { 0x44 } },
+ { VT_UI1|VT_VECTOR, 0xf002, 4, { 0x44, 0x33, 0x22, 0x11 } },
+ { VT_I1, 0xf003, 0, { 0x44 } },
+ { VT_I2, 0xf004, 0, { 0x3344 } },
+ { VT_I2|VT_VECTOR, 0xf005, 2, { 0x3344, 0x1122 } },
+ { VT_I4, 0xf006, 0, { 0x11223344 } },
+ { VT_R4, 0xf007, 0, { 0x11223344 } },
+ { VT_R8, 0xf008, 0, { ((LONGLONG)3 << 32) | 900 } },
+ { VT_I8, 0xf009, 0, { ((LONGLONG)3 << 32) | 900 } },
+ { VT_LPSTR, 0xf00a, 12, { 0 }, "Hello World!" },
+ { VT_UI1|VT_VECTOR, 0xf00b, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } },
+ { VT_I2|VT_VECTOR, 0xf00c, 4, { 900, 0, 3, 0 } },
+ { VT_I4|VT_VECTOR, 0xf00d, 2, { 900, 3 } },
+ { VT_R4|VT_VECTOR, 0xf00e, 2, { 900, 3 } },
+ { VT_LPSTR, 0xf00f, 4, { 0 }, "abcd" },
+ { VT_BLOB, 0xf010, 13, { 0 }, "Hello World!" },
+ { VT_UI1, 0xf011, 0, { 0x44 } },
+ { VT_UI2, 0xf012, 0, { 0x3344 } },
+ { VT_UI4, 0xf013, 0, { 0x11223344 } },
+ { VT_R4, 0xf014, 0, { 0x11223344 } },
+ };
+ HRESULT hr;
+ IWICMetadataReader *reader;
+ IWICMetadataBlockReader *blockreader;
+ PROPVARIANT schema, id, value;
+ ULONG count;
+ GUID format;
+ char *IFD_data_swapped;
+#ifdef WORDS_BIGENDIAN
+ DWORD persist_options = WICPersistOptionsBigEndian;
+#else
+ DWORD persist_options = WICPersistOptionsLittleEndian;
+#endif
+
+ hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IWICMetadataReader, (void**)&reader);
+ ok(hr == S_OK, "CoCreateInstance error %#x\n", hr);
+
+ hr = IWICMetadataReader_GetCount(reader, NULL);
+ ok(hr == E_INVALIDARG, "GetCount error %#x\n", hr);
+
+ hr = IWICMetadataReader_GetCount(reader, &count);
+ ok(hr == S_OK, "GetCount error %#x\n", hr);
+ ok(count == 0, "unexpected count %u\n", count);
+
+ load_stream((IUnknown*)reader, (const char *)&IFD_data, sizeof(IFD_data), persist_options);
+
+ hr = IWICMetadataReader_GetCount(reader, &count);
+ ok(hr == S_OK, "GetCount error %#x\n", hr);
+ ok(count == sizeof(td)/sizeof(td[0]), "unexpected count %u\n", count);
+
+ compare_ifd_metadata(reader, td, count);
+
+ /* test IFD data with different endianness */
+ if (persist_options == WICPersistOptionsLittleEndian)
+ persist_options = WICPersistOptionsBigEndian;
+ else
+ persist_options = WICPersistOptionsLittleEndian;
+
+ IFD_data_swapped = HeapAlloc(GetProcessHeap(), 0, sizeof(IFD_data));
+ memcpy(IFD_data_swapped, &IFD_data, sizeof(IFD_data));
+ /* FIXME: since many fields reuse the same data avoid double conversion problems */
+ *(SHORT *)IFD_data_swapped = 13;
+ *(LONG *)(IFD_data_swapped + sizeof(SHORT) + 13 * sizeof(struct IFD_entry)) = 0;
+ byte_swap_ifd_data(IFD_data_swapped);
+ load_stream((IUnknown*)reader, IFD_data_swapped, sizeof(IFD_data), persist_options);
+ hr = IWICMetadataReader_GetCount(reader, &count);
+ ok(hr == S_OK, "GetCount error %#x\n", hr);
+ ok(count == 13, "expected count 13, got %u\n", count);
+ compare_ifd_metadata(reader, td, 13);
+ HeapFree(GetProcessHeap(), 0, IFD_data_swapped);
hr = IWICMetadataReader_GetMetadataFormat(reader, &format);
todo_wine
@@ -546,6 +692,10 @@ todo_wine
return;
}
+ PropVariantInit(&schema);
+ PropVariantInit(&id);
+ PropVariantInit(&value);
+
hr = IWICMetadataReader_GetValueByIndex(reader, count - 1, NULL, NULL, NULL);
ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
@@ -566,7 +716,7 @@ todo_wine
hr = IWICMetadataReader_GetValueByIndex(reader, 0, NULL, NULL, &value);
ok(hr == S_OK, "GetValueByIndex error %#x\n", hr);
ok(value.vt == VT_UI2, "unexpected vt: %u\n", value.vt);
- ok(U(value).ulVal == 1, "unexpected id: %u\n", U(value).ulVal);
+ ok(U(value).uiVal == 1, "unexpected id: %#x\n", U(value).uiVal);
PropVariantClear(&value);
hr = IWICMetadataReader_GetValueByIndex(reader, count, &schema, NULL, NULL);
--
1.7.10.1
More information about the wine-patches
mailing list