[6/6] USER: Add support for loading .ANI cursors
H. Verbeet
hverbeet at gmail.com
Tue Apr 18 16:50:41 CDT 2006
This patch adds support for loading .ANI cursors to
CreateIconFromResourceEx. Since .ANI files are RIFF files, the mmio*
functions are required for loading them.
Changelog:
- Add support for loading .ANI cursors.
-------------- next part --------------
diff --git a/dlls/user/Makefile.in b/dlls/user/Makefile.in
index fea90ac..44a4cc4 100644
--- a/dlls/user/Makefile.in
+++ b/dlls/user/Makefile.in
@@ -6,7 +6,7 @@ VPATH = @srcdir@
MODULE = user32.dll
IMPORTLIB = libuser32.$(IMPLIBEXT)
IMPORTS = gdi32 advapi32 kernel32 ntdll
-DELAYIMPORTS = imm32
+DELAYIMPORTS = imm32 winmm
EXTRALIBS = $(LIBUNICODE)
SPEC_SRCS16 = \
diff --git a/dlls/user/cursoricon.c b/dlls/user/cursoricon.c
index e61ded8..033cfaf 100644
--- a/dlls/user/cursoricon.c
+++ b/dlls/user/cursoricon.c
@@ -5,6 +5,7 @@
* 1996 Martin Von Loewis
* 1997 Alex Korobka
* 1998 Turchanov Sergey
+ * 2006 Henri Verbeet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -67,6 +68,7 @@
#include "wine/exception.h"
#include "wine/debug.h"
#include "user_private.h"
+#include "mmsystem.h"
WINE_DEFAULT_DEBUG_CHANNEL(cursor);
WINE_DECLARE_DEBUG_CHANNEL(icon);
@@ -675,6 +677,9 @@ static CURSORICONFILEDIRENTRY *CURSORICO
/**********************************************************************
* .ANI cursor support
*/
+#define ANI_FLAG_ICON 0x1
+#define ANI_FLAG_SEQUENCE 0x2
+
typedef struct {
DWORD header_size;
DWORD num_frames;
@@ -704,6 +709,126 @@ static void free_ani_info(ani_info *info
HeapFree(GetProcessHeap(), 0, info->seq);
}
+static void dump_ani_header(const ani_header *header)
+{
+ TRACE(" header size: %ld\n", header->header_size);
+ TRACE(" frames: %ld\n", header->num_frames);
+ TRACE(" steps: %ld\n", header->num_steps);
+ TRACE(" width: %ld\n", header->width);
+ TRACE(" height: %ld\n", header->height);
+ TRACE(" bpp: %ld\n", header->bpp);
+ TRACE(" planes: %ld\n", header->num_planes);
+ TRACE(" display rate: %ld\n", header->display_rate);
+ TRACE(" flags: 0x%08lx\n", header->flags);
+}
+
+static void load_ani(const LPBYTE bits, DWORD bits_size, ani_info *info, INT width, INT height)
+{
+ LPBYTE ptr = 0;
+ int i;
+ HMMIO hmmio;
+ MMIOINFO mmio_info = {0};
+ MMCKINFO root_chunk, anih, seq, icon_list, icon_chunk;
+ CURSORICONFILEDIR *dir = 0;
+ WORD max_count = 0;
+
+ TRACE("bits %p, bits_size %ld, ani_info %p\n", bits, bits_size, info);
+
+ mmio_info.fccIOProc = FOURCC_MEM;
+ mmio_info.pchBuffer = bits;
+ mmio_info.cchBuffer = bits_size;
+ hmmio = mmioOpenW(NULL, &mmio_info, MMIO_READWRITE);
+ if (!hmmio) return;
+
+ root_chunk.fccType = mmioFOURCC('A', 'C', 'O', 'N');
+ if (mmioDescend(hmmio, &root_chunk, 0, MMIO_FINDRIFF))
+ {
+ ERR("Failed to get root chunk.\n");
+ mmioClose(hmmio, 0);
+ return;
+ }
+
+ anih.ckid = mmioFOURCC('a', 'n', 'i', 'h');
+ if (mmioDescend(hmmio, &anih, &root_chunk, MMIO_FINDCHUNK))
+ {
+ ERR("Failed to get 'anih' chunk.\n");
+ mmioClose(hmmio, 0);
+ return;
+ }
+ mmioRead(hmmio, (char *)&(info->header), sizeof(info->header));
+ mmioAscend(hmmio, &anih, 0);
+ dump_ani_header(&(info->header));
+
+ if (info->header.flags & ANI_FLAG_SEQUENCE)
+ {
+ TRACE("Loading sequence data.\n");
+ seq.ckid = mmioFOURCC('s', 'e', 'q', ' ');
+ if (mmioDescend(hmmio, &seq, &root_chunk, MMIO_FINDCHUNK))
+ {
+ ERR("Failed to get 'seq ' chunk\n");
+ mmioClose(hmmio, 0);
+ return;
+ }
+ info->seq = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * info->header.num_steps);
+ mmioRead(hmmio, (char *)info->seq, sizeof(DWORD) * info->header.num_steps);
+ mmioAscend(hmmio, &seq, 0);
+ }
+
+ icon_list.fccType = mmioFOURCC('f', 'r', 'a', 'm');
+ if (mmioDescend(hmmio, &icon_list, &root_chunk, MMIO_FINDLIST))
+ {
+ ERR("Failed to get icon list\n");
+ mmioClose(hmmio, 0);
+ return;
+ }
+
+ if (mmioDescend(hmmio, &icon_chunk, &icon_list, 0))
+ {
+ ERR("Failed to get icon chunk\n");
+ mmioClose(hmmio, 0);
+ return;
+ }
+ info->data = HeapAlloc(GetProcessHeap(), 0, info->header.num_frames * sizeof(LPBYTE));
+ for (i = 0; i < info->header.num_frames; ++i)
+ {
+ WORD count;
+ CURSORICONFILEDIRENTRY *entry;
+ LONG chunk_start = mmioSeek(hmmio, 0, SEEK_CUR);
+
+ mmioSeek(hmmio, 4, SEEK_CUR); /* Skip magic */
+ mmioRead(hmmio, (char *)&count, 2);
+
+ /* There's a decent chance the amount of entries will be the same for each icon */
+ if (count > max_count)
+ {
+ HeapFree(GetProcessHeap(), 0, dir);
+ dir = HeapAlloc(GetProcessHeap(), 0, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6);
+ max_count = count;
+ }
+ mmioSeek(hmmio, chunk_start, SEEK_SET);
+ mmioRead(hmmio, (char *)dir, (count * sizeof(CURSORICONFILEDIRENTRY)) + 6);
+ entry = CURSORICON_FindBestCursorFile(dir, width, height, 1);
+
+ ptr = HeapAlloc(GetProcessHeap(), 0, (entry->dwDIBSize)+sizeof(POINT16));
+ info->data[i] = ptr;
+ if (!info->header.width || !info->header.height)
+ {
+ info->header.width = entry->bWidth;
+ info->header.height = entry->bHeight;
+ }
+ ((POINT16 *)ptr)->x = entry->xHotspot;
+ ((POINT16 *)ptr)->y = entry->yHotspot;
+ ptr += sizeof(POINT16);
+ mmioSeek(hmmio, chunk_start+entry->dwDIBOffset, SEEK_SET);
+ mmioRead(hmmio, ptr, entry->dwDIBSize);
+
+ if (mmioDescend(hmmio, &icon_chunk, &icon_list, 0)) break;
+ }
+ HeapFree(GetProcessHeap(), 0, dir);
+
+ mmioClose(hmmio, 0);
+}
+
/**********************************************************************
* CreateIconFromResourceEx (USER32.@)
*
@@ -742,25 +867,30 @@ HICON WINAPI CreateIconFromResourceEx( L
return 0;
}
- bmi = (BITMAPINFO *)(bits + (bIcon ? 0 : sizeof(POINT16)));
-
- /* Check bitmap header */
- if ((bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
- && (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)
- || bmi->bmiHeader.biCompression != BI_RGB))
+ if (!memcmp(bits, "RIFF", 4))
{
- WARN_(cursor)("\tinvalid resource bitmap header.\n");
- free_ani_info(&ani_info);
- return 0;
- }
+ load_ani(bits, cbSize, &ani_info, width, height);
+ } else {
+ bmi = (BITMAPINFO *)(bits + (bIcon ? 0 : sizeof(POINT16)));
+
+ /* Check bitmap header */
+ if ((bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
+ && (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)
+ || bmi->bmiHeader.biCompression != BI_RGB))
+ {
+ WARN_(cursor)("\tinvalid resource bitmap header.\n");
+ free_ani_info(&ani_info);
+ return 0;
+ }
- ani_info.header.num_steps = 1;
- ani_info.header.num_frames = 1;
- ani_info.header.bpp = bmi->bmiHeader.biBitCount;
- ani_info.header.width = bmi->bmiHeader.biWidth;
- ani_info.header.height = bmi->bmiHeader.biHeight >> 1;
- ani_info.data = HeapAlloc(GetProcessHeap(), 0, sizeof(LPBYTE));
- ani_info.data[0] = bits;
+ ani_info.header.num_steps = 1;
+ ani_info.header.num_frames = 1;
+ ani_info.header.bpp = bmi->bmiHeader.biBitCount;
+ ani_info.header.width = bmi->bmiHeader.biWidth;
+ ani_info.header.height = (bmi->bmiHeader.biHeight >> 1);
+ ani_info.data = HeapAlloc(GetProcessHeap(), 0, sizeof(LPBYTE));
+ ani_info.data[0] = bits;
+ }
if (!width) width = ani_info.header.width;
if (!height) height = ani_info.header.height;;
@@ -995,6 +1125,12 @@ static HICON CURSORICON_LoadFromFile( LP
if (!memcmp(bits, "\x00\x00\x01\x00", 4)) fCursor = FALSE;
/* Same thing for .CUR */
else if (!memcmp(bits, "\x00\x00\x02\x00", 4)) fCursor = TRUE;
+ else if (!memcmp(bits, "RIFF", 4))
+ {
+ hIcon = CreateIconFromResourceEx(bits, filesize,
+ FALSE, 0x00030000, width, height, loadflags);
+ goto end;
+ }
dir = (CURSORICONFILEDIR*) bits;
if ( filesize < sizeof(*dir) )
More information about the wine-patches
mailing list