menubuilder: Use png file format for icons with 24 & 32-bit color.

Vitaliy Margolen wine-patch at kievinfo.com
Mon Jan 23 17:06:49 CST 2006


ChangeLog:
menubuilder: Use png file format for icons with 24 & 32-bit color.
Add BMP file handling.

This time with processing of the AND mask. For that I'm using top left corner
for the background color.

 configure                                  |   82 +++++++++++
 configure.ac                               |   10 +
 include/config.h.in                        |    3 
 programs/winemenubuilder/Makefile.in       |    2 
 programs/winemenubuilder/winemenubuilder.c |  204 +++++++++++++++++++++++-----
 5 files changed, 260 insertions(+), 41 deletions(-)
-------------- next part --------------
d12de0bc85cce7df66aafd8af21e3c152fb7a93e
diff --git a/configure b/configure
index 4de3c19..7217067 100755
--- a/configure
+++ b/configure
@@ -311,7 +311,7 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS DLLDEFS build build_cpu build_vendor build_os host host_cpu host_vendor host_os WIN16_FILES WIN16_INSTALL SET_MAKE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPPBIN ac_ct_CPPBIN TOOLSDIR CPP X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS LEX LEXLIB LEX_OUTPUT_ROOT XLEX BISON AS ac_ct_AS LD ac_ct_LD AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP WINDRES ac_ct_WINDRES LN_S LN EGREP LDCONFIG INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LINT LINTFLAGS FONTFORGE PKG_CONFIG PRELINK LIBPTHREAD XLIB XFILES OPENGLFILES GLU32FILES OPENGL_LIBS GLUT_LIBS GLUT32FILES NASLIBS XML2LIBS XML2INCL XSLTLIBS XSLTINCL CURSESLIBS sane_devel SANELIBS SANEINCL ICULIBS LCMSLIBS LDAPLIBS FREETYPELIBS FREETYPEINCL ft_devel ft_devel2 FONTSSUBDIRS ARTSCCONFIG ARTSLIBS ARTSINCL ESDCONFIG ESDLIBS ESDINCL ALSALIBS AUDIOIOLIBS EXTRACFLAGS BUILTINFLAG DLLEXT DLLFLAGS DLLIBS LDSHARED LDDLLFLAGS LIBEXT IMPLIBEXT DLLTOOL ac_ct_DLLTOOL DLLWRAP ac_ct_DLLWRAP LDEXECFLAGS COREFOUNDATIONLIB IOKITLIB LDLIBWINEFLAGS CROSSTEST CROSSCC CROSSWINDRES LDPATH CRTLIBS SOCKETLIBS WINE_BINARIES MAIN_BINARY LDD LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS DLLDEFS build build_cpu build_vendor build_os host host_cpu host_vendor host_os WIN16_FILES WIN16_INSTALL SET_MAKE CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX CPPBIN ac_ct_CPPBIN TOOLSDIR CPP X_CFLAGS X_PRE_LIBS X_LIBS X_EXTRA_LIBS LEX LEXLIB LEX_OUTPUT_ROOT XLEX BISON AS ac_ct_AS LD ac_ct_LD AR ac_ct_AR RANLIB ac_ct_RANLIB STRIP ac_ct_STRIP WINDRES ac_ct_WINDRES LN_S LN EGREP LDCONFIG INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LINT LINTFLAGS FONTFORGE PKG_CONFIG PRELINK LIBPTHREAD XLIB XFILES OPENGLFILES GLU32FILES OPENGL_LIBS GLUT_LIBS GLUT32FILES NASLIBS XML2LIBS XML2INCL XSLTLIBS XSLTINCL CURSESLIBS sane_devel SANELIBS SANEINCL ICULIBS LCMSLIBS PNGLIBS LDAPLIBS FREETYPELIBS FREETYPEINCL ft_devel ft_devel2 FONTSSUBDIRS ARTSCCONFIG ARTSLIBS ARTSINCL ESDCONFIG ESDLIBS ESDINCL ALSALIBS AUDIOIOLIBS EXTRACFLAGS BUILTINFLAG DLLEXT DLLFLAGS DLLIBS LDSHARED LDDLLFLAGS LIBEXT IMPLIBEXT DLLTOOL ac_ct_DLLTOOL DLLWRAP ac_ct_DLLWRAP LDEXECFLAGS COREFOUNDATIONLIB IOKITLIB LDLIBWINEFLAGS CROSSTEST CROSSCC CROSSWINDRES LDPATH CRTLIBS SOCKETLIBS WINE_BINARIES MAIN_BINARY LDD LIBOBJS LTLIBOBJS'
 ac_subst_files='MAKE_RULES MAKE_DLL_RULES MAKE_IMPLIB_RULES MAKE_TEST_RULES MAKE_LIB_RULES MAKE_PROG_RULES'
 
 # Initialize some variables set by options.
