Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1021 lines
29 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: acons.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains code for dealing with animated icons/cursors.
  7. *
  8. * History:
  9. * 10-02-91 DarrinM Created.
  10. * 07-30-92 DarrinM Unicodized.
  11. * 11-28-94 JimA Moved to client from server.
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. /*
  16. * Resource Directory format for IconEditor generated icon and cursor
  17. * (.ICO & .CUR) files. All fields are shared except xHotspot and yHotspot
  18. * which are only valid for cursors.
  19. */
  20. typedef struct _ICONFILERESDIR { // ird
  21. BYTE bWidth;
  22. BYTE bHeight;
  23. BYTE bColorCount;
  24. BYTE bReserved;
  25. WORD xHotspot;
  26. WORD yHotspot;
  27. DWORD dwDIBSize;
  28. DWORD dwDIBOffset;
  29. } ICONFILERESDIR;
  30. typedef struct _HOTSPOTREC { // hs
  31. WORD xHotspot;
  32. WORD yHotspot;
  33. } HOTSPOTREC;
  34. PCURSORRESOURCE ReadIconGuts(
  35. IN PFILEINFO pfi,
  36. IN LPNEWHEADER pnhBase,
  37. IN int offResBase,
  38. OUT LPWSTR *prt,
  39. IN int cxDesired,
  40. IN int cyDesired,
  41. IN DWORD LR_flags);
  42. BOOL ReadTag(
  43. IN PFILEINFO pfi,
  44. OUT PRTAG ptag);
  45. BOOL ReadChunk(
  46. IN PFILEINFO pfi,
  47. IN PRTAG ptag,
  48. OUT PVOID pv);
  49. BOOL SkipChunk(
  50. IN PFILEINFO pfi,
  51. IN PRTAG ptag);
  52. HICON CreateAniIcon(
  53. LPCWSTR pszName,
  54. LPWSTR rt,
  55. int cicur,
  56. DWORD *aicur,
  57. int cpcur,
  58. HCURSOR *ahcur,
  59. JIF jifRate,
  60. PJIF ajifRate,
  61. BOOL fPublic);
  62. HCURSOR ReadIconFromFileMap(
  63. IN PFILEINFO pfi,
  64. IN int cbSize,
  65. IN DWORD cxDesired,
  66. IN DWORD cyDesired,
  67. IN DWORD LR_flags);
  68. HICON LoadAniIcon(
  69. IN PFILEINFO pfi,
  70. IN LPWSTR rt,
  71. IN DWORD cxDesired,
  72. IN DWORD cyDesired,
  73. IN DWORD LR_flags);
  74. /***************************************************************************\
  75. * LoadCursorFromFile (API)
  76. *
  77. * Called by SetSystemCursor.
  78. *
  79. * History:
  80. * 08-03-92 DarrinM Created.
  81. \***************************************************************************/
  82. FUNCLOG1(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorFromFileW, LPCWSTR, pszFilename)
  83. HCURSOR WINAPI LoadCursorFromFileW(
  84. LPCWSTR pszFilename)
  85. {
  86. return(LoadImage(NULL,
  87. pszFilename,
  88. IMAGE_CURSOR,
  89. 0,
  90. 0,
  91. LR_DEFAULTSIZE | LR_LOADFROMFILE));
  92. }
  93. /***********************************************************************\
  94. * LoadCursorFromFileA
  95. *
  96. * Returns: hCursor
  97. *
  98. * 10/9/1995 Created SanfordS
  99. \***********************************************************************/
  100. FUNCLOG1(LOG_GENERAL, HCURSOR, WINAPI, LoadCursorFromFileA, LPCSTR, pszFilename)
  101. HCURSOR WINAPI LoadCursorFromFileA(
  102. LPCSTR pszFilename)
  103. {
  104. LPWSTR lpUniName;
  105. HCURSOR hcur;
  106. if (pszFilename == NULL ||
  107. !MBToWCS(pszFilename, -1, &lpUniName, -1, TRUE))
  108. return (HANDLE)NULL;
  109. hcur = LoadCursorFromFileW(lpUniName);
  110. UserLocalFree(lpUniName);
  111. return hcur;
  112. }
  113. /***********************************************************************\
  114. * ReadFilePtr
  115. *
  116. * Works like ReadFile but with pointers to a mapped file buffer.
  117. *
  118. * Returns:
  119. *
  120. * 11/16/1995 Created SanfordS
  121. \***********************************************************************/
  122. BOOL ReadFilePtr(
  123. IN PFILEINFO pfi,
  124. OUT LPVOID *ppBuf,
  125. IN DWORD cb)
  126. {
  127. *ppBuf = pfi->pFilePtr;
  128. pfi->pFilePtr += cb;
  129. return (pfi->pFilePtr <= pfi->pFileEnd);
  130. }
  131. /***********************************************************************\
  132. * ReadFilePtrUnaligned
  133. *
  134. * Works like ReadFile but with pointers to a mapped file buffer.
  135. *
  136. * Returns:
  137. *
  138. * 11/16/1995 Created SanfordS
  139. \***********************************************************************/
  140. BOOL ReadFilePtrUnaligned(
  141. IN PFILEINFO pfi,
  142. OUT VOID UNALIGNED **ppBuf,
  143. IN DWORD cb)
  144. {
  145. *ppBuf = pfi->pFilePtr;
  146. pfi->pFilePtr += cb;
  147. return (pfi->pFilePtr <= pfi->pFileEnd);
  148. }
  149. /***********************************************************************\
  150. * ReadFilePtrCopy
  151. *
  152. * Works even more like ReadFile in that is copies data to the given buffer.
  153. *
  154. * Returns:
  155. *
  156. * 11/16/1995 Created SanfordS
  157. \***********************************************************************/
  158. BOOL ReadFilePtrCopy(
  159. IN PFILEINFO pfi,
  160. IN OUT LPVOID pBuf,
  161. IN DWORD cb)
  162. {
  163. if (pfi->pFilePtr + cb > pfi->pFileEnd) {
  164. return(FALSE);
  165. }
  166. RtlCopyMemory(pBuf, pfi->pFilePtr, cb);
  167. pfi->pFilePtr += cb;
  168. return TRUE;
  169. }
  170. /***************************************************************************\
  171. * ReadTag, ReadChunk, SkipChunk
  172. *
  173. * Some handy functions for reading RIFF files.
  174. *
  175. * History:
  176. * 10-02-91 DarrinM Created.
  177. * 03-25-93 Jonpa Changed to use RIFF format instead of ASDF
  178. \***************************************************************************/
  179. BOOL ReadTag(
  180. IN PFILEINFO pfi,
  181. OUT PRTAG ptag)
  182. {
  183. ptag->ckID = ptag->ckSize = 0L; // in case we fail the read.
  184. return(ReadFilePtrCopy(pfi, ptag, sizeof(RTAG)));
  185. }
  186. BOOL ReadChunk(
  187. IN PFILEINFO pfi,
  188. IN PRTAG ptag,
  189. OUT PVOID pv)
  190. {
  191. if (!ReadFilePtrCopy(pfi, pv, ptag->ckSize))
  192. return FALSE;
  193. /* WORD align file pointer */
  194. if( ptag->ckSize & 1 )
  195. pfi->pFilePtr++;
  196. if (pfi->pFilePtr <= pfi->pFileEnd) {
  197. return TRUE;
  198. } else {
  199. RIPMSG0(RIP_WARNING, "ReadChunk: Advanced pointer past end of file map");
  200. return FALSE;
  201. }
  202. }
  203. BOOL SkipChunk(
  204. IN PFILEINFO pfi,
  205. IN PRTAG ptag)
  206. {
  207. /*
  208. * Round ptag->ckSize up to nearest word boundary
  209. * to maintain alignment
  210. */
  211. pfi->pFilePtr += (ptag->ckSize + 1) & (~1);
  212. if (pfi->pFilePtr <= pfi->pFileEnd) {
  213. return TRUE;
  214. } else {
  215. RIPMSG0(RIP_WARNING, "SkipChunk: Advanced pointer past end of file map");
  216. return FALSE;
  217. }
  218. }
  219. /***************************************************************************\
  220. * LoadCursorIconFromFileMap
  221. *
  222. * If pszName is one of the IDC_* values then we use WIN.INI to find a
  223. * custom cursor/icon. Otherwise, pszName points to a filename of a .ICO/.CUR
  224. * file to be loaded. If the file is an .ANI file containing a multiframe
  225. * animation then LoadAniIcon is called to create an ACON. Otherwise if
  226. * the file is an .ANI file containing just a single frame then it is loaded
  227. * and a normal CURSOR/ICON resource is created from it.
  228. *
  229. * 12-26-91 DarrinM Wrote it.
  230. * 03-17-93 JonPa Changed to use RIFF format for ani-cursors
  231. * 11/16/1995 SanfordS Added LR_flags support
  232. \***************************************************************************/
  233. HANDLE LoadCursorIconFromFileMap(
  234. IN PFILEINFO pfi,
  235. IN OUT LPWSTR *prt,
  236. IN DWORD cxDesired,
  237. IN DWORD cyDesired,
  238. IN DWORD LR_flags,
  239. OUT LPBOOL pfAni)
  240. {
  241. LPNEWHEADER pnh;
  242. int offResBase;
  243. *pfAni = FALSE;
  244. offResBase = 0;
  245. /*
  246. * Determine if this is an .ICO/.CUR file or an .ANI file.
  247. */
  248. pnh = (LPNEWHEADER)pfi->pFileMap;
  249. if (*(LPDWORD)pnh == FOURCC_RIFF) {
  250. RTAG tag;
  251. /*
  252. * It's an ANICURSOR!
  253. * Seek back to beginning + 1 tag.
  254. */
  255. pfi->pFilePtr = pfi->pFileMap + sizeof(tag);
  256. /* check RIFF type for ACON */
  257. if (*(LPDWORD)pfi->pFilePtr != FOURCC_ACON) {
  258. return NULL;
  259. }
  260. pfi->pFilePtr += sizeof(DWORD);
  261. if (pfi->pFilePtr > pfi->pFileEnd) {
  262. return NULL;
  263. }
  264. /*
  265. * Ok, we have a ACON chunk. Find the first ICON chunk and set
  266. * things up so it looks we've just loaded the header of a normal
  267. * .CUR file, then fall into the .CUR bits handling code below.
  268. */
  269. while (ReadTag(pfi, &tag)) {
  270. /*
  271. * Handle each chunk type.
  272. */
  273. if (tag.ckID == FOURCC_anih) {
  274. ANIHEADER anih;
  275. if (!ReadChunk(pfi, &tag, &anih)) {
  276. return NULL;
  277. }
  278. if (!(anih.fl & AF_ICON) || (anih.cFrames == 0)) {
  279. return NULL;
  280. }
  281. // If this ACON has more than one frame then go ahead
  282. // and create an ACON, otherwise just use the first
  283. // frame to create a normal ICON/CURSOR.
  284. if (anih.cFrames > 1) {
  285. *pfAni = TRUE;
  286. *prt = RT_CURSOR;
  287. return(LoadAniIcon(pfi,
  288. RT_CURSOR,
  289. cxDesired,
  290. cyDesired,
  291. LR_flags));
  292. }
  293. } else if (tag.ckID == FOURCC_LIST) {
  294. LPDWORD pdwType = NULL;
  295. BOOL fOK = FALSE;
  296. /*
  297. * If this is the fram list, then get the first icon out of it
  298. */
  299. /* check LIST type for fram */
  300. if( tag.ckSize >= sizeof(DWORD) &&
  301. (fOK = ReadFilePtr( pfi,
  302. &pdwType,
  303. sizeof(DWORD))) &&
  304. *pdwType == FOURCC_fram) {
  305. if (!ReadTag(pfi, &tag)) {
  306. return NULL;
  307. }
  308. if (tag.ckID == FOURCC_icon) {
  309. /*
  310. * We've found what we're looking for. Get current position
  311. * in file to be used as the base from which the icon data
  312. * offsets are offset from.
  313. */
  314. offResBase = (int)(pfi->pFilePtr - pfi->pFileMap);
  315. /*
  316. * Grab the header first, since the following code assumes
  317. * it was read above.
  318. */
  319. ReadFilePtr(pfi, &pnh, sizeof(NEWHEADER));
  320. /*
  321. * Break out and let the icon loading/cursor creating code
  322. * take it from here.
  323. */
  324. break;
  325. } else {
  326. SkipChunk(pfi, &tag);
  327. }
  328. } else {
  329. /*
  330. * Something bad happened in the type read, if it was
  331. * a file error then close and exit, otherwise just
  332. * skip the rest of the chunk
  333. */
  334. if(!fOK) {
  335. return NULL;
  336. }
  337. /*
  338. * take the type we just read out of the tag size and
  339. * skip the rest
  340. */
  341. tag.ckSize -= sizeof(DWORD);
  342. SkipChunk(pfi, &tag);
  343. }
  344. } else {
  345. /*
  346. * We're not interested in this chunk, skip it.
  347. */
  348. SkipChunk(pfi, &tag);
  349. }
  350. }
  351. } else { // not a RIFF file.
  352. if ((pnh->ResType != FT_ICON) && (pnh->ResType != FT_CURSOR)) {
  353. return NULL;
  354. }
  355. }
  356. {
  357. PCURSORRESOURCE pcres;
  358. pcres = ReadIconGuts(pfi,
  359. pnh,
  360. offResBase,
  361. prt,
  362. cxDesired,
  363. cyDesired,
  364. LR_flags);
  365. if (pcres == NULL) {
  366. return NULL;
  367. }
  368. return ConvertDIBIcon((LPBITMAPINFOHEADER)pcres,
  369. NULL,
  370. pfi->pszName,
  371. *prt == RT_ICON,
  372. cxDesired,
  373. cyDesired,
  374. LR_flags);
  375. }
  376. }
  377. /***********************************************************************\
  378. * ReadIconGuts
  379. *
  380. * Returns: a pointer to a locally allocated buffer extraced from the
  381. * given file that looks like a icon/acon resource.
  382. * Also returns the type of the icon (RT_ICON or RT_CURSOR)
  383. *
  384. *
  385. * 8/23/1995 SanfordS Documented
  386. * 11/16/1995 SanfordS Added LR_flags support
  387. \***********************************************************************/
  388. PCURSORRESOURCE ReadIconGuts(
  389. IN PFILEINFO pfi,
  390. IN NEWHEADER *pnhBase,
  391. IN int offResBase,
  392. OUT LPWSTR *prt,
  393. IN int cxDesired,
  394. IN int cyDesired,
  395. IN DWORD LR_flags)
  396. {
  397. NEWHEADER *pnh;
  398. int i, Id;
  399. ICONFILERESDIR UNALIGNED *pird;
  400. PCURSORRESOURCE pcres;
  401. RESDIR UNALIGNED *prd;
  402. DWORD cb;
  403. HOTSPOTREC UNALIGNED *phs;
  404. LPBITMAPINFOHEADER pbih;
  405. /*
  406. * Construct a fake array of RESDIR entries using the info at the head
  407. * of the file. Store the data offset in the idIcon WORD so it can be
  408. * returned by RtlGetIdFromDirectory.
  409. */
  410. pnh = (NEWHEADER *)UserLocalAlloc(0, sizeof(NEWHEADER) +
  411. (pnhBase->ResCount * (sizeof(RESDIR) + sizeof(HOTSPOTREC))));
  412. if (pnh == NULL)
  413. return NULL;
  414. *pnh = *pnhBase;
  415. prd = (RESDIR UNALIGNED *)(pnh + 1);
  416. phs = (HOTSPOTREC UNALIGNED *)(prd + pnhBase->ResCount);
  417. for (i = 0; i < (int)pnh->ResCount; i++, prd++) {
  418. /*
  419. * Read the resource directory from the icon file.
  420. */
  421. ReadFilePtrUnaligned(pfi, &pird, sizeof(ICONFILERESDIR));
  422. /*
  423. * Convert from the icon editor's resource directory format
  424. * to the post-RC.EXE format LookupIconIdFromDirectory expects.
  425. */
  426. prd->Icon.Width = pird->bWidth;
  427. prd->Icon.Height = pird->bHeight;
  428. prd->Icon.reserved = 0;
  429. prd->BytesInRes = pird->dwDIBSize;
  430. prd->idIcon = (WORD)pird->dwDIBOffset;
  431. if (pnh->ResType == FT_ICON) {
  432. /*
  433. * 10/18/2000 - dwaynen
  434. *
  435. * For icons, this is really an ICONDIRENTRY (which has
  436. * wPlanes and wBitCount fields that overlap xHotSpot and
  437. * yHotSpot!
  438. */
  439. prd->Icon.ColorCount = pird->bColorCount;
  440. prd->Planes = pird->xHotspot;
  441. prd->BitCount = pird->yHotspot;
  442. } else {
  443. /*
  444. * 10/18/2000 - dwaynen
  445. *
  446. * Hopefully, cursors will only have one image. Otherwise,
  447. * our selection logic is gonna be screwed up because we don't
  448. * store the color bit depth! I suppose we could dig out the
  449. * actual bitmap header and find the info there. Consider doing
  450. * this if we ever want to support multi-resource cursors.
  451. */
  452. prd->Icon.ColorCount = 0;
  453. prd->Planes = 0;
  454. prd->BitCount = 0;
  455. }
  456. phs->xHotspot = pird->xHotspot;
  457. phs->yHotspot = pird->yHotspot;
  458. phs++;
  459. }
  460. *prt = pnhBase->ResType == FT_ICON ? RT_ICON : RT_CURSOR;
  461. Id = RtlGetIdFromDirectory((PBYTE)pnh,
  462. *prt == RT_ICON,
  463. cxDesired,
  464. cyDesired,
  465. LR_flags,
  466. &cb);
  467. /*
  468. * Allocate for worst case (cursor).
  469. */
  470. pcres = (PCURSORRESOURCE)UserLocalAlloc(0,
  471. cb + FIELD_OFFSET(CURSORRESOURCE, bih));
  472. if (pcres == NULL) {
  473. goto CleanExit;
  474. }
  475. if (*prt == RT_CURSOR) {
  476. /*
  477. * Fill in hotspot info for cursors.
  478. */
  479. prd = (RESDIR UNALIGNED *)(pnh + 1);
  480. phs = (HOTSPOTREC UNALIGNED *)(prd + pnh->ResCount);
  481. for( i = 0; i < pnh->ResCount; i++ ) {
  482. if (prd[i].idIcon == (WORD)Id) {
  483. pcres->xHotspot = phs[i].xHotspot;
  484. pcres->yHotspot = phs[i].yHotspot;
  485. break;
  486. }
  487. }
  488. if (i == pnh->ResCount) {
  489. pcres->xHotspot = pird->xHotspot;
  490. pcres->yHotspot = pird->yHotspot;
  491. }
  492. pbih = &pcres->bih;
  493. } else {
  494. pbih = (LPBITMAPINFOHEADER)pcres;
  495. }
  496. /*
  497. * Read in the header information into pcres.
  498. */
  499. pfi->pFilePtr = pfi->pFileMap + offResBase + Id;
  500. if (!ReadFilePtrCopy(pfi, pbih, cb)) {
  501. UserLocalFree(pnh);
  502. UserLocalFree(pcres);
  503. return NULL;
  504. }
  505. CleanExit:
  506. UserLocalFree(pnh);
  507. return pcres;
  508. }
  509. /***************************************************************************\
  510. * CreateAniIcon
  511. *
  512. * For now, CreateAniIcon copies the jif rate table and the sequence table
  513. * but not the CURSOR structs. This is ok as long as this routine is
  514. * internal only.
  515. *
  516. * History:
  517. * 10-02-91 DarrinM Created.
  518. \***************************************************************************/
  519. HCURSOR CreateAniIcon(
  520. LPCWSTR pszName,
  521. LPWSTR rt,
  522. int cicur,
  523. DWORD *aicur,
  524. int cpcur,
  525. HCURSOR *ahcur,
  526. JIF jifRate,
  527. PJIF ajifRate,
  528. BOOL fPublic)
  529. {
  530. HCURSOR hacon;
  531. CURSORDATA acon;
  532. DWORD cbacon;
  533. HCURSOR *ahcurT; // Array of image frame pointers
  534. DWORD *aicurT; // Array of frame indices (sequence table)
  535. PJIF ajifRateT; // Array of time offsets
  536. int i;
  537. /*
  538. * Start by allocating space for the ACON structure and the ahcur and
  539. * ajifRate arrays.
  540. */
  541. hacon = (HCURSOR)NtUserCallOneParam(fPublic,
  542. SFI__CREATEEMPTYCURSOROBJECT);
  543. if (hacon == NULL)
  544. return NULL;
  545. /*
  546. * Save a couple UserLocalAlloc calls by allocating the memory needed for
  547. * the CURSOR, JIF, and SEQ arrays at once.
  548. */
  549. RtlZeroMemory(&acon, sizeof(acon));
  550. cbacon = (cpcur * sizeof(HCURSOR)) +
  551. (cicur * sizeof(JIF)) + (cicur * sizeof(DWORD));
  552. ahcurT = (HCURSOR *)UserLocalAlloc(HEAP_ZERO_MEMORY, cbacon);
  553. if (ahcurT == NULL) {
  554. NtUserDestroyCursor((HCURSOR)hacon, CURSOR_ALWAYSDESTROY);
  555. return NULL;
  556. }
  557. acon.aspcur = (PCURSOR *)ahcurT;
  558. /*
  559. * Set up work pointers
  560. */
  561. ajifRateT = (PJIF)((PBYTE)ahcurT + (cpcur * sizeof(HCURSOR)));
  562. aicurT = (DWORD *)((PBYTE)ajifRateT + (cicur * sizeof(JIF)));
  563. /*
  564. * Save offsets to arrays to make copying them to the server
  565. * easier.
  566. */
  567. acon.ajifRate = (PJIF)(cpcur * sizeof(HCURSOR));
  568. acon.aicur = (KPDWORD)((KPBYTE)acon.ajifRate + (cicur * sizeof(JIF)));
  569. acon.cpcur = cpcur;
  570. acon.cicur = cicur;
  571. acon.CURSORF_flags = CURSORF_ACON;
  572. /*
  573. * Store this information away so we can identify
  574. * repeated calls to LoadCursor/Icon for the same
  575. * resource type/id.
  576. */
  577. acon.rt = PTR_TO_ID(rt);
  578. acon.lpModName = szUSER32;
  579. acon.lpName = (LPWSTR)pszName;
  580. /*
  581. * Make a private copy of the cursor pointers and the animation rate table.
  582. */
  583. for (i = 0; i < cpcur; i++) {
  584. ahcurT[i] = ahcur[i];
  585. // ahcurT[i]->fPointer |= PTRI_ANIMATED; // if GDI needs it
  586. }
  587. for (i = 0; i < cicur; i++) {
  588. /*
  589. * If constant rate, initialize the rate table to a single value.
  590. */
  591. if (ajifRate == NULL)
  592. ajifRateT[i] = jifRate;
  593. else
  594. ajifRateT[i] = ajifRate[i];
  595. /*
  596. * If no sequence table then build a unity map to the cursor table.
  597. */
  598. if (aicur == NULL)
  599. aicurT[i] = i;
  600. else
  601. aicurT[i] = aicur[i];
  602. }
  603. /*
  604. * Stuff acon data into the cursor
  605. */
  606. if (!_SetCursorIconData(hacon, &acon)) {
  607. NtUserDestroyCursor(hacon, CURSOR_ALWAYSDESTROY);
  608. hacon = NULL;
  609. }
  610. UserLocalFree(ahcurT);
  611. return hacon;
  612. }
  613. /***************************************************************************\
  614. * ReadIconFromFileMap
  615. *
  616. * LATER: Error handling.
  617. *
  618. * History:
  619. * 12-21-91 DarrinM Created.
  620. \***************************************************************************/
  621. HCURSOR ReadIconFromFileMap(
  622. PFILEINFO pfi,
  623. int cbSize, // used to seek past this chunk in case of error
  624. DWORD cxDesired,
  625. DWORD cyDesired,
  626. DWORD LR_flags)
  627. {
  628. PCURSORRESOURCE pcres;
  629. HCURSOR hcur = NULL;
  630. LPNEWHEADER pnh;
  631. int offResBase;
  632. LPWSTR rt;
  633. /*
  634. * Get current position in file to be used as the base from which
  635. * the icon data offsets are offset from.
  636. */
  637. offResBase = (int)(pfi->pFilePtr - pfi->pFileMap);
  638. /*
  639. * Read the .ICO/.CUR data's header.
  640. */
  641. ReadFilePtr(pfi, &pnh, sizeof(NEWHEADER));
  642. pcres = ReadIconGuts(pfi,
  643. pnh,
  644. offResBase,
  645. &rt,
  646. cxDesired,
  647. cyDesired,
  648. LR_flags);
  649. if (pcres != NULL) {
  650. hcur = (HCURSOR)ConvertDIBIcon((LPBITMAPINFOHEADER)pcres,
  651. NULL,
  652. NULL,
  653. (rt == RT_ICON),
  654. cxDesired,
  655. cyDesired,
  656. LR_ACONFRAME | LR_flags);
  657. UserLocalFree(pcres);
  658. }
  659. /*
  660. * Seek to the end of this chunk, regardless of our current position.
  661. */
  662. pfi->pFilePtr = pfi->pFileMap + ((offResBase + cbSize + 1) & (~1));
  663. return hcur;
  664. }
  665. /***************************************************************************\
  666. * LoadAniIcon
  667. *
  668. * Loads an animatied cursor from a RIFF file. The RIFF file format for
  669. * animated cursors looks like this:
  670. *
  671. * RIFF( 'ACON'
  672. * LIST( 'INFO'
  673. * INAM( <name> )
  674. * IART( <artist> )
  675. * )
  676. * anih( <anihdr> )
  677. * [rate( <rateinfo> ) ]
  678. * ['seq '( <seq_info> )]
  679. * LIST( 'fram' icon( <icon_file> ) ... )
  680. * )
  681. *
  682. *
  683. * History:
  684. * 10-02-91 DarrinM Created.
  685. * 03-17-93 JonPa Rewrote to use RIFF format instead of RAD
  686. * 04-22-93 JonPa Finalized RIFF format (changed from ANI to ACON etc)
  687. * 11/16/1995 SanfordS Added LR_flags support.
  688. \***************************************************************************/
  689. HICON LoadAniIcon(
  690. IN PFILEINFO pfi,
  691. IN LPWSTR rt,
  692. IN DWORD cxDesired,
  693. IN DWORD cyDesired,
  694. IN DWORD LR_flags)
  695. {
  696. int cpcur, ipcur = 0, i, cicur;
  697. ANIHEADER anih;
  698. ANIHEADER *panih = NULL;
  699. HICON hacon = NULL;
  700. HCURSOR *phcur = NULL;
  701. JIF jifRate, *pjifRate;
  702. RTAG tag;
  703. DWORD *picur;
  704. /*
  705. * Position to the beginning of the file.
  706. */
  707. pfi->pFilePtr = pfi->pFileMap + sizeof(tag);
  708. #if DBG
  709. if ((ULONG_PTR)pfi->pFileEnd != ((ULONG_PTR)(pfi->pFileMap + sizeof (RTAG) + ((RTAG *)(pfi->pFileMap))->ckSize + 1) & ~1)) {
  710. RIPMSG2(RIP_WARNING, "LoadAniIcon: First RIFF chunk has invalid ckSize. Actual:%#lx Expected:%#lx",
  711. ((RTAG *)(pfi->pFileMap))->ckSize, (pfi->pFileEnd - pfi->pFileMap - sizeof(RTAG)) & ~1);
  712. }
  713. #endif
  714. /* read the chunk type */
  715. if(!ReadFilePtrCopy(pfi,
  716. &tag.ckID,
  717. sizeof(tag.ckID))) {
  718. goto laiFileErr;
  719. }
  720. if (tag.ckID != FOURCC_ACON)
  721. goto laiFileErr;
  722. /* look for 'anih', 'rate', 'seq ', and 'icon' chunks */
  723. while( ReadTag(pfi, &tag)) {
  724. switch( tag.ckID ) {
  725. case FOURCC_anih:
  726. if (!ReadChunk(pfi, &tag, &anih))
  727. goto laiFileErr;
  728. if (!(anih.fl & AF_ICON) || (anih.cFrames == 0))
  729. goto laiFileErr;
  730. /*
  731. * Allocate space for the ANIHEADER, HCURSOR array and a
  732. * rate table (in case we run into one later).
  733. */
  734. cpcur = anih.cFrames;
  735. cicur = anih.cSteps;
  736. panih = (PANIHEADER)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(ANIHEADER));
  737. if (panih == NULL)
  738. goto laiFileErr;
  739. phcur = UserLocalAlloc(HEAP_ZERO_MEMORY, cpcur * sizeof(HCURSOR) + cicur * sizeof(JIF) + cicur * sizeof(DWORD));
  740. UserAssert(phcur == NATURAL_ALIGNED_PTR(HCURSOR, phcur));
  741. if (phcur == NULL) {
  742. goto laiFileErr;
  743. }
  744. pjifRate = NULL;
  745. picur = NULL;
  746. *panih = anih;
  747. jifRate = panih->jifRate;
  748. break;
  749. case FOURCC_rate:
  750. /*
  751. * If we find a rate chunk, read it into its preallocated
  752. * space.
  753. */
  754. pjifRate = (PJIF)((PBYTE)phcur + cpcur * sizeof(HCURSOR));
  755. UserAssert(pjifRate == NATURAL_ALIGNED_PTR(JIF, pjifRate));
  756. if(!ReadChunk(pfi, &tag, (PBYTE)pjifRate))
  757. goto laiFileErr;
  758. break;
  759. case FOURCC_seq:
  760. /*
  761. * If we find a seq chunk, read it into its preallocated
  762. * space.
  763. */
  764. picur = (DWORD *)((PBYTE)phcur + cpcur * sizeof(HCURSOR) +
  765. cicur * sizeof(JIF));
  766. UserAssert(picur == NATURAL_ALIGNED_PTR(DWORD, picur));
  767. if(!ReadChunk(pfi, &tag, (PBYTE)picur))
  768. goto laiFileErr;
  769. break;
  770. case FOURCC_LIST:
  771. {
  772. DWORD cbChunk = (tag.ckSize + 1) & ~1;
  773. /*
  774. * See if this list is the 'fram' list of icon chunks
  775. */
  776. if(!ReadFilePtrCopy(pfi, &tag.ckID, sizeof(tag.ckID))) {
  777. goto laiFileErr;
  778. }
  779. cbChunk -= sizeof(tag.ckID);
  780. if (tag.ckID != FOURCC_fram) {
  781. /*
  782. * Not the fram list (probably the INFO list). Skip
  783. * the rest of this chunk. (Don't forget that we have
  784. * already skipped one dword!)
  785. */
  786. tag.ckSize = cbChunk;
  787. SkipChunk(pfi, &tag);
  788. break;
  789. }
  790. while(cbChunk >= sizeof(tag)) {
  791. if (!ReadTag(pfi, &tag))
  792. goto laiFileErr;
  793. cbChunk -= sizeof(tag);
  794. if(tag.ckID == FOURCC_icon) {
  795. /*
  796. * Ok, load the icon/cursor bits, create a cursor from
  797. * them, and save a pointer to it away in the ACON
  798. * cursor pointer array.
  799. */
  800. phcur[ipcur] = ReadIconFromFileMap(pfi,
  801. tag.ckSize,
  802. cxDesired,
  803. cyDesired,
  804. LR_flags);
  805. if (phcur[ipcur] == NULL) {
  806. for (i = 0; i < ipcur; i++)
  807. NtUserDestroyCursor(phcur[i], 0);
  808. goto laiFileErr;
  809. }
  810. ipcur++;
  811. } else {
  812. /*
  813. * Unknown chunk in fram list, just ignore it
  814. */
  815. SkipChunk(pfi, &tag);
  816. }
  817. cbChunk -= (tag.ckSize + 1) & ~1;
  818. }
  819. }
  820. break;
  821. default:
  822. /*
  823. * We're not interested in this chunk, skip it.
  824. */
  825. if(!SkipChunk(pfi, &tag))
  826. goto laiFileErr;
  827. break;
  828. }
  829. }
  830. /*
  831. * Sanity check the count of frames so we won't fault trying
  832. * to select a nonexistant cursor
  833. */
  834. if (cpcur != ipcur) {
  835. RIPMSG2(RIP_WARNING, "LoadAniIcon: Invalid number of frames; Actual:%#lx Expected:%#lx",
  836. ipcur, cpcur);
  837. for (i = 0; i < ipcur; i++)
  838. NtUserDestroyCursor(phcur[i], CURSOR_ALWAYSDESTROY);
  839. goto laiFileErr;
  840. }
  841. if (cpcur != 0)
  842. hacon = CreateAniIcon(pfi->pszName,
  843. rt,
  844. cicur,
  845. picur,
  846. cpcur,
  847. phcur,
  848. jifRate,
  849. pjifRate,
  850. LR_flags & LR_GLOBAL);
  851. laiFileErr:
  852. #if DBG
  853. if (hacon == NULL) {
  854. RIPMSG0(RIP_WARNING, "LoadAniIcon: Invalid icon data format");
  855. }
  856. #endif
  857. if (panih != NULL)
  858. UserLocalFree(panih);
  859. if (phcur != NULL) {
  860. UserLocalFree(phcur);
  861. }
  862. return hacon;
  863. }