| /* | 
 |  * Copyright 2012 Dmitry Timoshkov | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
 |  */ | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdio.h> | 
 |  | 
 | #define COBJMACROS | 
 |  | 
 | #include "windef.h" | 
 | #include "wincodec.h" | 
 | #include "wine/test.h" | 
 |  | 
 | #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 | 
 |  | 
 | #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_1bpp_data | 
 | { | 
 |     USHORT byte_order; | 
 |     USHORT version; | 
 |     ULONG  dir_offset; | 
 |     USHORT number_of_entries; | 
 |     struct IFD_entry entry[13]; | 
 |     ULONG next_IFD; | 
 |     struct IFD_rational res; | 
 |     BYTE pixel_data[4]; | 
 | } tiff_1bpp_data = | 
 | { | 
 | #ifdef WORDS_BIGENDIAN | 
 |     'M' | 'M' << 8, | 
 | #else | 
 |     'I' | 'I' << 8, | 
 | #endif | 
 |     42, | 
 |     FIELD_OFFSET(struct tiff_1bpp_data, number_of_entries), | 
 |     13, | 
 |     { | 
 |         { 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_SHORT, 1, 1 }, /* COMPRESSION: XP doesn't accept IFD_LONG here */ | 
 |         { 0x106, IFD_SHORT, 1, 1 }, /* PHOTOMETRIC */ | 
 |         { 0x111, IFD_LONG, 1, FIELD_OFFSET(struct tiff_1bpp_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_1bpp_data, res) }, | 
 |         { 0x11b, IFD_RATIONAL, 1, FIELD_OFFSET(struct tiff_1bpp_data, res) }, | 
 |         { 0x128, IFD_SHORT, 1, 2 }, /* RESOLUTIONUNIT */ | 
 |     }, | 
 |     0, | 
 |     { 900, 3 }, | 
 |     { 0x11, 0x22, 0x33, 0 } | 
 | }; | 
 | #include "poppack.h" | 
 |  | 
 | static IWICImagingFactory *factory; | 
 |  | 
 | static const char *debugstr_guid(const GUID *guid) | 
 | { | 
 |     static char buf[50]; | 
 |  | 
 |     if (!guid) return "(null)"; | 
 |     sprintf(buf, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", | 
 |             guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], | 
 |             guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], | 
 |             guid->Data4[5], guid->Data4[6], guid->Data4[7]); | 
 |     return buf; | 
 | } | 
 |  | 
 | static IStream *create_stream(const void *data, int data_size) | 
 | { | 
 |     HRESULT hr; | 
 |     IStream *stream; | 
 |     HGLOBAL hdata; | 
 |     void *locked_data; | 
 |  | 
 |     hdata = GlobalAlloc(GMEM_MOVEABLE, data_size); | 
 |     ok(hdata != 0, "GlobalAlloc failed\n"); | 
 |     if (!hdata) return NULL; | 
 |  | 
 |     locked_data = GlobalLock(hdata); | 
 |     memcpy(locked_data, data, data_size); | 
 |     GlobalUnlock(hdata); | 
 |  | 
 |     hr = CreateStreamOnHGlobal(hdata, TRUE, &stream); | 
 |     ok(hr == S_OK, "CreateStreamOnHGlobal failed, hr=%x\n", hr); | 
 |  | 
 |     return stream; | 
 | } | 
 |  | 
 | static IWICBitmapDecoder *create_decoder(const void *image_data, UINT image_size) | 
 | { | 
 |     HRESULT hr; | 
 |     IStream *stream; | 
 |     IWICBitmapDecoder *decoder = NULL; | 
 |     GUID guid; | 
 |  | 
 |     stream = create_stream(image_data, image_size); | 
 |  | 
 |     hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder); | 
 |     ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr); | 
 |  | 
 |     hr = IWICBitmapDecoder_GetContainerFormat(decoder, &guid); | 
 |     ok(hr == S_OK, "GetContainerFormat error %#x\n", hr); | 
 |     ok(IsEqualGUID(&guid, &GUID_ContainerFormatTiff), "container format is not TIFF\n"); | 
 |  | 
 |     IStream_Release(stream); | 
 |  | 
 |     return decoder; | 
 | } | 
 |  | 
 | static void test_tiff_palette(void) | 
 | { | 
 |     HRESULT hr; | 
 |     IWICBitmapDecoder *decoder; | 
 |     IWICBitmapFrameDecode *frame; | 
 |     IWICPalette *palette; | 
 |     GUID format; | 
 |  | 
 |     decoder = create_decoder(&tiff_1bpp_data, sizeof(tiff_1bpp_data)); | 
 |     ok(decoder != 0, "Failed to load TIFF image data\n"); | 
 |  | 
 |     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); | 
 |     ok(hr == S_OK, "GetFrame error %#x\n", hr); | 
 |  | 
 |     hr = IWICBitmapFrameDecode_GetPixelFormat(frame, &format); | 
 |     ok(hr == S_OK, "GetPixelFormat error %#x\n", hr); | 
 |     ok(IsEqualGUID(&format, &GUID_WICPixelFormatBlackWhite), | 
 |        "got wrong format %s\n", debugstr_guid(&format)); | 
 |  | 
 |     hr = IWICImagingFactory_CreatePalette(factory, &palette); | 
 |     ok(hr == S_OK, "CreatePalette error %#x\n", hr); | 
 |     hr = IWICBitmapFrameDecode_CopyPalette(frame, palette); | 
 |     ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, | 
 |        "expected WINCODEC_ERR_PALETTEUNAVAILABLE, got %#x\n", hr); | 
 |  | 
 |     IWICPalette_Release(palette); | 
 |     IWICBitmapFrameDecode_Release(frame); | 
 |     IWICBitmapDecoder_Release(decoder); | 
 | } | 
 |  | 
 | static void test_QueryCapability(void) | 
 | { | 
 |     HRESULT hr; | 
 |     IStream *stream; | 
 |     IWICBitmapDecoder *decoder; | 
 |     IWICBitmapFrameDecode *frame; | 
 |     static const DWORD exp_caps = WICBitmapDecoderCapabilityCanDecodeAllImages | | 
 |                                   WICBitmapDecoderCapabilityCanDecodeSomeImages | | 
 |                                   WICBitmapDecoderCapabilityCanEnumerateMetadata; | 
 |     static const DWORD exp_caps_xp = WICBitmapDecoderCapabilityCanDecodeAllImages | | 
 |                                      WICBitmapDecoderCapabilityCanDecodeSomeImages; | 
 |     DWORD capability; | 
 |     LARGE_INTEGER pos; | 
 |     ULARGE_INTEGER cur_pos; | 
 |     UINT frame_count; | 
 |  | 
 |     stream = create_stream(&tiff_1bpp_data, sizeof(tiff_1bpp_data)); | 
 |     if (!stream) return; | 
 |  | 
 |     hr = IWICImagingFactory_CreateDecoder(factory, &GUID_ContainerFormatTiff, NULL, &decoder); | 
 |     ok(hr == S_OK, "CreateDecoder error %#x\n", hr); | 
 |  | 
 |     frame_count = 0xdeadbeef; | 
 |     hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); | 
 |     ok(hr == S_OK || broken(hr == E_POINTER) /* XP */, "GetFrameCount error %#x\n", hr); | 
 |     ok(frame_count == 0, "expected 0, got %u\n", frame_count); | 
 |  | 
 |     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); | 
 |     ok(hr == WINCODEC_ERR_FRAMEMISSING || broken(hr == E_POINTER) /* XP */, "expected WINCODEC_ERR_FRAMEMISSING, got %#x\n", hr); | 
 |  | 
 |     pos.QuadPart = 4; | 
 |     hr = IStream_Seek(stream, pos, SEEK_SET, NULL); | 
 |     ok(hr == S_OK, "IStream_Seek error %#x\n", hr); | 
 |  | 
 |     capability = 0xdeadbeef; | 
 |     hr = IWICBitmapDecoder_QueryCapability(decoder, stream, &capability); | 
 |     ok(hr == S_OK, "QueryCapability error %#x\n", hr); | 
 |     ok(capability == exp_caps || capability == exp_caps_xp, | 
 |        "expected %#x, got %#x\n", exp_caps, capability); | 
 |  | 
 |     frame_count = 0xdeadbeef; | 
 |     hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); | 
 |     ok(hr == S_OK, "GetFrameCount error %#x\n", hr); | 
 |     ok(frame_count == 1, "expected 1, got %u\n", frame_count); | 
 |  | 
 |     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); | 
 |     ok(hr == S_OK, "GetFrame error %#x\n", hr); | 
 |     IWICBitmapFrameDecode_Release(frame); | 
 |  | 
 |     pos.QuadPart = 0; | 
 |     hr = IStream_Seek(stream, pos, SEEK_CUR, &cur_pos); | 
 |     ok(hr == S_OK, "IStream_Seek error %#x\n", hr); | 
 |     ok(cur_pos.QuadPart > 4 && cur_pos.QuadPart < sizeof(tiff_1bpp_data), | 
 |        "current stream pos is at %x/%x\n", cur_pos.u.LowPart, cur_pos.u.HighPart); | 
 |  | 
 |     hr = IWICBitmapDecoder_QueryCapability(decoder, stream, &capability); | 
 |     ok(hr == WINCODEC_ERR_WRONGSTATE, "expected WINCODEC_ERR_WRONGSTATE, got %#x\n", hr); | 
 |  | 
 |     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand); | 
 |     ok(hr == WINCODEC_ERR_WRONGSTATE, "expected WINCODEC_ERR_WRONGSTATE, got %#x\n", hr); | 
 |  | 
 |     IWICBitmapDecoder_Release(decoder); | 
 |  | 
 |     hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder); | 
 | todo_wine | 
 |     ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "expected WINCODEC_ERR_COMPONENTNOTFOUND, got %#x\n", hr); | 
 |  | 
 |     pos.QuadPart = 0; | 
 |     hr = IStream_Seek(stream, pos, SEEK_SET, NULL); | 
 |     ok(hr == S_OK, "IStream_Seek error %#x\n", hr); | 
 |  | 
 |     hr = IWICImagingFactory_CreateDecoderFromStream(factory, stream, NULL, 0, &decoder); | 
 |     ok(hr == S_OK, "CreateDecoderFromStream error %#x\n", hr); | 
 |  | 
 |     frame_count = 0xdeadbeef; | 
 |     hr = IWICBitmapDecoder_GetFrameCount(decoder, &frame_count); | 
 |     ok(hr == S_OK, "GetFrameCount error %#x\n", hr); | 
 |     ok(frame_count == 1, "expected 1, got %u\n", frame_count); | 
 |  | 
 |     hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame); | 
 |     ok(hr == S_OK, "GetFrame error %#x\n", hr); | 
 |     IWICBitmapFrameDecode_Release(frame); | 
 |  | 
 |     hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand); | 
 |     ok(hr == WINCODEC_ERR_WRONGSTATE, "expected WINCODEC_ERR_WRONGSTATE, got %#x\n", hr); | 
 |  | 
 |     hr = IWICBitmapDecoder_QueryCapability(decoder, stream, &capability); | 
 |     ok(hr == WINCODEC_ERR_WRONGSTATE, "expected WINCODEC_ERR_WRONGSTATE, got %#x\n", hr); | 
 |  | 
 |     IWICBitmapDecoder_Release(decoder); | 
 |     IStream_Release(stream); | 
 | } | 
 |  | 
 | START_TEST(tiffformat) | 
 | { | 
 |     HRESULT hr; | 
 |  | 
 |     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); | 
 |  | 
 |     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, | 
 |                           &IID_IWICImagingFactory, (void **)&factory); | 
 |     ok(hr == S_OK, "CoCreateInstance error %#x\n", hr); | 
 |     if (FAILED(hr)) return; | 
 |  | 
 |     test_tiff_palette(); | 
 |     test_QueryCapability(); | 
 |  | 
 |     IWICImagingFactory_Release(factory); | 
 |     CoUninitialize(); | 
 | } |