fixed LoadCursorIconImage (Thunderbird is now working)
Modified: trunk/reactos/lib/user32/windows/bitmap.c
_____
Modified: trunk/reactos/lib/user32/windows/bitmap.c
--- trunk/reactos/lib/user32/windows/bitmap.c 2006-01-14 12:18:10 UTC
(rev 20848)
+++ trunk/reactos/lib/user32/windows/bitmap.c 2006-01-14 12:42:04 UTC
(rev 20849)
@@ -30,6 +30,29 @@
#include <user32.h>
+#include "pshpack1.h"
+
+typedef struct {
+ BYTE bWidth;
+ BYTE bHeight;
+ BYTE bColorCount;
+ BYTE bReserved;
+ WORD xHotspot;
+ WORD yHotspot;
+ DWORD dwDIBSize;
+ DWORD dwDIBOffset;
+} CURSORICONFILEDIRENTRY;
+
+typedef struct
+{
+ WORD idReserved;
+ WORD idType;
+ WORD idCount;
+ CURSORICONFILEDIRENTRY idEntries[1];
+} CURSORICONFILEDIR;
+
+#include "poppack.h"
+
/*forward declerations... actualy in user32\windows\icon.c but usful
here****/
HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE*
IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE*
IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
@@ -71,6 +94,87 @@
}
+/*
+ * The following macro functions account for the irregularities of
+ * accessing cursor and icon resources in files and resource entries.
+ */
+typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
+ int *width, int *height, int *bits );
+
+/**********************************************************************
+ * CURSORICON_FindBestCursor2
+ *
+ * Find the cursor closest to the requested size.
+ * FIXME: parameter 'color' ignored and entries with more than 1 bpp
+ * ignored too
+ */
+static int CURSORICON_FindBestCursor2( LPVOID dir, fnGetCIEntry
get_entry,
+ int width, int height, int color
)
+{
+ int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
+
+ /* Double height to account for AND and XOR masks */
+
+ height *= 2;
+
+ /* First find the largest one smaller than or equal to the
requested size*/
+
+ maxwidth = maxheight = 0;
+ for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
+ {
+ if ((cx <= width) && (cy <= height) &&
+ (cx > maxwidth) && (cy > maxheight) &&
+ (bits == 1))
+ {
+ bestEntry = i;
+ maxwidth = cx;
+ maxheight = cy;
+ }
+ }
+ if (bestEntry != -1) return bestEntry;
+
+ /* Now find the smallest one larger than the requested size */
+
+ maxwidth = maxheight = 255;
+ for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
+ {
+ if (((cx < maxwidth) && (cy < maxheight) && (bits == 1))
||
+ (bestEntry==-1))
+ {
+ bestEntry = i;
+ maxwidth = cx;
+ maxheight = cy;
+ }
+ }
+
+ return bestEntry;
+}
+
+static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
+ int *width, int *height, int *bits
)
+{
+ CURSORICONFILEDIR *filedir = dir;
+ CURSORICONFILEDIRENTRY *entry;
+
+ if ( filedir->idCount <= n )
+ return FALSE;
+ entry = &filedir->idEntries[n];
+ *width = entry->bWidth;
+ *height = entry->bHeight;
+ *bits = entry->bColorCount;
+ return TRUE;
+}
+
+static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile(
CURSORICONFILEDIR *dir,
+ int width, int height, int color
)
+{
+ int n = CURSORICON_FindBestCursor2( dir, CURSORICON_GetFileEntry,
+ width, height, color );
+ if ( n < 0 )
+ return NULL;
+ return &dir->idEntries[n];
+}
+
static HANDLE
LoadCursorIconImage(
HINSTANCE hinst,
@@ -85,19 +189,20 @@
HANDLE hfRes;
HANDLE hFile;
HANDLE hSection;
- CURSORICONDIR *IconDIR;
+ CURSORICONFILEDIR *IconDIR;
HDC hScreenDc;
HICON hIcon;
ULONG HeaderSize;
ULONG ColorCount;
ULONG ColorBits;
PVOID Data;
- CURSORICONDIRENTRY* dirEntry;
+ CURSORICONFILEDIRENTRY* dirEntry;
ICONIMAGE* SafeIconImage = NULL;
GRPCURSORICONDIR* IconResDir;
INT id;
ICONIMAGE *ResIcon;
BOOL Icon = (uType == IMAGE_ICON);
+ DWORD filesize = 0;
if (!(fuLoad & LR_LOADFROMFILE))
{
@@ -158,14 +263,6 @@
return hIcon;
}
- /*
- * FIXME: This code is incorrect and is likely to crash in many
cases.
- * In the file the cursor/icon directory records are stored like
- * CURSORICONFILEDIR, but we treat them like CURSORICONDIR. In Wine
- * this is solved by creating a fake cursor/icon directory in memory
- * and passing that to CURSORICON_FindBestIcon.
- */
-
if (fuLoad & LR_SHARED)
{
DbgPrint("FIXME: need LR_SHARED support for loading icon images
from files\n");
@@ -177,6 +274,7 @@
return NULL;
hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0,
NULL);
+ filesize = GetFileSize( hFile, NULL );
CloseHandle(hFile);
if (hSection == NULL)
return NULL;
@@ -219,7 +317,7 @@
}
/* Pick the best size. */
- dirEntry = (CURSORICONDIRENTRY *)CURSORICON_FindBestIcon(IconDIR,
width, height, ColorBits);
+ dirEntry = CURSORICON_FindBestCursorFile( IconDIR, width, height,
ColorBits );
if (!dirEntry)
{
DeleteDC(hScreenDc);
@@ -227,7 +325,20 @@
return NULL;
}
- SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0,
dirEntry->dwBytesInRes);
+ if ( dirEntry->dwDIBOffset > filesize )
+ {
+ DeleteDC(hScreenDc);
+ UnmapViewOfFile(IconDIR);
+ return NULL;
+ }
+
+ if ( dirEntry->dwDIBOffset + dirEntry->dwDIBSize > filesize ){
+ DeleteDC(hScreenDc);
+ UnmapViewOfFile(IconDIR);
+ return NULL;
+ }
+
+ SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0,
dirEntry->dwDIBSize);
if (SafeIconImage == NULL)
{
DeleteDC(hScreenDc);
@@ -235,7 +346,7 @@
return NULL;
}
- memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwImageOffset,
dirEntry->dwBytesInRes);
+ memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwDIBOffset,
dirEntry->dwDIBSize);
UnmapViewOfFile(IconDIR);
/* At this point we have a copy of the icon image to play with. */