Hi, This fixes a report from some weeks ago, where an app called OleLoadPicture on a GIF resource (http://www.myhexin.com/tw2002/rjxz/download.asp?rjxz=exe1). Please rerun autoconf and autoheader. The application uses shdocvw.dll right after that, which does not work here, since I lack the native setup on this machine. So I was not able to 'see' the GIF images. But it should be correct I hope, at least the CreateDIBSection and later GetObject does not crash. Ciao, Marcus Changelog: Implemented loading of GIF pictures for the OLE Automation IPicture interface using libungif/libgif. Sometimes the persistant stream does not have a header. Index: configure.ac =================================================================== RCS file: /home/wine/wine/configure.ac,v retrieving revision 1.116 diff -u -u -r1.116 configure.ac --- configure.ac 4 Jan 2003 02:52:05 -0000 1.116 +++ configure.ac 5 Jan 2003 19:09:46 -0000 @@ -146,6 +146,21 @@ ) ) +GIFLIB="" +AC_SUBST(GIFLIB) +AC_CHECK_HEADERS(gif_lib.h, + AC_CHECK_LIB(ungif,DGifOpen, + AC_DEFINE(HAVE_LIBGIF,1,[Define if you have libgif/libungif including devel headers]) + GIFLIB="-lungif", + [ + AC_CHECK_LIB(gif,DGifOpen, + AC_DEFINE(HAVE_LIBGIF,1,[Define if you have libgif/libungif including devel headers]) + JPEGLIB="-lgif" + ) + ] + ) +) + AC_SUBST(XLIB) AC_SUBST(XFILES) Index: dlls/oleaut32/olepicture.c =================================================================== RCS file: /home/wine/wine/dlls/oleaut32/olepicture.c,v retrieving revision 1.21 diff -u -u -r1.21 olepicture.c --- dlls/oleaut32/olepicture.c 2 Jan 2003 17:54:57 -0000 1.21 +++ dlls/oleaut32/olepicture.c 5 Jan 2003 19:09:47 -0000 @@ -42,6 +42,14 @@ #endif #include <stdio.h> #include <string.h> + +/* Must be before wine includes, the header has things conflicting with + * WINE headers. + */ +#ifdef HAVE_LIBGIF +# include <gif_lib.h> +#endif + #include "winerror.h" #include "winbase.h" #include "wingdi.h" @@ -810,6 +818,26 @@ static void _jpeg_term_source(j_decompress_ptr cinfo) { } #endif /* HAVE_LIBJPEG */ +#ifdef HAVE_LIBGIF +struct gifdata { + unsigned char *data; + unsigned int curoff; + unsigned int len; +}; + +static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { + struct gifdata *gd = (struct gifdata*)gif->UserData; + + if (len+gd->curoff > gd->len) { + FIXME("Trying to read %d bytes, but only %d available.\n",len, gd->len-gd->curoff); + len = gd->len - gd->curoff; + } + memcpy(data, gd->data+gd->curoff, len); + gd->curoff += len; + return len; +} +#endif + /************************************************************************ * OLEPictureImpl_IPersistStream_Load (IUnknown) * @@ -826,30 +854,134 @@ BYTE *xbuf; DWORD header[2]; WORD magic; + STATSTG statstg; ICOM_THIS_From_IPersistStream(OLEPictureImpl, iface); - + TRACE("(%p,%p)\n",This,pStm); + /* Sometimes we have a header, sometimes we don't. Apply some guesses to find + * out whether we do. + */ + hr=IStream_Stat(pStm,&statstg,STATFLAG_NONAME); + if (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; } - xread = 0; - xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]); - This->datalen = header[1]; - while (xread < header[1]) { - ULONG nread; - hr = IStream_Read(pStm,xbuf+xread,header[1]-xread,&nread); - xread+=nread; - if (hr || !nread) - break; + if (header[1] > statstg.cbSize.QuadPart) {/* 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); + } else { + xread = 0; + xbuf = This->data = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,header[1]); + This->datalen = header[1]; + while (xread < header[1]) { + ULONG nread; + hr = IStream_Read(pStm,xbuf+xread,header[1]-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 != header[1]) - FIXME("Could only read %ld of %ld bytes?\n",xread,header[1]); - magic = xbuf[0] + (xbuf[1]<<8); switch (magic) { + case 0x4947: { /* GIF */ +#ifdef HAVE_LIBGIF + struct gifdata gd; + GifFileType *gif; + BITMAPINFO *bmi; + HDC hdcref; + LPBYTE bytes; + int i,j,ret; + GifImageDesc *gid; + SavedImage *si; + ColorMapObject *cm; + + gd.data = xbuf; + gd.curoff = 0; + gd.len = xread; + gif = DGifOpen((void*)&gd, _gif_inputfunc); + ret = DGifSlurp(gif); + if (ret == GIF_ERROR) { + FIXME("Failed reading GIF using libgif.\n"); + return E_FAIL; + } + TRACE("screen height %d, width %d\n", gif->SWidth, gif->SHeight); + TRACE("color res %d, backgcolor %d\n", gif->SColorResolution, gif->SBackGroundColor); + TRACE("imgcnt %d\n", gif->ImageCount); + if (gif->ImageCount<1) { + FIXME("GIF stream does not have images inside?\n"); + return E_FAIL; + } + TRACE("curimage: %d x %d, on %dx%d, interlace %d\n", + gif->Image.Width, gif->Image.Height, + gif->Image.Left, gif->Image.Top, + gif->Image.Interlace + ); + /* */ + bmi = HeapAlloc(GetProcessHeap(),0,sizeof(BITMAPINFOHEADER)+(1<<gif->SColorResolution)*sizeof(RGBQUAD)); + bytes= HeapAlloc(GetProcessHeap(),0,gif->SWidth*gif->SHeight); + si = gif->SavedImages+0; + gid = &(si->ImageDesc); + cm = gid->ColorMap; + if (!cm) cm = gif->SColorMap; + for (i=0;i<(1<<gif->SColorResolution);i++) { + bmi->bmiColors[i].rgbRed = cm->Colors[i].Red; + bmi->bmiColors[i].rgbGreen = cm->Colors[i].Green; + bmi->bmiColors[i].rgbBlue = cm->Colors[i].Blue; + } + /* Map to in picture coordinates */ + for (i=0;i<gid->Height;i++) + for (j=0;j<gid->Width;j++) + bytes[(gid->Top+i)*gif->SWidth+gid->Left+j]=si->RasterBits[i*gid->Width+j]; + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = gif->SWidth; + bmi->bmiHeader.biHeight = gif->SHeight; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = 8; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biSizeImage = gif->SWidth*gif->SHeight; + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biClrUsed = 1 << gif->SColorResolution; + bmi->bmiHeader.biClrImportant = 0; + + hdcref = GetDC(0); + This->desc.u.bmp.hbitmap=CreateDIBitmap( + hdcref, + bmi, + CBM_INIT, + bytes, + bmi, + DIB_PAL_COLORS + ); + DeleteDC(hdcref); + This->desc.picType = PICTYPE_BITMAP; + OLEPictureImpl_SetBitmap(This); + DGifCloseFile(gif); + HeapFree(GetProcessHeap(),0,bytes); + return S_OK; +#else + FIXME("Trying to load GIF, but no support for libgif/libungif compiled in.\n"); + return E_FAIL; +#endif + break; + } case 0xd8ff: { /* JPEG */ #ifdef HAVE_LIBJPEG struct jpeg_decompress_struct jd; @@ -1009,9 +1141,18 @@ break; } default: - FIXME("Unknown magic %04x\n",magic); + { + int i; + FIXME("Unknown magic %04x, %ld read bytes:\n",magic,xread); hr=E_FAIL; + for (i=0;i<xread+8;i++) { + if (i<8) MESSAGE("%02x ",((unsigned char*)&header)[i]); + else MESSAGE("%02x ",xbuf[i-8]); + if (i % 10 == 9) MESSAGE("\n"); + } + MESSAGE("\n"); break; + } } /* FIXME: this notify is not really documented */