|
|
/****************************** Module Header ******************************\
* Module Name: acons.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains code for dealing with animated icons/cursors. * * History: * 10-02-91 DarrinM Created. * 07-30-92 DarrinM Unicodized. * 11-28-94 JimA Moved to client from server. \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
/*
* Resource Directory format for IconEditor generated icon and cursor * (.ICO & .CUR) files. All fields are shared except xHotspot and yHotspot * which are only valid for cursors. */ typedef struct _ICONFILERESDIR { // ird
BYTE bWidth; BYTE bHeight; BYTE bColorCount; BYTE bReserved; WORD xHotspot; WORD yHotspot; DWORD dwDIBSize; DWORD dwDIBOffset; } ICONFILERESDIR;
typedef struct _HOTSPOTREC { // hs
WORD xHotspot; WORD yHotspot; } HOTSPOTREC;
PCURSORRESOURCE ReadIconGuts( IN PFILEINFO pfi, IN LPNEWHEADER pnhBase, IN int offResBase, OUT LPWSTR *prt, IN int cxDesired, IN int cyDesired, IN DWORD LR_flags);
BOOL ReadTag( IN PFILEINFO pfi, OUT PRTAG ptag);
BOOL ReadChunk( IN PFILEINFO pfi, IN PRTAG ptag, OUT PVOID pv);
BOOL SkipChunk( IN PFILEINFO pfi, IN PRTAG ptag);
HICON CreateAniIcon( LPCWSTR pszName, LPWSTR rt, int cicur, DWORD *aicur, int cpcur, HCURSOR *ahcur, JIF jifRate, PJIF ajifRate, BOOL fPublic);
HCURSOR ReadIconFromFileMap( IN PFILEINFO pfi, IN int cbSize, IN DWORD cxDesired, IN DWORD cyDesired, IN DWORD LR_flags);
HICON LoadAniIcon( IN PFILEINFO pfi, IN LPWSTR rt, IN DWORD cxDesired, IN DWORD cyDesired, IN DWORD LR_flags);
/***************************************************************************\
* LoadCursorFromFile (API) * * Called by SetSystemCursor. * * History: * 08-03-92 DarrinM Created. \***************************************************************************/
FUNCLOG1(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorFromFileW, LPCWSTR, pszFilename) HCURSOR WINAPI LoadCursorFromFileW( LPCWSTR pszFilename) { return(LoadImage(NULL, pszFilename, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE)); }
/***********************************************************************\
* LoadCursorFromFileA * * Returns: hCursor * * 10/9/1995 Created SanfordS \***********************************************************************/
FUNCLOG1(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorFromFileA, LPCSTR, pszFilename) HCURSOR WINAPI LoadCursorFromFileA( LPCSTR pszFilename) { LPWSTR lpUniName; HCURSOR hcur;
if (pszFilename == NULL || !MBToWCS(pszFilename, -1, &lpUniName, -1, TRUE)) return (HANDLE)NULL;
hcur = LoadCursorFromFileW(lpUniName);
UserLocalFree(lpUniName);
return hcur; }
/***********************************************************************\
* ReadFilePtr * * Works like ReadFile but with pointers to a mapped file buffer. * * Returns: * * 11/16/1995 Created SanfordS \***********************************************************************/ BOOL ReadFilePtr( IN PFILEINFO pfi, OUT LPVOID *ppBuf, IN DWORD cb) { *ppBuf = pfi->pFilePtr; pfi->pFilePtr += cb; return (pfi->pFilePtr <= pfi->pFileEnd); }
/***********************************************************************\
* ReadFilePtrUnaligned * * Works like ReadFile but with pointers to a mapped file buffer. * * Returns: * * 11/16/1995 Created SanfordS \***********************************************************************/ BOOL ReadFilePtrUnaligned( IN PFILEINFO pfi, OUT VOID UNALIGNED **ppBuf, IN DWORD cb) { *ppBuf = pfi->pFilePtr; pfi->pFilePtr += cb; return (pfi->pFilePtr <= pfi->pFileEnd); }
/***********************************************************************\
* ReadFilePtrCopy * * Works even more like ReadFile in that is copies data to the given buffer. * * Returns: * * 11/16/1995 Created SanfordS \***********************************************************************/ BOOL ReadFilePtrCopy( IN PFILEINFO pfi, IN OUT LPVOID pBuf, IN DWORD cb) { if (pfi->pFilePtr + cb > pfi->pFileEnd) { return(FALSE); } RtlCopyMemory(pBuf, pfi->pFilePtr, cb); pfi->pFilePtr += cb; return TRUE; }
/***************************************************************************\
* ReadTag, ReadChunk, SkipChunk * * Some handy functions for reading RIFF files. * * History: * 10-02-91 DarrinM Created. * 03-25-93 Jonpa Changed to use RIFF format instead of ASDF \***************************************************************************/ BOOL ReadTag( IN PFILEINFO pfi, OUT PRTAG ptag) { ptag->ckID = ptag->ckSize = 0L; // in case we fail the read.
return(ReadFilePtrCopy(pfi, ptag, sizeof(RTAG))); }
BOOL ReadChunk( IN PFILEINFO pfi, IN PRTAG ptag, OUT PVOID pv) { if (!ReadFilePtrCopy(pfi, pv, ptag->ckSize)) return FALSE;
/* WORD align file pointer */ if( ptag->ckSize & 1 ) pfi->pFilePtr++;
if (pfi->pFilePtr <= pfi->pFileEnd) { return TRUE; } else { RIPMSG0(RIP_WARNING, "ReadChunk: Advanced pointer past end of file map"); return FALSE; } }
BOOL SkipChunk( IN PFILEINFO pfi, IN PRTAG ptag) { /*
* Round ptag->ckSize up to nearest word boundary * to maintain alignment */ pfi->pFilePtr += (ptag->ckSize + 1) & (~1); if (pfi->pFilePtr <= pfi->pFileEnd) { return TRUE; } else { RIPMSG0(RIP_WARNING, "SkipChunk: Advanced pointer past end of file map"); return FALSE; } }
/***************************************************************************\
* LoadCursorIconFromFileMap * * If pszName is one of the IDC_* values then we use WIN.INI to find a * custom cursor/icon. Otherwise, pszName points to a filename of a .ICO/.CUR * file to be loaded. If the file is an .ANI file containing a multiframe * animation then LoadAniIcon is called to create an ACON. Otherwise if * the file is an .ANI file containing just a single frame then it is loaded * and a normal CURSOR/ICON resource is created from it. * * 12-26-91 DarrinM Wrote it. * 03-17-93 JonPa Changed to use RIFF format for ani-cursors * 11/16/1995 SanfordS Added LR_flags support \***************************************************************************/
HANDLE LoadCursorIconFromFileMap( IN PFILEINFO pfi, IN OUT LPWSTR *prt, IN DWORD cxDesired, IN DWORD cyDesired, IN DWORD LR_flags, OUT LPBOOL pfAni) { LPNEWHEADER pnh; int offResBase;
*pfAni = FALSE; offResBase = 0;
/*
* Determine if this is an .ICO/.CUR file or an .ANI file. */ pnh = (LPNEWHEADER)pfi->pFileMap; if (*(LPDWORD)pnh == FOURCC_RIFF) {
RTAG tag;
/*
* It's an ANICURSOR! * Seek back to beginning + 1 tag. */ pfi->pFilePtr = pfi->pFileMap + sizeof(tag);
/* check RIFF type for ACON */ if (*(LPDWORD)pfi->pFilePtr != FOURCC_ACON) { return NULL; } pfi->pFilePtr += sizeof(DWORD); if (pfi->pFilePtr > pfi->pFileEnd) { return NULL; }
/*
* Ok, we have a ACON chunk. Find the first ICON chunk and set * things up so it looks we've just loaded the header of a normal * .CUR file, then fall into the .CUR bits handling code below. */ while (ReadTag(pfi, &tag)) { /*
* Handle each chunk type. */ if (tag.ckID == FOURCC_anih) {
ANIHEADER anih;
if (!ReadChunk(pfi, &tag, &anih)) { return NULL; }
if (!(anih.fl & AF_ICON) || (anih.cFrames == 0)) { return NULL; }
// If this ACON has more than one frame then go ahead
// and create an ACON, otherwise just use the first
// frame to create a normal ICON/CURSOR.
if (anih.cFrames > 1) {
*pfAni = TRUE; *prt = RT_CURSOR; return(LoadAniIcon(pfi, RT_CURSOR, cxDesired, cyDesired, LR_flags)); }
} else if (tag.ckID == FOURCC_LIST) { LPDWORD pdwType = NULL; BOOL fOK = FALSE; /*
* If this is the fram list, then get the first icon out of it */
/* check LIST type for fram */
if( tag.ckSize >= sizeof(DWORD) && (fOK = ReadFilePtr( pfi, &pdwType, sizeof(DWORD))) && *pdwType == FOURCC_fram) {
if (!ReadTag(pfi, &tag)) { return NULL; }
if (tag.ckID == FOURCC_icon) { /*
* We've found what we're looking for. Get current position * in file to be used as the base from which the icon data * offsets are offset from. */ offResBase = (int)(pfi->pFilePtr - pfi->pFileMap);
/*
* Grab the header first, since the following code assumes * it was read above. */ ReadFilePtr(pfi, &pnh, sizeof(NEWHEADER));
/*
* Break out and let the icon loading/cursor creating code * take it from here. */ break; } else { SkipChunk(pfi, &tag); } } else { /*
* Something bad happened in the type read, if it was * a file error then close and exit, otherwise just * skip the rest of the chunk */ if(!fOK) { return NULL; } /*
* take the type we just read out of the tag size and * skip the rest */ tag.ckSize -= sizeof(DWORD); SkipChunk(pfi, &tag); } } else { /*
* We're not interested in this chunk, skip it. */ SkipChunk(pfi, &tag); } } } else { // not a RIFF file.
if ((pnh->ResType != FT_ICON) && (pnh->ResType != FT_CURSOR)) { return NULL; } } { PCURSORRESOURCE pcres;
pcres = ReadIconGuts(pfi, pnh, offResBase, prt, cxDesired, cyDesired, LR_flags);
if (pcres == NULL) { return NULL; }
return ConvertDIBIcon((LPBITMAPINFOHEADER)pcres, NULL, pfi->pszName, *prt == RT_ICON, cxDesired, cyDesired, LR_flags); } }
/***********************************************************************\
* ReadIconGuts * * Returns: a pointer to a locally allocated buffer extraced from the * given file that looks like a icon/acon resource. * Also returns the type of the icon (RT_ICON or RT_CURSOR) * * * 8/23/1995 SanfordS Documented * 11/16/1995 SanfordS Added LR_flags support \***********************************************************************/ PCURSORRESOURCE ReadIconGuts( IN PFILEINFO pfi, IN NEWHEADER *pnhBase, IN int offResBase, OUT LPWSTR *prt, IN int cxDesired, IN int cyDesired, IN DWORD LR_flags) { NEWHEADER *pnh; int i, Id; ICONFILERESDIR UNALIGNED *pird; PCURSORRESOURCE pcres; RESDIR UNALIGNED *prd; DWORD cb; HOTSPOTREC UNALIGNED *phs; LPBITMAPINFOHEADER pbih;
/*
* Construct a fake array of RESDIR entries using the info at the head * of the file. Store the data offset in the idIcon WORD so it can be * returned by RtlGetIdFromDirectory. */ pnh = (NEWHEADER *)UserLocalAlloc(0, sizeof(NEWHEADER) + (pnhBase->ResCount * (sizeof(RESDIR) + sizeof(HOTSPOTREC)))); if (pnh == NULL) return NULL;
*pnh = *pnhBase; prd = (RESDIR UNALIGNED *)(pnh + 1); phs = (HOTSPOTREC UNALIGNED *)(prd + pnhBase->ResCount);
for (i = 0; i < (int)pnh->ResCount; i++, prd++) { /*
* Read the resource directory from the icon file. */ ReadFilePtrUnaligned(pfi, &pird, sizeof(ICONFILERESDIR));
/*
* Convert from the icon editor's resource directory format * to the post-RC.EXE format LookupIconIdFromDirectory expects. */ prd->Icon.Width = pird->bWidth; prd->Icon.Height = pird->bHeight; prd->Icon.reserved = 0; prd->BytesInRes = pird->dwDIBSize; prd->idIcon = (WORD)pird->dwDIBOffset;
if (pnh->ResType == FT_ICON) { /*
* 10/18/2000 - dwaynen * * For icons, this is really an ICONDIRENTRY (which has * wPlanes and wBitCount fields that overlap xHotSpot and * yHotSpot! */ prd->Icon.ColorCount = pird->bColorCount; prd->Planes = pird->xHotspot; prd->BitCount = pird->yHotspot; } else { /*
* 10/18/2000 - dwaynen * * Hopefully, cursors will only have one image. Otherwise, * our selection logic is gonna be screwed up because we don't * store the color bit depth! I suppose we could dig out the * actual bitmap header and find the info there. Consider doing * this if we ever want to support multi-resource cursors. */ prd->Icon.ColorCount = 0; prd->Planes = 0; prd->BitCount = 0; }
phs->xHotspot = pird->xHotspot; phs->yHotspot = pird->yHotspot; phs++; }
*prt = pnhBase->ResType == FT_ICON ? RT_ICON : RT_CURSOR; Id = RtlGetIdFromDirectory((PBYTE)pnh, *prt == RT_ICON, cxDesired, cyDesired, LR_flags, &cb);
/*
* Allocate for worst case (cursor). */ pcres = (PCURSORRESOURCE)UserLocalAlloc(0, cb + FIELD_OFFSET(CURSORRESOURCE, bih)); if (pcres == NULL) { goto CleanExit; }
if (*prt == RT_CURSOR) { /*
* Fill in hotspot info for cursors. */ prd = (RESDIR UNALIGNED *)(pnh + 1); phs = (HOTSPOTREC UNALIGNED *)(prd + pnh->ResCount);
for( i = 0; i < pnh->ResCount; i++ ) { if (prd[i].idIcon == (WORD)Id) { pcres->xHotspot = phs[i].xHotspot; pcres->yHotspot = phs[i].yHotspot; break; } }
if (i == pnh->ResCount) { pcres->xHotspot = pird->xHotspot; pcres->yHotspot = pird->yHotspot; } pbih = &pcres->bih; } else { pbih = (LPBITMAPINFOHEADER)pcres; }
/*
* Read in the header information into pcres. */ pfi->pFilePtr = pfi->pFileMap + offResBase + Id; if (!ReadFilePtrCopy(pfi, pbih, cb)) { UserLocalFree(pnh); UserLocalFree(pcres); return NULL; }
CleanExit: UserLocalFree(pnh); return pcres; }
/***************************************************************************\
* CreateAniIcon * * For now, CreateAniIcon copies the jif rate table and the sequence table * but not the CURSOR structs. This is ok as long as this routine is * internal only. * * History: * 10-02-91 DarrinM Created. \***************************************************************************/
HCURSOR CreateAniIcon( LPCWSTR pszName, LPWSTR rt, int cicur, DWORD *aicur, int cpcur, HCURSOR *ahcur, JIF jifRate, PJIF ajifRate, BOOL fPublic) { HCURSOR hacon; CURSORDATA acon; DWORD cbacon; HCURSOR *ahcurT; // Array of image frame pointers
DWORD *aicurT; // Array of frame indices (sequence table)
PJIF ajifRateT; // Array of time offsets
int i;
/*
* Start by allocating space for the ACON structure and the ahcur and * ajifRate arrays. */ hacon = (HCURSOR)NtUserCallOneParam(fPublic, SFI__CREATEEMPTYCURSOROBJECT); if (hacon == NULL) return NULL;
/*
* Save a couple UserLocalAlloc calls by allocating the memory needed for * the CURSOR, JIF, and SEQ arrays at once. */ RtlZeroMemory(&acon, sizeof(acon)); cbacon = (cpcur * sizeof(HCURSOR)) + (cicur * sizeof(JIF)) + (cicur * sizeof(DWORD)); ahcurT = (HCURSOR *)UserLocalAlloc(HEAP_ZERO_MEMORY, cbacon); if (ahcurT == NULL) { NtUserDestroyCursor((HCURSOR)hacon, CURSOR_ALWAYSDESTROY); return NULL; } acon.aspcur = (PCURSOR *)ahcurT;
/*
* Set up work pointers */ ajifRateT = (PJIF)((PBYTE)ahcurT + (cpcur * sizeof(HCURSOR))); aicurT = (DWORD *)((PBYTE)ajifRateT + (cicur * sizeof(JIF)));
/*
* Save offsets to arrays to make copying them to the server * easier. */ acon.ajifRate = (PJIF)(cpcur * sizeof(HCURSOR)); acon.aicur = (KPDWORD)((KPBYTE)acon.ajifRate + (cicur * sizeof(JIF)));
acon.cpcur = cpcur; acon.cicur = cicur;
acon.CURSORF_flags = CURSORF_ACON;
/*
* Store this information away so we can identify * repeated calls to LoadCursor/Icon for the same * resource type/id. */ acon.rt = PTR_TO_ID(rt); acon.lpModName = szUSER32; acon.lpName = (LPWSTR)pszName;
/*
* Make a private copy of the cursor pointers and the animation rate table. */ for (i = 0; i < cpcur; i++) { ahcurT[i] = ahcur[i]; // ahcurT[i]->fPointer |= PTRI_ANIMATED; // if GDI needs it
}
for (i = 0; i < cicur; i++) {
/*
* If constant rate, initialize the rate table to a single value. */ if (ajifRate == NULL) ajifRateT[i] = jifRate; else ajifRateT[i] = ajifRate[i];
/*
* If no sequence table then build a unity map to the cursor table. */ if (aicur == NULL) aicurT[i] = i; else aicurT[i] = aicur[i]; }
/*
* Stuff acon data into the cursor */ if (!_SetCursorIconData(hacon, &acon)) { NtUserDestroyCursor(hacon, CURSOR_ALWAYSDESTROY); hacon = NULL; } UserLocalFree(ahcurT);
return hacon; }
/***************************************************************************\
* ReadIconFromFileMap * * LATER: Error handling. * * History: * 12-21-91 DarrinM Created. \***************************************************************************/
HCURSOR ReadIconFromFileMap( PFILEINFO pfi, int cbSize, // used to seek past this chunk in case of error
DWORD cxDesired, DWORD cyDesired, DWORD LR_flags) { PCURSORRESOURCE pcres; HCURSOR hcur = NULL; LPNEWHEADER pnh; int offResBase; LPWSTR rt;
/*
* Get current position in file to be used as the base from which * the icon data offsets are offset from. */ offResBase = (int)(pfi->pFilePtr - pfi->pFileMap);
/*
* Read the .ICO/.CUR data's header. */ ReadFilePtr(pfi, &pnh, sizeof(NEWHEADER));
pcres = ReadIconGuts(pfi, pnh, offResBase, &rt, cxDesired, cyDesired, LR_flags);
if (pcres != NULL) { hcur = (HCURSOR)ConvertDIBIcon((LPBITMAPINFOHEADER)pcres, NULL, NULL, (rt == RT_ICON), cxDesired, cyDesired, LR_ACONFRAME | LR_flags);
UserLocalFree(pcres); }
/*
* Seek to the end of this chunk, regardless of our current position. */ pfi->pFilePtr = pfi->pFileMap + ((offResBase + cbSize + 1) & (~1));
return hcur; }
/***************************************************************************\
* LoadAniIcon * * Loads an animatied cursor from a RIFF file. The RIFF file format for * animated cursors looks like this: * * RIFF( 'ACON' * LIST( 'INFO' * INAM( <name> ) * IART( <artist> ) * ) * anih( <anihdr> ) * [rate( <rateinfo> ) ] * ['seq '( <seq_info> )] * LIST( 'fram' icon( <icon_file> ) ... ) * ) * * * History: * 10-02-91 DarrinM Created. * 03-17-93 JonPa Rewrote to use RIFF format instead of RAD * 04-22-93 JonPa Finalized RIFF format (changed from ANI to ACON etc) * 11/16/1995 SanfordS Added LR_flags support. \***************************************************************************/
HICON LoadAniIcon( IN PFILEINFO pfi, IN LPWSTR rt, IN DWORD cxDesired, IN DWORD cyDesired, IN DWORD LR_flags) { int cpcur, ipcur = 0, i, cicur; ANIHEADER anih; ANIHEADER *panih = NULL; HICON hacon = NULL; HCURSOR *phcur = NULL; JIF jifRate, *pjifRate; RTAG tag; DWORD *picur;
/*
* Position to the beginning of the file. */ pfi->pFilePtr = pfi->pFileMap + sizeof(tag);
#if DBG
if ((ULONG_PTR)pfi->pFileEnd != ((ULONG_PTR)(pfi->pFileMap + sizeof (RTAG) + ((RTAG *)(pfi->pFileMap))->ckSize + 1) & ~1)) { RIPMSG2(RIP_WARNING, "LoadAniIcon: First RIFF chunk has invalid ckSize. Actual:%#lx Expected:%#lx", ((RTAG *)(pfi->pFileMap))->ckSize, (pfi->pFileEnd - pfi->pFileMap - sizeof(RTAG)) & ~1); } #endif
/* read the chunk type */ if(!ReadFilePtrCopy(pfi, &tag.ckID, sizeof(tag.ckID))) { goto laiFileErr; }
if (tag.ckID != FOURCC_ACON) goto laiFileErr;
/* look for 'anih', 'rate', 'seq ', and 'icon' chunks */ while( ReadTag(pfi, &tag)) {
switch( tag.ckID ) { case FOURCC_anih: if (!ReadChunk(pfi, &tag, &anih)) goto laiFileErr;
if (!(anih.fl & AF_ICON) || (anih.cFrames == 0)) goto laiFileErr;
/*
* Allocate space for the ANIHEADER, HCURSOR array and a * rate table (in case we run into one later). */ cpcur = anih.cFrames; cicur = anih.cSteps; panih = (PANIHEADER)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(ANIHEADER));
if (panih == NULL) goto laiFileErr;
phcur = UserLocalAlloc(HEAP_ZERO_MEMORY, cpcur * sizeof(HCURSOR) + cicur * sizeof(JIF) + cicur * sizeof(DWORD)); UserAssert(phcur == NATURAL_ALIGNED_PTR(HCURSOR, phcur)); if (phcur == NULL) { goto laiFileErr; }
pjifRate = NULL; picur = NULL;
*panih = anih; jifRate = panih->jifRate; break;
case FOURCC_rate: /*
* If we find a rate chunk, read it into its preallocated * space. */ pjifRate = (PJIF)((PBYTE)phcur + cpcur * sizeof(HCURSOR)); UserAssert(pjifRate == NATURAL_ALIGNED_PTR(JIF, pjifRate)); if(!ReadChunk(pfi, &tag, (PBYTE)pjifRate)) goto laiFileErr; break;
case FOURCC_seq: /*
* If we find a seq chunk, read it into its preallocated * space. */ picur = (DWORD *)((PBYTE)phcur + cpcur * sizeof(HCURSOR) + cicur * sizeof(JIF)); UserAssert(picur == NATURAL_ALIGNED_PTR(DWORD, picur)); if(!ReadChunk(pfi, &tag, (PBYTE)picur)) goto laiFileErr; break;
case FOURCC_LIST: { DWORD cbChunk = (tag.ckSize + 1) & ~1;
/*
* See if this list is the 'fram' list of icon chunks */ if(!ReadFilePtrCopy(pfi, &tag.ckID, sizeof(tag.ckID))) { goto laiFileErr; }
cbChunk -= sizeof(tag.ckID);
if (tag.ckID != FOURCC_fram) { /*
* Not the fram list (probably the INFO list). Skip * the rest of this chunk. (Don't forget that we have * already skipped one dword!) */ tag.ckSize = cbChunk; SkipChunk(pfi, &tag); break; }
while(cbChunk >= sizeof(tag)) { if (!ReadTag(pfi, &tag)) goto laiFileErr;
cbChunk -= sizeof(tag);
if(tag.ckID == FOURCC_icon) {
/*
* Ok, load the icon/cursor bits, create a cursor from * them, and save a pointer to it away in the ACON * cursor pointer array. */ phcur[ipcur] = ReadIconFromFileMap(pfi, tag.ckSize, cxDesired, cyDesired, LR_flags);
if (phcur[ipcur] == NULL) { for (i = 0; i < ipcur; i++) NtUserDestroyCursor(phcur[i], 0); goto laiFileErr; }
ipcur++; } else { /*
* Unknown chunk in fram list, just ignore it */ SkipChunk(pfi, &tag); }
cbChunk -= (tag.ckSize + 1) & ~1; } } break;
default: /*
* We're not interested in this chunk, skip it. */ if(!SkipChunk(pfi, &tag)) goto laiFileErr; break;
}
}
/*
* Sanity check the count of frames so we won't fault trying * to select a nonexistant cursor */ if (cpcur != ipcur) { RIPMSG2(RIP_WARNING, "LoadAniIcon: Invalid number of frames; Actual:%#lx Expected:%#lx", ipcur, cpcur); for (i = 0; i < ipcur; i++) NtUserDestroyCursor(phcur[i], CURSOR_ALWAYSDESTROY); goto laiFileErr; }
if (cpcur != 0) hacon = CreateAniIcon(pfi->pszName, rt, cicur, picur, cpcur, phcur, jifRate, pjifRate, LR_flags & LR_GLOBAL);
laiFileErr:
#if DBG
if (hacon == NULL) { RIPMSG0(RIP_WARNING, "LoadAniIcon: Invalid icon data format"); } #endif
if (panih != NULL) UserLocalFree(panih);
if (phcur != NULL) { UserLocalFree(phcur); }
return hacon; }
|