@@ -7091,6 +7091,7 @@ for ac_header in \
 	poll.h \
 	process.h \
 	pthread.h \
+	png.h \
 	pwd.h \
 	regex.h \
 	sched.h \
@@ -9613,6 +9614,84 @@ fi
 
 fi
 
+PNGLIBS=""
+
+if test "$ac_cv_header_png_h" = "yes"
+then
+    echo "$as_me:$LINENO: checking for png_set_IHDR in -lpng" >&5
+echo $ECHO_N "checking for png_set_IHDR in -lpng... $ECHO_C" >&6
+if test "${ac_cv_lib_png_png_set_IHDR+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpng  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+/* Override any gcc2 internal prototype to avoid an error.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+   builtin and then its argument prototype would still apply.  */
+char png_set_IHDR ();
+int
+main ()
+{
+png_set_IHDR ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag"			 || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_lib_png_png_set_IHDR=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_png_png_set_IHDR=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_png_png_set_IHDR" >&5
+echo "${ECHO_T}$ac_cv_lib_png_png_set_IHDR" >&6
+if test $ac_cv_lib_png_png_set_IHDR = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_PNG 1
+_ACEOF
+
+         PNGLIBS="-lpng"
+fi
+
+fi
+
 LDAPLIBS=""
 
 if test "$ac_cv_header_ldap_h" = "yes" -a "$ac_cv_header_lber_h" = "yes"
@@ -19689,6 +19768,7 @@ s, at SANELIBS@,$SANELIBS,;t t
 s, at SANEINCL@,$SANEINCL,;t t
 s, at ICULIBS@,$ICULIBS,;t t
 s, at LCMSLIBS@,$LCMSLIBS,;t t
+s, at PNGLIBS@,$PNGLIBS,;t t
 s, at LDAPLIBS@,$LDAPLIBS,;t t
 s, at FREETYPELIBS@,$FREETYPELIBS,;t t
 s, at FREETYPEINCL@,$FREETYPEINCL,;t t
diff --git a/configure.ac b/configure.ac
index b458d7d..c1b78b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -224,6 +224,7 @@ AC_CHECK_HEADERS(\
 	poll.h \
 	process.h \
 	pthread.h \
+	png.h \
 	pwd.h \
 	regex.h \
 	sched.h \
@@ -542,6 +543,15 @@ then
          LCMSLIBS="-llcms"])
 fi
 
+dnl **** Check for libpng ***
+AC_SUBST(PNGLIBS,"")
+if test "$ac_cv_header_png_h" = "yes"
+then
+    AC_CHECK_LIB(png, png_set_IHDR,
+        [AC_DEFINE(HAVE_PNG, 1, [Define if you have the libpng development environment])
+         PNGLIBS="-lpng"])
+fi
+
 dnl **** Check for OpenLDAP ***
 AC_SUBST(LDAPLIBS,"")
 if test "$ac_cv_header_ldap_h" = "yes" -a "$ac_cv_header_lber_h" = "yes"
diff --git a/include/config.h.in b/include/config.h.in
index 51ecdc5..95c7149 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -458,6 +458,9 @@
 /* Define to 1 if the system has the type `pid_t'. */
 #undef HAVE_PID_T
 
+/* Define to 1 if you have the <png.h> header file. */
+#undef HAVE_PNG_H
+
 /* Define to 1 if you have the <poll.h> header file. */
 #undef HAVE_POLL_H
 
diff --git a/programs/winemenubuilder/Makefile.in b/programs/winemenubuilder/Makefile.in
index 48ac38d..adb79a1 100644
--- a/programs/winemenubuilder/Makefile.in
+++ b/programs/winemenubuilder/Makefile.in
@@ -5,7 +5,7 @@ VPATH     = @srcdir@
 MODULE    = winemenubuilder.exe
 APPMODE   = -mwindows
 IMPORTS   = shell32 ole32 user32 advapi32 kernel32
