PATCH: olepicture fixes / testcases

Marcus Meissner marcus at jet.franken.de
Mon Jun 6 02:06:39 CDT 2005


Hi,

I wrote some Olepicture testcases and fixed some fallout in comparison
to native oleaut32.dll.

make check passes for both builtin and native.
s25atonce (which loades a GIF) still works.

dlls/oleaut32/tests/olepicture.c is attached.

Ciao, Marcus

Changelog:
	Added testcases for OLE Picture handling.
	Implemented PICTYPE_NONE loading.
	Cleaned up stream loading, handle "lt" magic.
	Fixed some small problems exposed by tests against
	native.

Index: dlls/oleaut32/olepicture.c
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/olepicture.c,v
retrieving revision 1.61
diff -u -r1.61 olepicture.c
--- dlls/oleaut32/olepicture.c	22 Apr 2005 19:05:05 -0000	1.61
+++ dlls/oleaut32/olepicture.c	6 Jun 2005 07:02:14 -0000
@@ -334,6 +334,9 @@
     case PICTYPE_ENHMETAFILE:
       DeleteEnhMetaFile(Obj->desc.u.emf.hemf);
       break;
+    case PICTYPE_NONE:
+      /* Nothing to do */
+      break;
     default:
       FIXME("Unsupported type %d - unable to delete\n", Obj->desc.picType);
       break;
@@ -485,6 +488,9 @@
   OLEPictureImpl *This = (OLEPictureImpl *)iface;
   TRACE("(%p)->(%p)\n", This, phandle);
   switch(This->desc.picType) {
+  case PICTYPE_NONE:
+    *phandle = 0;
+    break;
   case PICTYPE_BITMAP:
     *phandle = (OLE_HANDLE)This->desc.u.bmp.hbitmap;
     break;
@@ -512,8 +518,10 @@
 					      OLE_HANDLE *phandle)
 {
   OLEPictureImpl *This = (OLEPictureImpl *)iface;
-  FIXME("(%p)->(%p): stub\n", This, phandle);
-  return E_NOTIMPL;
+  FIXME("(%p)->(%p): stub, return 0 palette.\n", This, phandle);
+
+  *phandle = 0;
+  return S_OK;
 }
 
 /************************************************************************
@@ -992,7 +1000,8 @@
  */
 static HRESULT WINAPI OLEPictureImpl_Load(IPersistStream* iface,IStream*pStm) {
   HRESULT	hr = E_FAIL;
-  ULONG		xread;
+  BOOL		headerisdata = FALSE;
+  ULONG		xread, toread;
   BYTE 		*xbuf;
   DWORD		header[2];
   WORD		magic;
@@ -1013,43 +1022,54 @@
    */
   hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME);
   if (hr)
-    FIXME("Stat failed with hres %lx\n",hr);
+      FIXME("Stat failed with hres %lx\n",hr);
   hr=IStream_Read(pStm,header,8,&xread);
   if (hr || xread!=8) {
       FIXME("Failure while reading picture header (hr is %lx, nread is %ld).\n",hr,xread);
       return hr;
   }
