From f88231b96ba2761a5e5354108919f71d3b130099 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Thu, 28 Jun 2012 13:28:34 +0900 Subject: [PATCH] gdiplus: Add a bunch of tests for TIFF image properties. --- dlls/gdiplus/tests/image.c | 251 +++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c index 274098fcfaf..8c972eef512 100644 --- a/dlls/gdiplus/tests/image.c +++ b/dlls/gdiplus/tests/image.c @@ -22,6 +22,7 @@ #include #include +#include #include "initguid.h" #include "windows.h" @@ -2860,6 +2861,255 @@ static void test_image_properties(void) } } +#define IFD_BYTE 1 +#define IFD_ASCII 2 +#define IFD_SHORT 3 +#define IFD_LONG 4 +#define IFD_RATIONAL 5 +#define IFD_SBYTE 6 +#define IFD_UNDEFINED 7 +#define IFD_SSHORT 8 +#define IFD_SLONG 9 +#define IFD_SRATIONAL 10 +#define IFD_FLOAT 11 +#define IFD_DOUBLE 12 + +#ifndef PropertyTagTypeSByte +#define PropertyTagTypeSByte 6 +#define PropertyTagTypeSShort 8 +#define PropertyTagTypeFloat 11 +#define PropertyTagTypeDouble 12 +#endif + +static UINT documented_type(UINT type) +{ + switch (type) + { + case PropertyTagTypeSByte: return PropertyTagTypeByte; + case PropertyTagTypeSShort: return PropertyTagTypeShort; + case PropertyTagTypeFloat: return PropertyTagTypeUndefined; + case PropertyTagTypeDouble: return PropertyTagTypeUndefined; + default: return type; + } +} + +#include "pshpack2.h" +struct IFD_entry +{ + SHORT id; + SHORT type; + ULONG count; + LONG value; +}; + +struct IFD_rational +{ + LONG numerator; + LONG denominator; +}; + +static const struct tiff_data +{ + USHORT byte_order; + USHORT version; + ULONG dir_offset; + USHORT number_of_entries; + struct IFD_entry entry[40]; + ULONG next_IFD; + struct IFD_rational xres; + DOUBLE double_val; + struct IFD_rational srational_val; + char string[14]; + SHORT short_val[4]; + LONG long_val[2]; + FLOAT float_val[2]; + struct IFD_rational rational[3]; + BYTE pixel_data[4]; +} TIFF_data = +{ +#ifdef WORDS_BIGENDIAN + 'M' | 'M' << 8, +#else + 'I' | 'I' << 8, +#endif + 42, + FIELD_OFFSET(struct tiff_data, number_of_entries), + 31, + { + { 0xff, IFD_SHORT, 1, 0 }, /* SUBFILETYPE */ + { 0x100, IFD_LONG, 1, 1 }, /* IMAGEWIDTH */ + { 0x101, IFD_LONG, 1, 1 }, /* IMAGELENGTH */ + { 0x102, IFD_SHORT, 1, 1 }, /* BITSPERSAMPLE */ + { 0x103, IFD_LONG, 1, 1 }, /* COMPRESSION */ + { 0x106, IFD_SHORT, 1, 1 }, /* PHOTOMETRIC */ + { 0x111, IFD_LONG, 1, FIELD_OFFSET(struct tiff_data, pixel_data) }, /* STRIPOFFSETS */ + { 0x115, IFD_SHORT, 1, 1 }, /* SAMPLESPERPIXEL */ + { 0x116, IFD_LONG, 1, 1 }, /* ROWSPERSTRIP */ + { 0x117, IFD_LONG, 1, 1 }, /* STRIPBYTECOUNT */ + { 0x11a, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_data, xres) }, + { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_data, xres) }, + { 0x128, IFD_SHORT, 1, 2 }, /* RESOLUTIONUNIT */ + { 0xf001, IFD_BYTE, 1, 0x11223344 }, + { 0xf002, IFD_BYTE, 4, 0x11223344 }, + { 0xf003, IFD_SBYTE, 1, 0x11223344 }, + { 0xf004, IFD_SSHORT, 1, 0x11223344 }, + { 0xf005, IFD_SSHORT, 2, 0x11223344 }, + { 0xf006, IFD_SLONG, 1, 0x11223344 }, + { 0xf007, IFD_FLOAT, 1, 0x11223344 }, + { 0xf008, IFD_DOUBLE, 1, FIELD_OFFSET(struct tiff_data, double_val) }, + { 0xf009, IFD_SRATIONAL, 1, FIELD_OFFSET(struct tiff_data, srational_val) }, + { 0xf00a, IFD_BYTE, 13, FIELD_OFFSET(struct tiff_data, string) }, + { 0xf00b, IFD_SSHORT, 4, FIELD_OFFSET(struct tiff_data, short_val) }, + { 0xf00c, IFD_SLONG, 2, FIELD_OFFSET(struct tiff_data, long_val) }, + { 0xf00e, IFD_ASCII, 13, FIELD_OFFSET(struct tiff_data, string) }, + { 0xf00f, IFD_ASCII, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 }, + { 0xf010, IFD_UNDEFINED, 13, FIELD_OFFSET(struct tiff_data, string) }, + { 0xf011, IFD_UNDEFINED, 4, 'a' | 'b' << 8 | 'c' << 16 | 'd' << 24 }, + /* Some gdiplus versions ignore these fields. + { 0xf012, IFD_BYTE, 0, 0x11223344 }, + { 0xf013, IFD_SHORT, 0, 0x11223344 }, + { 0xf014, IFD_LONG, 0, 0x11223344 }, + { 0xf015, IFD_FLOAT, 0, 0x11223344 },*/ + { 0xf016, IFD_SRATIONAL, 3, FIELD_OFFSET(struct tiff_data, rational) }, + /* Win7 before SP1 doesn't recognize this field, everybody else does. */ + { 0xf017, IFD_FLOAT, 2, FIELD_OFFSET(struct tiff_data, float_val) }, + }, + 0, + { 900, 3 }, + 1234567890.0987654321, + { 0x1a2b3c4d, 0x5a6b7c8d }, + "Hello World!", + { 0x0101, 0x0202, 0x0303, 0x0404 }, + { 0x11223344, 0x55667788 }, + { (FLOAT)1234.5678, (FLOAT)8765.4321 }, + { { 0x01020304, 0x05060708 }, { 0x10203040, 0x50607080 }, { 0x11223344, 0x55667788 } }, + { 0x11, 0x22, 0x33, 0 } +}; +#include "poppack.h" + +static void test_tiff_properties(void) +{ + static const struct test_data + { + ULONG type, id, length; + const BYTE value[24]; + } td[31] = + { + { PropertyTagTypeShort, 0xff, 2, { 0 } }, + { PropertyTagTypeLong, 0x100, 4, { 1 } }, + { PropertyTagTypeLong, 0x101, 4, { 1 } }, + { PropertyTagTypeShort, 0x102, 2, { 1 } }, + { PropertyTagTypeLong, 0x103, 4, { 1 } }, + { PropertyTagTypeShort, 0x106, 2, { 1 } }, + { PropertyTagTypeLong, 0x111, 4, { 0x44,0x02 } }, + { PropertyTagTypeShort, 0x115, 2, { 1 } }, + { PropertyTagTypeLong, 0x116, 4, { 1 } }, + { PropertyTagTypeLong, 0x117, 4, { 1 } }, + { PropertyTagTypeRational, 0x11a, 8, { 0x84,0x03,0,0,0x03 } }, + { PropertyTagTypeRational, 0x11b, 8, { 0x84,0x03,0,0,0x03 } }, + { PropertyTagTypeShort, 0x128, 2, { 2 } }, + { PropertyTagTypeByte, 0xf001, 1, { 0x44 } }, + { PropertyTagTypeByte, 0xf002, 4, { 0x44,0x33,0x22,0x11 } }, + { PropertyTagTypeSByte, 0xf003, 1, { 0x44 } }, + { PropertyTagTypeSShort, 0xf004, 2, { 0x44,0x33 } }, + { PropertyTagTypeSShort, 0xf005, 4, { 0x44,0x33,0x22,0x11 } }, + { PropertyTagTypeSLONG, 0xf006, 4, { 0x44,0x33,0x22,0x11 } }, + { PropertyTagTypeFloat, 0xf007, 4, { 0x44,0x33,0x22,0x11 } }, + { PropertyTagTypeDouble, 0xf008, 8, { 0x2c,0x52,0x86,0xb4,0x80,0x65,0xd2,0x41 } }, + { PropertyTagTypeSRational, 0xf009, 8, { 0x4d, 0x3c, 0x2b, 0x1a, 0x8d, 0x7c, 0x6b, 0x5a } }, + { PropertyTagTypeByte, 0xf00a, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } }, + { PropertyTagTypeSShort, 0xf00b, 8, { 0x01,0x01,0x02,0x02,0x03,0x03,0x04,0x04 } }, + { PropertyTagTypeSLONG, 0xf00c, 8, { 0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55 } }, + { PropertyTagTypeASCII, 0xf00e, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } }, + { PropertyTagTypeASCII, 0xf00f, 5, { 'a','b','c','d' } }, + { PropertyTagTypeUndefined, 0xf010, 13, { 'H','e','l','l','o',' ','W','o','r','l','d','!',0 } }, + { PropertyTagTypeUndefined, 0xf011, 4, { 'a','b','c','d' } }, + { PropertyTagTypeSRational, 0xf016, 24, + { 0x04,0x03,0x02,0x01,0x08,0x07,0x06,0x05, + 0x40,0x30,0x20,0x10,0x80,0x70,0x60,0x50, + 0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55 } }, + /* Win7 before SP1 doesn't recognize this field, everybody else does. */ + { PropertyTagTypeFloat, 0xf017, 8, { 0x2b,0x52,0x9a,0x44,0xba,0xf5,0x08,0x46 } }, + }; + GpStatus status; + GpImage *image; + GUID guid; + UINT dim_count, frame_count, prop_count, prop_size, i; + PROPID *prop_id; + PropertyItem *prop_item; + + image = load_image((const BYTE *)&TIFF_data, sizeof(TIFF_data)); + ok(image != 0, "Failed to load TIFF image data\n"); + if (!image) return; + + status = GdipImageGetFrameDimensionsCount(image, &dim_count); + expect(Ok, status); + expect(1, dim_count); + + status = GdipImageGetFrameDimensionsList(image, &guid, 1); + expect(Ok, status); + expect_guid(&FrameDimensionPage, &guid, __LINE__, FALSE); + + frame_count = 0xdeadbeef; + status = GdipImageGetFrameCount(image, &guid, &frame_count); + expect(Ok, status); + expect(1, frame_count); + + prop_count = 0xdeadbeef; + status = GdipGetPropertyCount(image, &prop_count); + expect(Ok, status); + ok(prop_count == sizeof(td)/sizeof(td[0]) || + broken(prop_count == sizeof(td)/sizeof(td[0]) - 1) /* Win7 SP0 */, + "expected property count %u, got %u\n", (UINT)(sizeof(td)/sizeof(td[0])), prop_count); + + prop_id = HeapAlloc(GetProcessHeap(), 0, prop_count * sizeof(*prop_id)); + + status = GdipGetPropertyIdList(image, prop_count, prop_id); + expect(Ok, status); + + for (i = 0; i < prop_count; i++) + { + status = GdipGetPropertyItemSize(image, prop_id[i], &prop_size); + expect(Ok, status); + if (status != Ok) break; + ok(prop_size > sizeof(*prop_item), "%u: too small item length %u\n", i, prop_size); + + prop_item = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, prop_size); + status = GdipGetPropertyItem(image, prop_id[i], prop_size, prop_item); + expect(Ok, status); + ok(td[i].type == prop_item->type || + /* Win7 stopped using proper but not documented types, and it's + looks broken since TypeFloat and TypeDouble now reported as + TypeUndefined, and signed types reported as unsigned. */ + broken(prop_item->type == documented_type(td[i].type)), + "%u: expected type %u, got %u\n", i, td[i].type, prop_item->type); + ok(td[i].id == prop_item->id, "%u: expected id %#x, got %#x\n", i, td[i].id, prop_item->id); + prop_size -= sizeof(*prop_item); + ok(prop_item->length == prop_size, "%u: expected length %u, got %u\n", i, prop_size, prop_item->length); + ok(td[i].length == prop_item->length, "%u: expected length %u, got %u\n", i, td[i].length, prop_item->length); + ok(td[i].length == prop_size, "%u: expected length %u, got %u\n", i, td[i].length, prop_size); + if (td[i].length == prop_item->length) + { + int match = memcmp(td[i].value, prop_item->value, td[i].length) == 0; + ok(match || broken(td[i].length <= 4 && !match), "%u: data mismatch\n", i); + if (!match) + { + UINT j; + BYTE *data = prop_item->value; + printf("id %#x:", prop_item->id); + for (j = 0; j < prop_item->length; j++) + printf(" %02x", data[j]); + printf("\n"); + } + } + HeapFree(GetProcessHeap(), 0, prop_item); + } + + HeapFree(GetProcessHeap(), 0, prop_id); + + GdipDisposeImage(image); +} + START_TEST(image) { struct GdiplusStartupInput gdiplusStartupInput; @@ -2872,6 +3122,7 @@ START_TEST(image) GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + test_tiff_properties(); test_image_properties(); test_Scan0(); test_FromGdiDib();