-EXTRALIBS = -luuid
+EXTRALIBS = -luuid @PNGLIBS@
 
 C_SRCS = \
 	winemenubuilder.c
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 08c0760..2875571 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -62,6 +62,9 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#ifdef HAVE_PNG_H
+#include <png.h>
+#endif
 #include <errno.h>
 #include <stdarg.h>
 
@@ -143,22 +146,131 @@ typedef struct
  * FIXME: should not use stdio
  */
 
-static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, const char *szXPMFileName, LPCWSTR commentW)
+#define MASK(x,y) (!(pAND)?0:(pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8))))
+
+#ifdef HAVE_PNG_H
+static BOOL SaveIconResAsPNG(const BITMAPINFO *pIcon, char *szPNGFileName, LPCWSTR commentW)
+{
+    FILE *fPNGFile;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    int nXORWidthBytes, nANDWidthBytes, color_type = 0, i, j;
+    BYTE *pXOR, *row;
+    const BYTE *pAND = NULL;
+    RGBQUAD bgColor = {0};
+    int nWidth  = pIcon->bmiHeader.biWidth;
+    int nHeight = pIcon->bmiHeader.biHeight;
+    int nBpp    = pIcon->bmiHeader.biBitCount;
+
+    memcpy(szPNGFileName + strlen(szPNGFileName) - 3, "png", 3);
+    if (!(fPNGFile = fopen(szPNGFileName, "w")))
+    {
+        WINE_ERR("unable to open '%s' for writing: %s\n", szPNGFileName, strerror(errno));
+        return FALSE;
+    }
+
+    nXORWidthBytes = 4 * ((nWidth * nBpp + 31) / 32);
+    nANDWidthBytes = 4 * ((nWidth + 31 ) / 32);
+    pXOR = (BYTE*) pIcon + sizeof(BITMAPINFOHEADER) + pIcon->bmiHeader.biClrUsed * sizeof(RGBQUAD);
+    if (nHeight > nWidth)
+    {
+        nHeight /= 2;
+        pAND = pXOR + nHeight * nXORWidthBytes;
+    }
+
+    switch (nBpp)
+    {
+    case 32:
+        color_type |= PNG_COLOR_MASK_ALPHA;
+        /* fall through */
+    case 24:
+        color_type |= PNG_COLOR_MASK_COLOR;
+        break;
+    default:
+        return FALSE;
+    }
+
+    /* image and mask are upside down reversed */
+    row = pXOR + (nHeight - 1) * nXORWidthBytes;
+    /* top left corner */
+    bgColor.rgbRed   = row[0];
+    bgColor.rgbGreen = row[1];
+    bgColor.rgbBlue  = row[2];
+    for (i = 0; i < nHeight; i++, row -= nXORWidthBytes)
+    {
+        for (j = 0; j < nWidth; j++, row += nBpp >> 3)
+        {
+            if (MASK(j, i))
+            {
+                RGBQUAD *pixel = (RGBQUAD *)row;
+                pixel->rgbBlue  = bgColor.rgbBlue;
+                pixel->rgbGreen = bgColor.rgbGreen;
+                pixel->rgbRed   = bgColor.rgbRed;
+                if (nBpp == 32)
+                    pixel->rgbReserved = bgColor.rgbReserved;
+            }
+        }
+    }
+
+    if (!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) ||
+        !(info_ptr = png_create_info_struct(png_ptr)))
+        goto error;
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+        /* All future errors jump here */
+        WINE_ERR("png error\n");
+        goto error;
+    }
+
+    png_init_io(png_ptr, fPNGFile);
+    png_set_IHDR(png_ptr, info_ptr, nWidth, nHeight, 8,
+                 color_type,
+                 PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT,
+                 PNG_FILTER_TYPE_DEFAULT);
+
+    png_write_info(png_ptr, info_ptr);
+    png_set_bgr(png_ptr);
+    for (i = nHeight - 1; i >= 0 ; i--)
+        png_write_row(png_ptr, (png_bytep)pXOR + nXORWidthBytes * i);
+    png_write_end(png_ptr, info_ptr);
+
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    if (png_ptr) png_destroy_write_struct(&png_ptr, NULL);
+    fclose(fPNGFile);
+    return TRUE;
+
+ error:
+    if (png_ptr) png_destroy_write_struct(&png_ptr, NULL);
+    fclose(fPNGFile);
+    unlink(szPNGFileName);
+    return FALSE;
+}
+#endif
+
+static BOOL SaveIconResAsXPM(const BITMAPINFO *pIcon, char *szXPMFileName, LPCWSTR commentW)
 {
     FILE *fXPMFile;
-    int nHeight;
+    int nWidth  = pIcon->bmiHeader.biWidth;
+    int nHeight = pIcon->bmiHeader.biHeight;
+    int nBpp    = pIcon->bmiHeader.biBitCount;
     int nXORWidthBytes;
     int nANDWidthBytes;
     BOOL b8BitColors;
     int nColors;
     const BYTE *pXOR;
-    const BYTE *pAND;
+    const BYTE *pAND = NULL;
     BOOL aColorUsed[256] = {0};
     int nColorsUsed = 0;
     int i,j;
     char *comment;
 
-    if (!((pIcon->bmiHeader.biBitCount == 4) || (pIcon->bmiHeader.biBitCount == 8)))
+#ifdef HAVE_PNG_H
+    if (nBpp >= 24) return SaveIconResAsPNG(pIcon, szXPMFileName, commentW);
+#endif
+
+    if (nBpp != 4 && nBpp != 8)
     {
         WINE_FIXME("Unsupported color depth %d-bit\n", pIcon->bmiHeader.biBitCount);
         return FALSE;
@@ -174,22 +286,21 @@ static BOOL SaveIconResAsXPM(const BITMA
     comment = HeapAlloc(GetProcessHeap(), 0, i);
     WideCharToMultiByte(CP_UNIXCP, 0, commentW, -1, comment, i, NULL, NULL);
 
-    nHeight = pIcon->bmiHeader.biHeight / 2;
-    nXORWidthBytes = 4 * ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount / 32)
-                          + ((pIcon->bmiHeader.biWidth * pIcon->bmiHeader.biBitCount % 32) > 0));
-    nANDWidthBytes = 4 * ((pIcon->bmiHeader.biWidth / 32)
-                          + ((pIcon->bmiHeader.biWidth % 32) > 0));
+    nXORWidthBytes = 4 * ((nWidth * nBpp + 31) / 32);
+    nANDWidthBytes = 4 * ((nWidth + 31) / 32);
     b8BitColors = pIcon->bmiHeader.biBitCount == 8;
-    nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed
-        : 1 << pIcon->bmiHeader.biBitCount;
+    nColors = pIcon->bmiHeader.biClrUsed ? pIcon->bmiHeader.biClrUsed : 1 << nBpp;
     pXOR = (const BYTE*) pIcon + sizeof (BITMAPINFOHEADER) + (nColors * sizeof (RGBQUAD));
-    pAND = pXOR + nHeight * nXORWidthBytes;
+    if (nHeight > nWidth)
+    {
+        nHeight /= 2; /* we have a mask */
+        pAND = pXOR + nHeight * nXORWidthBytes;
+    }
 
-#define MASK(x,y) (pAND[(x) / 8 + (nHeight - (y) - 1) * nANDWidthBytes] & (1 << (7 - (x) % 8)))
 #define COLOR(x,y) (b8BitColors ? pXOR[(x) + (nHeight - (y) - 1) * nXORWidthBytes] : (x) % 2 ? pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF : (pXOR[(x) / 2 + (nHeight - (y) - 1) * nXORWidthBytes] & 0xF0) >> 4)
 
     for (i = 0; i < nHeight; i++) {
-        for (j = 0; j < pIcon->bmiHeader.biWidth; j++) {
+        for (j = 0; j < nWidth; j++) {
             if (!aColorUsed[COLOR(j,i)] && !MASK(j,i))
             {
                 aColorUsed[COLOR(j,i)] = TRUE;
@@ -201,7 +312,7 @@ static BOOL SaveIconResAsXPM(const BITMA
     if (fprintf(fXPMFile, "/* XPM */\n/* %s */\nstatic char *icon[] = {\n", comment) <= 0)
         goto error;
     if (fprintf(fXPMFile, "\"%d %d %d %d\",\n",
-                (int) pIcon->bmiHeader.biWidth, nHeight, nColorsUsed + 1, 2) <=0)
+                (int) nWidth, nHeight, nColorsUsed + 1, 2) <=0)
         goto error;
 
     for (i = 0; i < nColors; i++) {
@@ -217,7 +328,7 @@ static BOOL SaveIconResAsXPM(const BITMA
     {
         if (fprintf(fXPMFile, ",\n\"") <= 0)
             goto error;
-        for (j = 0; j < pIcon->bmiHeader.biWidth; j++)
+        for (j = 0; j < nWidth; j++)
         {
             if MASK(j,i)
                 {
@@ -261,7 +372,7 @@ static BOOL CALLBACK EnumResNameProc(HMO
         return TRUE;
 }
 
-static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, const char *szXPMFileName)
+static BOOL extract_icon32(LPCWSTR szFileName, int nIndex, char *szXPMFileName)
 {
     HMODULE hModule;
     HRSRC hResInfo;
@@ -350,7 +461,7 @@ static BOOL extract_icon32(LPCWSTR szFil
     return ret;
 }
 
-static BOOL ExtractFromEXEDLL(LPCWSTR szFileName, int nIndex, const char *szXPMFileName)
+static BOOL ExtractFromEXEDLL(LPCWSTR szFileName, int nIndex, char *szXPMFileName)
 {
     if (!extract_icon32(szFileName, nIndex, szXPMFileName) /*&&
         !extract_icon16(szFileName, szXPMFileName)*/)
@@ -358,14 +469,14 @@ static BOOL ExtractFromEXEDLL(LPCWSTR sz
     return TRUE;
 }
 
-static int ExtractFromICO(LPCWSTR szFileName, const char *szXPMFileName)
+static int ExtractFromICO(LPCWSTR szFileName, char *szXPMFileName)
 {
     FILE *fICOFile;
     ICONDIR iconDir;
-    ICONDIRENTRY *pIconDirEntry;
+    ICONDIRENTRY *pIconDirEntry = NULL;
     int nMax = 0;
     int nIndex = 0;
-    void *pIcon;
+    BITMAPINFO *pIcon;
     int i;
     char *filename;
 
@@ -377,29 +488,44 @@ static int ExtractFromICO(LPCWSTR szFile
     }
 
     if (fread(&iconDir, sizeof (ICONDIR), 1, fICOFile) != 1 ||
-        (iconDir.idReserved != 0) || (iconDir.idType != 1))
+        ((iconDir.idReserved != 0 || iconDir.idType != 1) &&
+         iconDir.idReserved != 0x4d42) )
     {
-        WINE_ERR("Invalid ico file format\n");
+        WINE_ERR("Invalid ico file format (%x)\n", iconDir.idType);
         goto error2;
     }
 
-    if ((pIconDirEntry = HeapAlloc(GetProcessHeap(), 0, iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
-        goto error2;
-    if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
-        goto error3;
+    /* It's a BMP */
+    if (iconDir.idReserved == 0x4d42)
+    {
+        BITMAPFILEHEADER *bfHeader = (BITMAPFILEHEADER *)&iconDir;
 
-    for (i = 0; i < iconDir.idCount; i++)
-        if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
-        {
-            nIndex = i;
-            nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
-        }
-    if ((pIcon = HeapAlloc(GetProcessHeap(), 0, pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
-        goto error3;
-    if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
-        goto error4;
-    if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
-        goto error4;
+        if ((pIcon = HeapAlloc(GetProcessHeap(), 0, bfHeader->bfSize)) == NULL)
+            goto error3;
+        if (fseek(fICOFile, sizeof(BITMAPFILEHEADER), SEEK_SET) ||
+            fread(pIcon, bfHeader->bfSize - sizeof(BITMAPFILEHEADER), 1, fICOFile) != 1)
+            goto error4;
+    }
+    else
+    {
+        if ((pIconDirEntry = HeapAlloc(GetProcessHeap(), 0, iconDir.idCount * sizeof (ICONDIRENTRY))) == NULL)
+            goto error2;
+        if (fread(pIconDirEntry, sizeof (ICONDIRENTRY), iconDir.idCount, fICOFile) != iconDir.idCount)
+            goto error3;
+
+        for (i = 0; i < iconDir.idCount; i++)
+            if ((pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth) > nMax)
+            {
+                nIndex = i;
+                nMax = pIconDirEntry[i].bHeight * pIconDirEntry[i].bWidth;
+            }
+        if ((pIcon = HeapAlloc(GetProcessHeap(), 0, pIconDirEntry[nIndex].dwBytesInRes)) == NULL)
+            goto error3;
+        if (fseek(fICOFile, pIconDirEntry[nIndex].dwImageOffset, SEEK_SET))
+            goto error4;
+        if (fread(pIcon, pIconDirEntry[nIndex].dwBytesInRes, 1, fICOFile) != 1)
+            goto error4;
+    }
 
     if(!SaveIconResAsXPM(pIcon, szXPMFileName, szFileName))
         goto error4;


More information about the wine-patches mailing list