-  if (!memcmp(&(header[0]), "GIF8",     4) ||   /* GIF header */
-      !memcmp(&(header[0]), "BM",       2) ||   /* BMP header */
-      !memcmp(&(header[0]), "\xff\xd8", 2) ||   /* JPEG header */
-      header[1] > statstg.cbSize.QuadPart || (header[1]==0)) {/* Incorrect header, assume none. */
-    xread = 8;
-    xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,statstg.cbSize.QuadPart);
-    memcpy(xbuf,&header,8);
-    This->datalen = statstg.cbSize.QuadPart;
-    while (xread < This->datalen) {
-      ULONG nread;
-      hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
-      xread+=nread;
-      if (hr || !nread)
-	break;
-    }
-    if (xread != This->datalen)
-      FIXME("Could only read %ld of %d bytes in no-header case?\n",xread,This->datalen);
+
+  headerisdata = FALSE;
+  xread = 0;
+  if (!memcmp(&(header[0]),"lt\0\0", 4) && (header[1] <= statstg.cbSize.QuadPart-8)) {
+      toread = header[1];
   } else {
-    xread = 0;
-    xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]);
-    This->datalen = header[1];
-    while (xread < header[1]) {
+      if (!memcmp(&(header[0]), "GIF8",     4)	||   /* GIF header */
+	  !memcmp(&(header[0]), "BM",       2)	||   /* BMP header */
+	  !memcmp(&(header[0]), "\xff\xd8", 2)	||   /* JPEG header */
+	  (header[1] > statstg.cbSize.QuadPart)	||   /* invalid size */
+	  (header[1]==0)
+      ) {/* Incorrect header, assume none. */
+          headerisdata = TRUE;
+          toread = statstg.cbSize.QuadPart-8;
+	  xread = 8;
+      } else {
+	  FIXME("Unknown stream header magic: %08lx\n", header[0]);
+          toread = header[1];
+      }
+  }
+
+  This->datalen = toread+(headerisdata?8:0);
+  xbuf = This->data = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, This->datalen);
+
+  if (headerisdata)
+      memcpy (xbuf, &header, 8);
+
+  while (xread < This->datalen) {
       ULONG nread;
-      hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread);
+      hr = IStream_Read(pStm,xbuf+xread,This->datalen-xread,&nread);
       xread+=nread;
       if (hr || !nread)
 	break;
-    }
-    if (xread != header[1])
-      FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]);
   }
