[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