winemenubuilder: extract icons from NE binaries too (try 2)

Damjan Jovanovic damjan.jov at gmail.com
Sun May 22 07:09:05 CDT 2011


Changelog:
* winemenubuilder: extract icons from NE binaries too

Try 2 manually parses the NE file instead of using krnl386.exe functions.

Damjan Jovanovic
-------------- next part --------------
diff --git a/programs/winemenubuilder/winemenubuilder.c b/programs/winemenubuilder/winemenubuilder.c
index 5908e4e..2aa4b2a 100644
--- a/programs/winemenubuilder/winemenubuilder.c
+++ b/programs/winemenubuilder/winemenubuilder.c
@@ -147,6 +147,25 @@ typedef struct
     WORD idCount;
 } ICONDIR;
 
+typedef struct
+{
+    WORD offset;
+    WORD length;
+    WORD flags;
+    WORD id;
+    WORD handle;
+    WORD usage;
+} NE_NAMEINFO;
+
+typedef struct
+{
+    WORD  type_id;
+    WORD  count;
+    DWORD resloader;
+} NE_TYPEINFO;
+
+#define NE_RSCTYPE_ICON        0x8003
+#define NE_RSCTYPE_GROUP_ICON  0x800e
 
 #include "poppack.h"
 
@@ -491,7 +510,99 @@ end:
     return hr;
 }
 