+  if (xread != This->datalen)
+      FIXME("Could only read %ld of %d bytes out of stream?\n",xread,This->datalen);
+
+  if (This->datalen == 0) {	/* Marks the "NONE" picture */
+      This->desc.picType = PICTYPE_NONE;
+      return S_OK;
+  }
+
   magic = xbuf[0] + (xbuf[1]<<8);
   switch (magic) {
   case 0x4947: { /* GIF */
Index: dlls/oleaut32/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/oleaut32/tests/Makefile.in,v
retrieving revision 1.7
diff -u -r1.7 Makefile.in
--- dlls/oleaut32/tests/Makefile.in	19 Aug 2004 20:29:16 -0000	1.7
+++ dlls/oleaut32/tests/Makefile.in	6 Jun 2005 07:02:18 -0000
@@ -3,11 +3,12 @@
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 TESTDLL   = oleaut32.dll
-IMPORTS   = oleaut32
+IMPORTS   = oleaut32 ole32 gdi32
 EXTRALIBS = -luuid
 
 CTESTS = \
 	olefont.c \
+	olepicture.c \
 	safearray.c \
 	typelib.c \
 	vartest.c \
-------------- next part --------------
/*
 * OLEPICTURE test program
 *
 * Copyright 2005 Marcus Meissner
 *
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <stdarg.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include <time.h>

#define COBJMACROS

#include <wine/test.h>
#include <windef.h>
#include <winbase.h>
#include <winuser.h>
#include <wingdi.h>
#include <winnls.h>
#include <winerror.h>
#include <winnt.h>

#include <wtypes.h>
#include <olectl.h>
#include <objidl.h>

static HMODULE hOleaut32;

static HRESULT (WINAPI *pOleLoadPicture)(LPSTREAM,LONG,BOOL,REFIID,LPVOID*);

/* 1x1 pixel gif */
static const unsigned char gifimage[35] = {
0x47,0x49,0x46,0x38,0x37,0x61,0x01,0x00,0x01,0x00,0x80,0x00,0x00,0xff,0xff,0xff,
0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x02,0x02,0x44,
0x01,0x00,0x3b
};

/* 1x1 pixel jpg */
static const unsigned char jpgimage[285] = {
0xff,0xd8,0xff,0xe0,0x00,0x10,0x4a,0x46,0x49,0x46,0x00,0x01,0x01,0x01,0x01,0x2c,
0x01,0x2c,0x00,0x00,0xff,0xdb,0x00,0x43,0x00,0x05,0x03,0x04,0x04,0x04,0x03,0x05,
0x04,0x04,0x04,0x05,0x05,0x05,0x06,0x07,0x0c,0x08,0x07,0x07,0x07,0x07,0x0f,0x0b,
0x0b,0x09,0x0c,0x11,0x0f,0x12,0x12,0x11,0x0f,0x11,0x11,0x13,0x16,0x1c,0x17,0x13,
0x14,0x1a,0x15,0x11,0x11,0x18,0x21,0x18,0x1a,0x1d,0x1d,0x1f,0x1f,0x1f,0x13,0x17,
0x22,0x24,0x22,0x1e,0x24,0x1c,0x1e,0x1f,0x1e,0xff,0xdb,0x00,0x43,0x01,0x05,0x05,
0x05,0x07,0x06,0x07,0x0e,0x08,0x08,0x0e,0x1e,0x14,0x11,0x14,0x1e,0x1e,0x1e,0x1e,
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,
0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0x1e,0xff,0xc0,
0x00,0x11,0x08,0x00,0x01,0x00,0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,
0x01,0xff,0xc4,0x00,0x15,0x00,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xff,0xc4,0x00,0x14,0x10,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc4,
0x00,0x14,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xff,0xc4,0x00,0x14,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xda,0x00,0x0c,0x03,0x01,
0x00,0x02,0x11,0x03,0x11,0x00,0x3f,0x00,0xb2,0xc0,0x07,0xff,0xd9
};

#if 0 /* no png support yet */
/* 1x1 pixel png */
static const unsigned char pngimage[285] = {
0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x08,0x02,0x00,0x00,0x00,0x90,0x77,0x53,
0xde,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,0x00,0x0b,0x13,0x00,0x00,0x0b,
0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,0x74,0x49,0x4d,0x45,0x07,0xd5,
0x06,0x03,0x0f,0x07,0x2d,0x12,0x10,0xf0,0xfd,0x00,0x00,0x00,0x0c,0x49,0x44,0x41,
0x54,0x08,0xd7,0x63,0xf8,0xff,0xff,0x3f,0x00,0x05,0xfe,0x02,0xfe,0xdc,0xcc,0x59,
0xe7,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
#endif

/* 1x1 pixel bmp */
static const unsigned char bmpimage[66] = {
0x42,0x4d,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x00,0x00,0x28,0x00,
0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,
0x00,0x00,0x04,0x00,0x00,0x00,0x12,0x0b,0x00,0x00,0x12,0x0b,0x00,0x00,0x02,0x00,
0x00,0x00,0x02,0x00,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0x00,0x00,
0x00,0x00
};

/* 2x2 pixel gif */
static const unsigned char gif4pixel[42] = {
0x47,0x49,0x46,0x38,0x37,0x61,0x02,0x00,0x02,0x00,0xa1,0x00,0x00,0x00,0x00,0x00,
0x39,0x62,0xfc,0xff,0x1a,0xe5,0xff,0xff,0xff,0x2c,0x00,0x00,0x00,0x00,0x02,0x00,
0x02,0x00,0x00,0x02,0x03,0x14,0x16,0x05,0x00,0x3b
};

static void
test_pic(const unsigned char *imgdata, unsigned int imgsize)
{
	LPBYTE		data;
	LPSTREAM	stream;
	IPicture*	pic = NULL;
	HRESULT		hres;
	LPVOID		pvObj = NULL;
	HGLOBAL		hglob;
	ULARGE_INTEGER	newpos1;
	LARGE_INTEGER	seekto;
	OLE_HANDLE	handle, hPal;
	OLE_XSIZE_HIMETRIC	width;
	OLE_YSIZE_HIMETRIC	height;
	short		type;
	DWORD		attr;
	ULONG		res;

	/* let the fun begin */
	hglob = GlobalAlloc (0, imgsize);
	data = GlobalLock (hglob);
	memcpy(data, imgdata, imgsize);

	hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
	ok (hres == S_OK, "createstreamonhglobal failed? doubt it... hres 0x%08lx\n", hres);

	memset(&seekto,0,sizeof(seekto));
	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);

	pvObj = NULL;
	hres = pOleLoadPicture(stream, imgsize, TRUE, &IID_IPicture, &pvObj);
	pic = pvObj;

	ok(hres == S_OK,"OLP (NULL,..) does not return 0, but 0x%08lx\n",hres);
	ok(pic != NULL,"OLP (NULL,..) returns NULL, instead of !NULL\n");
	if (pic == NULL)
		return;

#if 0
	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos2);
	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);

	/* The stream position here is some bytes after the image, in both wine and
	 * native. But not at the correct end. -Marcus
	 */
	fprintf(stderr,"newpos1 %ld, newpos2 %ld\n", newpos1.LowPart, newpos2.LowPart);
	ok (	newpos2.LowPart == imgsize,
		"seeked after end of gifimage (offset %d instead of expected %d)\n",
		newpos2.LowPart, imgsize
	);
#endif

	pvObj = NULL;
	hres = IPicture_QueryInterface (pic, &IID_IPicture, &pvObj);

	ok(hres == S_OK,"IPicture_QI does not return S_OK, but 0x%08lx\n", hres);
	ok(pvObj != NULL,"IPicture_QI does return NULL, instead of a ptr\n");

	IPicture_Release ((IPicture*)pvObj);

	handle = 0;
	hres = IPicture_get_Handle (pic, &handle);
	ok(hres == S_OK,"IPicture_get_Handle does not return S_OK, but 0x%08lx\n", hres);
	ok(handle != 0, "IPicture_get_Handle returns a NULL handle, but it should be non NULL\n");

	width = 0;
	hres = IPicture_get_Width (pic, &width);
	ok(hres == S_OK,"IPicture_get_Width does not return S_OK, but 0x%08lx\n", hres);
	ok(width != 0, "IPicture_get_Width returns 0, but it should not be 0.\n");

	height = 0;
	hres = IPicture_get_Height (pic, &height);
	ok(hres == S_OK,"IPicture_get_Height does not return S_OK, but 0x%08lx\n", hres);
	ok(height != 0, "IPicture_get_Height returns 0, but it should not be 0.\n");

	type = 0;
	hres = IPicture_get_Type (pic, &type);
	ok(hres == S_OK,"IPicture_get_Type does not return S_OK, but 0x%08lx\n", hres);
	ok(type == PICTYPE_BITMAP, "IPicture_get_Type returns %d, but it should be PICTYPE_BITMAP(%d).\n", type, PICTYPE_BITMAP);

	attr = 0;
	hres = IPicture_get_Attributes (pic, &attr);
	ok(hres == S_OK,"IPicture_get_Attributes does not return S_OK, but 0x%08lx\n", hres);
	ok(attr == 0, "IPicture_get_Attributes returns %ld, but it should be 0.\n", attr);

	hPal = 0;
	hres = IPicture_get_hPal (pic, &hPal);
	ok(hres == S_OK,"IPicture_get_hPal does not return S_OK, but 0x%08lx\n", hres);
	/* a single pixel b/w image has no palette */
	ok(hPal == 0, "IPicture_get_hPal returns %ld, but it should be 0.\n", (long)hPal);

	res = IPicture_Release (pic);
	ok (res == 0, "refcount after release is %ld, but should be 1?\n", res);
}

static void test_empty_image() {
	LPBYTE		data;
	LPSTREAM	stream;
	IPicture*	pic = NULL;
	HRESULT		hres;
	LPVOID		pvObj = NULL;
	HGLOBAL		hglob;
	OLE_HANDLE	handle, hPal;
	ULARGE_INTEGER	newpos1;
	LARGE_INTEGER	seekto;
	short		type;

	/* Empty image. Happens occasionaly in VB programs. */
	hglob = GlobalAlloc (0, 8);
	data = GlobalLock (hglob);
	memcpy(data,"lt\0\0",4);
	((DWORD*)data)[1] = 0;
	hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
	ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);

	memset(&seekto,0,sizeof(seekto));
	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);

	pvObj = NULL;
	hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
	pic = pvObj;
	ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
	ok(pic != NULL,"empty picture not loaded, pic is NULL\n");

	hres = IPicture_get_Type (pic, &type);
	ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
	ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);

	hres = IPicture_get_Handle (pic, &handle);
	ok (hres == S_OK,"empty picture get handle failed with hres 0x%08lx\n", hres);
	ok (handle == 0, "empty picture get handle did not return 0, but 0x%08lx\n", handle);
	IPicture_Release (pic);
}

static void test_empty_image_2() {
	LPBYTE		data;
	LPSTREAM	stream;
	IPicture*	pic = NULL;
	HRESULT		hres;
	LPVOID		pvObj = NULL;
	HGLOBAL		hglob;
	ULARGE_INTEGER	newpos1;
	LARGE_INTEGER	seekto;
	short		type;

	/* Empty image at random stream position. */
	hglob = GlobalAlloc (0, 200);
	data = GlobalLock (hglob);
	data += 42;
	memcpy(data,"lt\0\0",4);
	((DWORD*)data)[1] = 0;
	hres = CreateStreamOnHGlobal (hglob, TRUE, &stream);
	ok (hres == S_OK, "CreatestreamOnHGlobal failed? doubt it... hres 0x%08lx\n", hres);

	memset(&seekto,0,sizeof(seekto));
	seekto.u.LowPart = 42;
	hres = IStream_Seek(stream,seekto,SEEK_CUR,&newpos1);
	ok (hres == S_OK, "istream seek failed? doubt it... hres 0x%08lx\n", hres);

	pvObj = NULL;
	hres = pOleLoadPicture(stream, 8, TRUE, &IID_IPicture, &pvObj);
	pic = pvObj;
	ok(hres == S_OK,"empty picture not loaded, hres 0x%08lx\n", hres);
	ok(pic != NULL,"empty picture not loaded, pic is NULL\n");

	hres = IPicture_get_Type (pic, &type);
	ok (hres == S_OK,"empty picture get type failed with hres 0x%08lx\n", hres);
	ok (type == PICTYPE_NONE,"type is %d, but should be PICTYPE_NONE(0)\n", type);

	IPicture_Release (pic);
}

START_TEST(olepicture)
{
	LPBYTE		data;
	LPSTREAM	stream;
	IPicture*	pic = NULL;
	HRESULT		hres;
	LPVOID		pvObj = NULL;
	HGLOBAL		hglob;
	ULARGE_INTEGER	newpos1, newpos2;
	LARGE_INTEGER	seekto;
	OLE_HANDLE	handle, hPal;
	OLE_XSIZE_HIMETRIC	width;
	OLE_YSIZE_HIMETRIC	height;
	short		type;
	DWORD		attr;

	hOleaut32 = LoadLibraryA("oleaut32.dll");    
	pOleLoadPicture = (void*)GetProcAddress(hOleaut32, "OleLoadPicture");
	if (!pOleLoadPicture)
	    return;

	/* Test regular 1x1 pixel images of gif, jpg, bmp type */
	test_pic(gifimage, sizeof(gifimage));
	test_pic(jpgimage, sizeof(jpgimage));
	test_pic(bmpimage, sizeof(bmpimage));
	test_pic(gif4pixel, sizeof(gif4pixel));
	/* no PNG support yet here or in older Windows...
	test_pic(pngimage, sizeof(pngimage));
	 */
	test_empty_image();
	test_empty_image_2();
}


More information about the wine-patches mailing list