-static IStream *add_module_icons_to_stream(HMODULE hModule, GRPICONDIR *grpIconDir)
+struct IconData16 {
+    BYTE *fileBytes;
+    DWORD fileSize;
+    NE_TYPEINFO *iconResources;
+    WORD alignmentShiftCount;
+};
+
+static int populate_module16_icons(struct IconData16 *iconData16, GRPICONDIR *grpIconDir, ICONDIRENTRY *iconDirEntries, BYTE *icons, SIZE_T *iconOffset)
+{
+    int i, j;
+    int validEntries = 0;
+
+    for (i = 0; i < grpIconDir->idCount; i++)
+    {
+        BYTE *iconPtr = (BYTE*)iconData16->iconResources;
+        NE_NAMEINFO *matchingIcon = NULL;
+        iconPtr += sizeof(NE_TYPEINFO);
+        for (j = 0; j < iconData16->iconResources->count; j++)
+        {
+            NE_NAMEINFO *iconInfo = (NE_NAMEINFO*)iconPtr;
+            if ((((BYTE*)iconPtr) + sizeof(NE_NAMEINFO)) > (iconData16->fileBytes + iconData16->fileSize))
+            {
+                WINE_WARN("file too small for icon NE_NAMEINFO\n");
+                break;
+            }
+            if (iconInfo->id == (0x8000 | grpIconDir->idEntries[i].nID))
+            {
+                matchingIcon = iconInfo;
+                break;
+            }
+            iconPtr += sizeof(NE_NAMEINFO);
+        }
+
+        if (matchingIcon == NULL)
+            continue;
+        if (((matchingIcon->offset << iconData16->alignmentShiftCount) + grpIconDir->idEntries[i].dwBytesInRes) > iconData16->fileSize)
+        {
+            WINE_WARN("file too small for icon contents\n");
+            break;
+        }
+
+        iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
+        iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
+        iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
+        iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
+        iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
+        iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
+        iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
+        iconDirEntries[validEntries].dwImageOffset = *iconOffset;
+        validEntries++;
+        memcpy(&icons[*iconOffset], &iconData16->fileBytes[matchingIcon->offset << iconData16->alignmentShiftCount], grpIconDir->idEntries[i].dwBytesInRes);
+        *iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
+    }
+    return validEntries;
+}
+
+static int populate_module_icons(HMODULE hModule, GRPICONDIR *grpIconDir, ICONDIRENTRY *iconDirEntries, BYTE *icons, SIZE_T *iconOffset)
+{
+    int i;
+    int validEntries = 0;
+
+    for (i = 0; i < grpIconDir->idCount; i++)
+    {
+        HRSRC hResInfo;
+        LPCWSTR lpName = MAKEINTRESOURCEW(grpIconDir->idEntries[i].nID);
+        if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON)))
+        {
+            HGLOBAL hResData;
+            if ((hResData = LoadResource(hModule, hResInfo)))
+            {
+                BITMAPINFO *pIcon;
+                if ((pIcon = LockResource(hResData)))
+                {
+                    iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
+                    iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
+                    iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
+                    iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
+                    iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
+                    iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
+                    iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
+                    iconDirEntries[validEntries].dwImageOffset = *iconOffset;
+                    validEntries++;
+                    memcpy(&icons[*iconOffset], pIcon, grpIconDir->idEntries[i].dwBytesInRes);
+                    *iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
+                }
+                FreeResource(hResData);
+            }
+        }
+    }
+    return validEntries;
+}
+
+static IStream *add_module_icons_to_stream(struct IconData16 *iconData16, HMODULE hModule, GRPICONDIR *grpIconDir)
 {
     int i;
     SIZE_T iconsSize = 0;
@@ -529,34 +640,10 @@ static IStream *add_module_icons_to_stream(HMODULE hModule, GRPICONDIR *grpIconD
     }
 
     iconOffset = 0;
-    for (i = 0; i < grpIconDir->idCount; i++)
-    {
-        HRSRC hResInfo;
-        LPCWSTR lpName = MAKEINTRESOURCEW(grpIconDir->idEntries[i].nID);
-        if ((hResInfo = FindResourceW(hModule, lpName, (LPCWSTR)RT_ICON)))
-        {
-            HGLOBAL hResData;
-            if ((hResData = LoadResource(hModule, hResInfo)))
-            {
-                BITMAPINFO *pIcon;
-                if ((pIcon = LockResource(hResData)))
-                {
-                    iconDirEntries[validEntries].bWidth = grpIconDir->idEntries[i].bWidth;
-                    iconDirEntries[validEntries].bHeight = grpIconDir->idEntries[i].bHeight;
-                    iconDirEntries[validEntries].bColorCount = grpIconDir->idEntries[i].bColorCount;
-                    iconDirEntries[validEntries].bReserved = grpIconDir->idEntries[i].bReserved;
-                    iconDirEntries[validEntries].wPlanes = grpIconDir->idEntries[i].wPlanes;
-                    iconDirEntries[validEntries].wBitCount = grpIconDir->idEntries[i].wBitCount;
-                    iconDirEntries[validEntries].dwBytesInRes = grpIconDir->idEntries[i].dwBytesInRes;
-                    iconDirEntries[validEntries].dwImageOffset = iconOffset;
-                    validEntries++;
-                    memcpy(&icons[iconOffset], pIcon, grpIconDir->idEntries[i].dwBytesInRes);
-                    iconOffset += grpIconDir->idEntries[i].dwBytesInRes;
-                }
-                FreeResource(hResData);
-            }
-        }
-    }
+    if (iconData16)
+        validEntries = populate_module16_icons(iconData16, grpIconDir, iconDirEntries, icons, &iconOffset);
+    else if (hModule)
+        validEntries = populate_module_icons(hModule, grpIconDir, iconDirEntries, icons, &iconOffset);
 
     if (validEntries == 0)
     {
@@ -601,6 +688,137 @@ end:
     return stream;
 }
 
+static HRESULT open_module16_icon(LPCWSTR szFileName, int nIndex, IStream **ppStream)
+{
+    HANDLE hFile = INVALID_HANDLE_VALUE;
+    HANDLE hFileMapping = NULL;
+    DWORD fileSize;
+    BYTE *fileBytes = NULL;
+    IMAGE_DOS_HEADER *dosHeader;
+    IMAGE_OS2_HEADER *neHeader;
+    BYTE *rsrcTab;
+    NE_TYPEINFO *iconGroupResources;
+    NE_TYPEINFO *iconResources;
+    NE_NAMEINFO *iconDirPtr;
+    GRPICONDIR *iconDir;
+    WORD alignmentShiftCount;
+    struct IconData16 iconData16;
+    HRESULT hr = E_FAIL;
+
+    hFile = CreateFileW(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
+        OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+    if (hFile == INVALID_HANDLE_VALUE)
+    {
+        WINE_WARN("opening %s failed with error %d\n", wine_dbgstr_w(szFileName), GetLastError());
+        goto end;
+    }
+
+    hFileMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
+    if (hFileMapping == NULL)
+    {
+        WINE_WARN("CreateFileMapping failed, error %d\n", GetLastError());
+        goto end;
+    }
+
+    fileSize = GetFileSize(hFile, NULL);
+
+    fileBytes = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
+    if (fileBytes == NULL)
+    {
+        WINE_WARN("MapViewOfFile failed, error %d\n", GetLastError());
+        goto end;
+    }
+
+    dosHeader = (IMAGE_DOS_HEADER*)fileBytes;
+    if (sizeof(IMAGE_DOS_HEADER) >= fileSize || dosHeader->e_magic != IMAGE_DOS_SIGNATURE)
+    {
+        WINE_WARN("file too small for MZ header\n");
+        goto end;
+    }
+
+    neHeader = (IMAGE_OS2_HEADER*)(fileBytes + dosHeader->e_lfanew);
+    if ((((BYTE*)neHeader) + sizeof(IMAGE_OS2_HEADER)) > (fileBytes + fileSize) ||
+        neHeader->ne_magic != IMAGE_OS2_SIGNATURE)
+    {
+        WINE_WARN("file too small for NE header\n");
+        goto end;
+    }
+
+    rsrcTab = ((BYTE*)neHeader) + neHeader->ne_rsrctab;
+    if ((rsrcTab + 2) > (fileBytes + fileSize))
+    {
+        WINE_WARN("file too small for resource table\n");
+        goto end;
+    }
+
+    alignmentShiftCount = *(WORD*)rsrcTab;
+    rsrcTab += 2;
+    iconGroupResources = NULL;
+    iconResources = NULL;
+    for (;;)
+    {
+        NE_TYPEINFO *neTypeInfo = (NE_TYPEINFO*)rsrcTab;
+        if ((rsrcTab + sizeof(NE_TYPEINFO)) > (fileBytes + fileSize))
+        {
+            WINE_WARN("file too small for resource table\n");
+            goto end;
+        }
+        if (neTypeInfo->type_id == 0)
+            break;
+        else if (neTypeInfo->type_id == NE_RSCTYPE_GROUP_ICON)
+            iconGroupResources = neTypeInfo;
+        else if (neTypeInfo->type_id == NE_RSCTYPE_ICON)
+            iconResources = neTypeInfo;
+        rsrcTab += sizeof(NE_TYPEINFO) + neTypeInfo->count*sizeof(NE_NAMEINFO);
+    }
+    if (iconGroupResources == NULL)
+    {
+        WINE_WARN("no group icon resource type found\n");
+        goto end;
+    }
+    if (iconResources == NULL)
+    {
+        WINE_WARN("no icon resource type found\n");
+        goto end;
+    }
+
+    if (nIndex >= iconGroupResources->count)
+    {
+        WINE_WARN("icon index out of range\n");
+        goto end;
+    }
+
+    iconDirPtr = (NE_NAMEINFO*)(((BYTE*)iconGroupResources) + sizeof(NE_TYPEINFO) + nIndex*sizeof(NE_NAMEINFO));
+    if ((((BYTE*)iconDirPtr) + sizeof(NE_NAMEINFO)) > (fileBytes + fileSize))
+    {
+        WINE_WARN("file to small for icon group NE_NAMEINFO\n");
+        goto end;
+    }
+    iconDir = (GRPICONDIR*)(fileBytes + (iconDirPtr->offset << alignmentShiftCount));
+    if ((((BYTE*)iconDir) + sizeof(GRPICONDIR) + iconDir->idCount*sizeof(GRPICONDIRENTRY)) > (fileBytes + fileSize))
+    {
+        WINE_WARN("file too small for GRPICONDIR\n");
+        goto end;
+    }
+
+    iconData16.fileBytes = fileBytes;
+    iconData16.fileSize = fileSize;
+    iconData16.iconResources = iconResources;
+    iconData16.alignmentShiftCount = alignmentShiftCount;
+    *ppStream = add_module_icons_to_stream(&iconData16, NULL, iconDir);
+    if (*ppStream)
+        hr = S_OK;
+
+end:
+    if (hFile != INVALID_HANDLE_VALUE)
+        CloseHandle(hFile);
+    if (hFileMapping != NULL)
+        CloseHandle(hFileMapping);
+    if (fileBytes != NULL)
+        UnmapViewOfFile(fileBytes);
+    return hr;
+}
+
 static BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCWSTR lpszType, LPWSTR lpszName, LONG_PTR lParam)
 {
     ENUMRESSTRUCT *sEnumRes = (ENUMRESSTRUCT *) lParam;
@@ -626,9 +844,14 @@ static HRESULT open_module_icon(LPCWSTR szFileName, int nIndex, IStream **ppStre
     hModule = LoadLibraryExW(szFileName, 0, LOAD_LIBRARY_AS_DATAFILE);
     if (!hModule)
     {
-        WINE_WARN("LoadLibraryExW (%s) failed, error %d\n",
-                 wine_dbgstr_w(szFileName), GetLastError());
-        return HRESULT_FROM_WIN32(GetLastError());
+        if (GetLastError() == ERROR_BAD_EXE_FORMAT)
+            return open_module16_icon(szFileName, nIndex, ppStream);
+        else
+        {
+            WINE_WARN("LoadLibraryExW (%s) failed, error %d\n",
+                     wine_dbgstr_w(szFileName), GetLastError());
+            return HRESULT_FROM_WIN32(GetLastError());
+        }
     }
 
     if (nIndex < 0)
@@ -656,7 +879,7 @@ static HRESULT open_module_icon(LPCWSTR szFileName, int nIndex, IStream **ppStre
         {
             if ((pIconDir = LockResource(hResData)))
             {
-                *ppStream = add_module_icons_to_stream(hModule, pIconDir);
+                *ppStream = add_module_icons_to_stream(0, hModule, pIconDir);
                 if (*ppStream)
                     hr = S_OK;
             }


More information about the wine-patches mailing list