|
|
1.1 root 1: /****************************************************************************\
2: *
3: * MODULE: anifile.c
4: *
5: * PURPOSE: Processes files for the Animated Cursor Editor
6: *
7: * Copyright 1993, Microsoft Corp.
8: *
9: *
10: * History:
11: * 21-Apr-1993 JonPa Wrote it.
12: *
13: \****************************************************************************/
14:
15: #include <windows.h>
16: #include <commdlg.h>
17: #include "anidefs.h"
18:
19: /****************************************************************************\
20: *
21: * FUNCTION: BOOL CreateFrameFromCursorFile( LPSTR pszFile )
22: *
23: * PURPOSE: Opens a cursor file, reads the icon info out of it,
24: * and creates a frame and step for that icon, then links
25: * everything together and updates the listbox.
26: *
27: * NOTES: This function accesses the global flag gfEditFrame.
28: * If this bool is TRUE, then the currently selected frame
29: * in the listbox is overwritten. If it is false, then
30: * a new frame is created and inserted after the currently
31: * selected frame (or at the end if no selection).
32: *
33: * History:
34: * 21-Apr-1993 JonPa Created it
35: *
36: \****************************************************************************/
37: BOOL CreateFrameFromCursorFile(HWND hwnd, LPTSTR pszFile, BOOL fEdit) {
38: PFRAME pf;
39: HANDLE hf;
40: PSTEP psOld, psNew;
41: DWORD ckSize;
42: int iSel;
43: int cSel;
44:
45: cSel = GetSelStepCount(hwnd);
46:
47: if ( (fEdit && (cSel != 1)) || cSel > 1) {
48: FmtMessageBox( hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
49: TRUE, fEdit ? MSG_MUSTEQONEFAME : MSG_LESSEQONEFRAME);
50: return FALSE;
51: }
52:
53: /* get currently selected frame */
54: GetCurrentSel(hwnd, DLG_MAIN_FRAMELIST, &iSel, 1, &cSel );
55:
56: if (cSel == 0)
57: psOld = NULL;
58: else
59: psOld = GetStep(hwnd, iSel);
60:
61: /*
62: * If not editing, create a new step
63: */
64: if (!fEdit || !IsValidPS(psOld)) {
65: psNew = NewStep();
66:
67: if (psNew == NULL) {
68: return FALSE;
69: }
70: } else {
71: psNew = NULL;
72: }
73:
74: hf = CreateFile(pszFile, GENERIC_READ,
75: 0, NULL,
76: OPEN_EXISTING,
77: FILE_ATTRIBUTE_NORMAL,
78: NULL);
79:
80: if (hf == INVALID_HANDLE_VALUE)
81: return FALSE;
82:
83: ckSize = GetFileSize(hf, NULL);
84:
85: /* get the frame out of the file */
86: pf = ReadIconFromFile(hwnd, hf, ckSize);
87: CloseHandle(hf);
88:
89: if (pf == NULL) {
90: if (psNew != NULL)
91: FreeMem(psNew);
92: return FALSE;
93: }
94:
95: if (psNew != NULL) {
96:
97: if (IsValidPS(psOld)) {
98: psNew->jif = psOld->jif;
99: iSel += 1;
100: } else {
101: psNew->jif = ganiAcon.anih.jifRate;
102: iSel = SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_GETCOUNT,
103: 0, 0);
104: }
105:
106: LinkStepFrame(psNew, pf);
107:
108: SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_INSERTSTRING, iSel,
109: (LPARAM)psNew);
110:
111: SetCurrentSel(hwnd, DLG_MAIN_FRAMELIST, FALSE, iSel);
112:
113: } else {
114: HWND hwndLB = GetDlgItem(hwnd, DLG_MAIN_FRAMELIST);
115:
116: /*
117: * Delete the old frame and point the step to the new one.
118: */
119: LinkStepFrame(psOld, pf);
120:
121: InvalidateRect(hwndLB, NULL, TRUE);
122: }
123:
124: return TRUE;
125: }
126:
127:
128: /****************************************************************************\
129: *
130: * FUNCTION: HICON ConvertDataToIcon( PFRAME pf )
131: *
132: * PURPOSE:
133: *
134: *
135: *
136: *
137: * History:
138: * 23-Apr-1993 JonPa copied from Win NT USERs ReadIconGuts
139: *
140: \****************************************************************************/
141: HICON ConvertDataToIcon( PFRAME pf, WORD *pxHotSave, WORD *pyHotSave )
142: {
143: NEWHEADER *pnh;
144: NEWHEADER *pnhBase;
145: RESDIR *prd;
146: int offMatch;
147: ICONFILERESDIR *pird;
148: PCURSORRESOURCE pcres;
149: BOOL fIcon;
150: HICON hicon;
151: WORD x, y;
152:
153: pnhBase = (NEWHEADER *)pf->abIcon;
154:
155: /*
156: * Construct a fake array of RESDIR entries using the info at the head
157: * of the file. Store the data offset in the idIcon WORD so it can be
158: * returned by RtlGetIdFromDirectory.
159: */
160: pnh = (NEWHEADER *)LocalAlloc(LMEM_FIXED, sizeof(NEWHEADER) +
161: (pnhBase->cResources * sizeof(RESDIR)));
162: if (pnh == NULL)
163: return NULL;
164:
165: *pnh = *pnhBase;
166: prd = (RESDIR *)(pnh + 1);
167: pird = (ICONFILERESDIR *)(pnhBase + 1);
168:
169: /* prime pird for first line of loop */
170: pird--;
171:
172: for (offMatch = 0; offMatch < (int)pnh->cResources; offMatch++, prd++) {
173:
174: /*
175: * Get the next resource directory from the icon file.
176: */
177:
178: ++pird;
179:
180: /*
181: * Convert from the icon editor's resource directory format
182: * to the post-RC.EXE format LookupIconIdFromDirectory expects.
183: */
184: if (pnh->rt == 1) { // ICON
185: prd->ResInfo.Icon.Width = pird->bWidth;
186: prd->ResInfo.Icon.Height = pird->bHeight;
187: prd->ResInfo.Icon.ColorCount = pird->bColorCount;
188: prd->ResInfo.Icon.reserved = 0;
189: } else { // CURSOR
190: prd->ResInfo.Cursor.Width = pird->bWidth;
191: prd->ResInfo.Cursor.Height = pird->bHeight;
192: }
193: prd->Planes = 0; // Hopefully nobody uses this
194: prd->BitCount = 0; // " "
195: prd->BytesInRes = pird->dwDIBSize;
196: prd->idIcon = (WORD)pird->dwDIBOffset;
197: }
198:
199: /*
200: * NOTE: nh.rt is NOT an RT_ type value. For instance, nh.rt == 1 for
201: * an icon file where as 1 == RT_CURSOR, not RT_ICON.
202: */
203:
204: fIcon = (pnhBase->rt == 1);
205: offMatch = LookupIconIdFromDirectory((PBYTE)pnh, fIcon);
206:
207: LocalFree(pnh);
208:
209: if (fIcon) {
210: pcres = (PCURSORRESOURCE)&(pf->abIcon[offMatch]);
211: *pxHotSave = gcxCursor / 2;
212: *pyHotSave = gcyCursor / 2;
213: } else {
214:
215: offMatch -= (sizeof(pcres->xHotspot) + sizeof(pcres->yHotspot));
216:
217: for(; pird->dwDIBOffset != (WORD)offMatch &&
218: pird != (ICONFILERESDIR *)(pnhBase + 1); pird--);
219:
220: pcres = (PCURSORRESOURCE)&(pf->abIcon[offMatch]);
221:
222: x = pcres->xHotspot;
223: y = pcres->yHotspot;
224: *pxHotSave = pcres->xHotspot = pird->xHotspot;
225: *pyHotSave = pcres->yHotspot = pird->yHotspot;
226: }
227:
228: hicon = CreateIconFromResource( (PBYTE)pcres,
229: pf->rtag.ckSize - offMatch, fIcon, 0x00030000);
230:
231: if(!fIcon) {
232: pcres->xHotspot = x;
233: pcres->yHotspot = y;
234: }
235:
236: return hicon;
237: }
238:
239:
240:
241:
242: /****************************************************************************\
243: *
244: * FUNCTION: PFRAME ReadIconFromFile(HWND hwnd, HANDLE hf, DWORD ckSize)
245: *
246: * PURPOSE: Reads the icon info out of a file,
247: * and creates a frame for that icon.
248: *
249: *
250: * History:
251: * 22-Apr-1993 JonPa Created it
252: *
253: \****************************************************************************/
254: PFRAME ReadIconFromFile(HWND hwnd, HANDLE hf, DWORD ckSize) {
255: PFRAME pf = AllocMem( sizeof( FRAME ) + ckSize );
256: DWORD cbRead;
257: PFRAME pfList;
258:
259: if (pf != NULL) {
260: pf->cRef = 0;
261:
262: if (ReadFile(hf, pf->abIcon, ckSize, &cbRead, NULL) &&
263: cbRead == ckSize) {
264: /* got the data, now set up the rest of the frame and link it in */
265: pf->dwCheckSum = CalcCheckSum( pf->abIcon, ckSize );
266: pf->rtag.ckID = FOURCC_icon;
267: pf->rtag.ckSize = ckSize;
268:
269: /* Check if this fram is already in the list */
270: for (pfList = gpfrmFrames; pfList != NULL;
271: pfList = pfList->pfrmNext ) {
272: if (pf->dwCheckSum == pfList->dwCheckSum &&
273: pf->rtag.ckSize == pfList->rtag.ckSize &&
274: memcmp( pf->abIcon, pfList->abIcon, ckSize ) == 0) {
275: /*
276: * These frames are the same, coalesce them into a
277: * sequence.
278: */
279: FreeMem(pf);
280: pf = pfList;
281: break;
282: }
283: }
284:
285: if (pfList == NULL) {
286: /*
287: * Did not find a dup, create an icon for this frame
288: */
289: pf->hcur = ConvertDataToIcon( pf, &(pf->xHotSpot),
290: &(pf->yHotSpot) );
291:
292: pf->pfrmNext = gpfrmFrames;
293: gpfrmFrames = pf;
294: }
295:
296: } else {
297: /* File Error */
298: FreeMem(pf);
299: pf = NULL;
300: }
301:
302: }
303:
304: return pf;
305: }
306:
307: /****************************************************************************\
308: *
309: * FUNCTION: HANDLE PromptAndOpenFile( )
310: *
311: * PURPOSE: Pust up the standard open dialog and then opens the file
312: *
313: *
314: *
315: *
316: * History:
317: * 21-Apr-1993 JonPa Created it
318: *
319: \****************************************************************************/
320: HANDLE PromptAndOpenFile(
321: HWND hwnd,
322: DWORD cchFileTitle,
323: LPTSTR pszFileTitle,
324: DWORD cchFileName,
325: LPTSTR pszFileName,
326: LPTSTR pszFilter
327: )
328: {
329: HANDLE hf = INVALID_HANDLE_VALUE;
330:
331: if (PromptForFile( hwnd, cchFileTitle, pszFileTitle, cchFileName,
332: pszFileName, pszFilter, NULL, FALSE )) {
333:
334: /* Open the file. */
335:
336: hf = CreateFile(pszFileName, GENERIC_READ,
337: 0, NULL,
338: OPEN_EXISTING,
339: FILE_ATTRIBUTE_NORMAL,
340: NULL);
341:
342: if (hf == INVALID_HANDLE_VALUE) {
343: FmtMessageBox( hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE,
344: MSG_CANTOPENFILE, pszFileName );
345: }
346: }
347:
348: return hf;
349: }
350:
351:
352: /****************************************************************************\
353: *
354: * FUNCTION: HANDLE PromptForFile( )
355: *
356: * PURPOSE: Pust up the standard open dialog
357: *
358: *
359: *
360: *
361: * History:
362: * 28-Apr-1993 JonPa Created it from PromptAndOpenFile
363: *
364: \****************************************************************************/
365: BOOL PromptForFile(
366: HWND hwnd,
367: DWORD cchFileTitle,
368: LPTSTR pszFileTitle,
369: DWORD cchFileName,
370: LPTSTR pszFile,
371: LPTSTR pszFilter,
372: LPTSTR pszDlgTitle,
373: BOOL fSave
374: )
375: {
376: OPENFILENAME ofn;
377:
378: ZeroMemory(&ofn, sizeof(ofn));
379:
380: /* Set the members of the OPENFILENAME structure. */
381:
382: ofn.lStructSize = sizeof(OPENFILENAME);
383: ofn.hwndOwner = hwnd;
384:
385: ofn.lpstrFilter = pszFilter;
386: ofn.nFilterIndex = 0;
387:
388: ofn.lpstrFile = pszFile;
389: ofn.nMaxFile = cchFileName;
390:
391: ofn.lpstrFileTitle = pszFileTitle;
392: ofn.nMaxFileTitle = cchFileTitle;
393:
394: ofn.lpstrTitle = pszDlgTitle;
395:
396: ofn.lpstrDefExt = gpszANI;
397:
398: if (fSave) {
399: ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
400: } else {
401: ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
402: }
403:
404: /* Display the SaveAs or Open dialog box. */
405:
406: return fSave ? GetSaveFileName(&ofn) : GetOpenFileName(&ofn);
407:
408: }
409:
410: /****************************************************************************\
411: *
412: * FUNCTION: BOOL ReadAniFile( HWND hwnd, HANDLE hf ) {
413: *
414: * PURPOSE:
415: &
416: * Loads an animatied cursor from a RIFF file. The RIFF file format for
417: * animated cursors looks like this:
418: *
419: * RIFF( 'ACON'
420: * LIST( 'INFO'
421: * INAM( <name> )
422: * IART( <artist> )
423: * )
424: * anih( <anihdr> )
425: * [rate( <rateinfo> ) ]
426: * ['seq '( <seq_info> )]
427: * LIST( 'fram' icon( <icon_file> ) )
428: * )
429: *
430: *
431: * History:
432: * 02-Oct-1991 DarrinM Created. (in Win32 user)
433: * 17-Mar-1993 JonPa Rewrote to use RIFF format instead of RAD
434: * 21-Apr-1993 JonPa Copied it to anifile.c and tweeked it.
435: *
436: \****************************************************************************/
437: BOOL ReadAniFile( HWND hwnd, HANDLE hf ) {
438:
439: RTAG tag;
440: DWORD cbRead;
441: BOOL fSuccess = FALSE;
442: JIF *pjifRate = NULL;
443: DWORD *pseq = NULL;
444: PFRAME *ppfram = NULL;
445: int iFrame = 0;
446: int i;
447:
448: if (!ReadTag(hf, &tag))
449: return FALSE;
450:
451: /*
452: * Make sure it's a RIFF ANI file
453: */
454: if (tag.ckID != FOURCC_RIFF)
455: goto laiFileErr;
456:
457: /* read the chunk type */
458: if(!ReadFile(hf, &tag.ckID, sizeof(tag.ckID), &cbRead, NULL) ||
459: cbRead < sizeof(tag.ckID)) {
460: goto laiFileErr;
461: }
462:
463: if (tag.ckID != FOURCC_ACON)
464: goto laiFileErr;
465:
466: /* look for 'anih', 'rate', 'seq ', and 'icon' chunks */
467: while( ReadTag(hf, &tag)) {
468:
469: switch( tag.ckID ) {
470: case FOURCC_anih:
471: if (!ReadChunk(hf, &tag, &ganiAcon.anih))
472: goto laiFileErr;
473:
474: if (!(ganiAcon.anih.fl & AF_ICON) || (ganiAcon.anih.cFrames == 0))
475: goto laiFileErr;
476:
477: /*
478: * Allocate space for the ANIHEADER, and a seq and
479: * rate table (in case we run into one later).
480: */
481:
482: pjifRate = AllocMem( ganiAcon.anih.cSteps * sizeof(JIF) +
483: ganiAcon.anih.cSteps * sizeof(DWORD) +
484: ganiAcon.anih.cSteps * sizeof(PFRAME));
485:
486:
487: if (pjifRate == NULL)
488: goto laiFileErr;
489:
490: pseq = (DWORD *)(pjifRate + ganiAcon.anih.cSteps);
491: ppfram = (PFRAME *)(pseq + ganiAcon.anih.cSteps);
492:
493: for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) {
494: pjifRate[i] = ganiAcon.anih.jifRate;
495: pseq[i] = i;
496: ppfram[i] = NULL;
497: }
498: break;
499:
500:
501: case FOURCC_rate:
502: /*
503: * If we find a rate chunk, read it into its preallocated
504: * space.
505: */
506: if(!ReadChunk(hf, &tag, (PBYTE)pjifRate))
507: goto laiFileErr;
508: break;
509:
510:
511: case FOURCC_seq:
512: /*
513: * If we find a seq chunk, read it into its preallocated
514: * space.
515: */
516: if(!ReadChunk(hf, &tag, (PBYTE)pseq))
517: goto laiFileErr;
518: break;
519:
520:
521: case FOURCC_LIST: {
522: DWORD cbChunk = PADUP(tag.ckSize);
523:
524: /*
525: * See if this list is the 'fram' list of icon chunks
526: */
527: if(!ReadFile(hf, &tag.ckID, sizeof(tag.ckID), &cbRead, NULL) ||
528: cbRead < sizeof(tag.ckID)) {
529: goto laiFileErr;
530: }
531:
532: cbChunk -= cbRead;
533:
534: if (tag.ckID == FOURCC_fram) {
535:
536: while(cbChunk >= sizeof(tag)) {
537: if (!ReadTag(hf, &tag))
538: goto laiFileErr;
539:
540: cbChunk -= sizeof(tag);
541:
542: if(tag.ckID == FOURCC_icon) {
543: PFRAME pfrm;
544:
545: /*
546: * Ok, load the icon/cursor bits,
547: */
548: pfrm = ReadIconFromFile(hwnd, hf, tag.ckSize);
549:
550: if (pfrm == NULL) {
551: goto laiFileErr;
552: }
553:
554: for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) {
555: if (pseq[i] == (DWORD)iFrame) {
556: ppfram[i] = pfrm;
557: }
558: }
559:
560: iFrame++;
561:
562: } else {
563: /*
564: * Unknown chunk in fram list, just ignore it
565: */
566: SkipChunk(hf, &tag);
567: }
568:
569: cbChunk -= PADUP(tag.ckSize);
570: }
571: } else if (tag.ckID == FOURCC_INFO) {
572: /* now look for INAM and IART chunks */
573:
574: while( cbChunk >= sizeof(tag) ) {
575:
576: if (!ReadTag(hf, &tag))
577: goto laiFileErr;
578:
579: cbChunk -= sizeof(tag);
580:
581: switch( tag.ckID ) {
582: case FOURCC_INAM:
583: if (cbChunk < tag.ckSize ||
584: !ReadChunkN(hf, &tag, ganiAcon.azTitle,
585: sizeof(ganiAcon.azTitle)))
586: goto laiFileErr;
587:
588: cbChunk -= PADUP(tag.ckSize);
589: break;
590:
591: case FOURCC_IART:
592: if (cbChunk < tag.ckSize ||
593: !ReadChunkN(hf, &tag, ganiAcon.azCreator,
594: sizeof(ganiAcon.azCreator)))
595: goto laiFileErr;
596:
597: cbChunk -= PADUP(tag.ckSize);
598: break;
599:
600: default:
601: if (!SkipChunk( hf, &tag ))
602: goto laiFileErr;
603:
604: cbChunk -= PADUP(tag.ckSize);
605: break;
606: }
607: }
608:
609: } else {
610: /*
611: * Not the fram list or the INFO list. Skip
612: * the rest of this chunk. (Don't forget that we have
613: * already skipped one dword!)
614: */
615: tag.ckSize = cbChunk;
616: SkipChunk(hf, &tag);
617: break;
618: }
619:
620: break;
621: }
622:
623:
624:
625: default:
626: /*
627: * We're not interested in this chunk, skip it.
628: */
629: if(!SkipChunk(hf, &tag))
630: goto laiFileErr;
631: break;
632:
633: }
634:
635: }
636:
637: /*
638: * Update the frame count incase we coalesced some frames while reading
639: * in the file.
640: */
641: ganiAcon.anih.cFrames = iFrame;
642:
643: /*
644: * Now build up the listbox
645: */
646:
647: for( i = 0; i < (int)ganiAcon.anih.cSteps; i++ ) {
648: PSTEP ps;
649:
650: ps = NewStep();
651: if (ps == NULL)
652: goto laiFileErr;
653:
654: ps->jif = pjifRate[i];
655: LinkStepFrame(ps, ppfram[i]);
656:
657: SendDlgItemMessage(hwnd, DLG_MAIN_FRAMELIST, LB_INSERTSTRING, i,
658: (LPARAM)ps);
659: }
660:
661: SetDlgItemText(hwnd, DLG_MAIN_TITLE, ganiAcon.azTitle);
662: SetDlgItemText(hwnd, DLG_MAIN_AUTHOR, ganiAcon.azCreator);
663:
664: SendDlgItemMessage(hwnd, DLG_MAIN_PREVIEW, PM_NEWCURSOR, 0, 0);
665: fSuccess = TRUE;
666:
667: laiFileErr:
668:
669: if (pjifRate != NULL)
670: FreeMem(pjifRate);
671:
672: if (!fSuccess)
673: NewAniCursor(hwnd);
674:
675: CloseHandle(hf);
676:
677: return fSuccess;
678: }
679:
680:
681:
682: /***************************************************************************\
683: * DWORD CalcCheckSum( PBYTE pb );
684: *
685: *
686: * History:
687: *
688: * 23-Apr-1993 JonPa Created.
689: \***************************************************************************/
690: DWORD CalcCheckSum( PBYTE pb, DWORD cb ) {
691: DWORD dw = 0;
692:
693: while(cb--)
694: dw += (DWORD)*pb++;
695:
696: return dw;
697: }
698:
699: /***************************************************************************\
700: * ReadTag, ReadChunk, SkipChunk
701: *
702: * Some handy functions for reading RIFF files.
703: *
704: * History:
705: * 10-02-91 DarrinM Created.
706: * 03-25-93 Jonpa Changed to use RIFF format instead of ASDF
707: * 23-Apr-1993 JonPa Copied from Win NT USER.
708: \***************************************************************************/
709: BOOL ReadTag(
710: HANDLE hf,
711: PRTAG ptag)
712: {
713: DWORD cbActual;
714:
715: ptag->ckID = ptag->ckSize = 0L;
716:
717: if (!ReadFile(hf, ptag, sizeof(RTAG), &cbActual, NULL) ||
718: (cbActual != sizeof(RTAG)))
719: return FALSE;
720:
721: /* no need to align file pointer since RTAG is already word aligned */
722: return TRUE;
723: }
724:
725:
726: BOOL ReadChunk(
727: HANDLE hf,
728: PRTAG ptag,
729: PVOID pv)
730: {
731: DWORD cbActual;
732:
733: if (!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) ||
734: (cbActual != ptag->ckSize))
735: return FALSE;
736:
737: /* WORD align file pointer */
738: if( ptag->ckSize & 1 )
739: SetFilePointer(hf, 1, NULL, FILE_CURRENT);
740:
741: return TRUE;
742: }
743:
744:
745: BOOL ReadChunkN(
746: HANDLE hf,
747: PRTAG ptag,
748: PVOID pv,
749: DWORD cbMax)
750: {
751: DWORD cbActual;
752: DWORD cbRead = min( cbMax, ptag->ckSize );
753:
754: if (!ReadFile(hf, pv, ptag->ckSize, &cbActual, NULL) ||
755: (cbActual != cbRead))
756: return FALSE;
757:
758: /* WORD align file pointer */
759:
760: cbRead = ptag->ckSize - cbActual;
761:
762: if( ptag->ckSize & 1 )
763: cbRead++;
764:
765: return SetFilePointer(hf, cbRead, NULL, FILE_CURRENT) != 0xFFFFFFFF;
766: }
767:
768: BOOL SkipChunk(
769: HANDLE hf,
770: PRTAG ptag)
771: {
772: /* Round ptag->ckSize up to nearest word boundary to maintain alignment */
773: return SetFilePointer(hf, PADUP(ptag->ckSize), NULL, FILE_CURRENT) !=
774: 0xFFFFFFFFL;
775: }
776:
777: /****************************************************************************\
778: *
779: * FUNCTION: VOID GetTempCursorFileName( szFileName );
780: *
781: * PURPOSE: Create a temporary .cur filename
782: *
783: *
784: * History:
785: * 22-Apr-1993 JonPa Created it
786: *
787: \****************************************************************************/
788: BOOL GetTempCursorFileName( LPTSTR pszName ) {
789: TCHAR szPath[MAX_PATH];
790:
791: if( GetTempPath( MAX_PATH, szPath ) >= MAX_PATH )
792: lstrcpy( pszName, TEXT(".") );
793:
794:
795: return GetTempFileName(szPath, TEXT("ae"), 0, pszName) != 0;
796: }
797:
798: /****************************************************************************\
799: *
800: * FUNCTION: BOOL SaveAniFile( HWND hwnd, HANDLE hf )
801: *
802: * PURPOSE:
803: &
804: * Saves an animatied cursor to a RIFF file. The RIFF file format for
805: * animated cursors looks like this:
806: *
807: * RIFF( 'ACON'
808: * [LIST( 'INFO'
809: * [INAM( <name> )]
810: * [IART( <artist> )]
811: * )]
812: * anih( <anihdr> )
813: * [rate( <rateinfo> ) ]
814: * ['seq '( <seq_info> )]
815: * LIST( 'fram' icon( <icon_file> ) )
816: * )
817: *
818: *
819: * History:
820: * 29-Apr-1993 JonPa Created it.
821: *
822: \****************************************************************************/
823: BOOL SaveAniFile( HWND hwnd, HANDLE hf ) {
824: int cSteps, i;
825: int cFrames;
826: PFRAME pf;
827: DWORD cbFile, cbFram, cbINFO, cbTitle, cbAuthor;
828: BOOL fRate, fSeq;
829: RTAG rtag;
830: PJIF pjif;
831: DWORD *pseq;
832: PFRAME *pfrm;
833:
834: fRate = fSeq = FALSE;
835: cbINFO = cbFram = cbFile = cbTitle = cbAuthor = 0;
836:
837: PausePreview(hwnd, DLG_MAIN_PREVIEW);
838:
839: cSteps = GetStepCount(hwnd);
840:
841: if( cSteps == LB_ERR ) {
842: FmtMessageBox( ghwndMain, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP,
843: TRUE, MSG_OUTOFRESOUCES );
844: return FALSE;
845: }
846:
847: cFrames = 0;
848: for( pf = gpfrmFrames; pf != NULL; pf = pf->pfrmNext ) {
849: pf->iFrame = -1;
850: cFrames++;
851: }
852:
853: ganiAcon.anih.cSteps = cSteps;
854:
855: pjif = AllocMem( (sizeof(JIF) + sizeof(DWORD) + sizeof(PFRAME)) * cSteps );
856:
857: if(pjif == NULL)
858: return FALSE;
859:
860: pseq = (DWORD *)&pjif[cSteps];
861: pfrm = (PFRAME *)&pseq[cSteps];
862:
863: cFrames = 0;
864:
865: for( i = 0; i < cSteps; i++ ) {
866: PSTEP ps;
867:
868: ps = GetStep(hwnd, i);
869:
870: if( IsValidPS(ps) ) {
871:
872: if (ps->pfrmFrame->iFrame == -1) {
873:
874: cbFram += sizeof(RTAG);
875: cbFram += PADUP(ps->pfrmFrame->rtag.ckSize);
876:
877: ps->pfrmFrame->iFrame = cFrames;
878: pfrm[cFrames++] = ps->pfrmFrame;
879:
880: } else
881: fSeq = TRUE;
882:
883: pseq[i] = ps->pfrmFrame->iFrame;
884:
885: if ((pjif[i] = ps->jif) != ganiAcon.anih.jifRate) {
886: fRate = TRUE;
887: }
888: }
889: }
890:
891: ganiAcon.anih.cbSizeof = sizeof(ganiAcon.anih);
892: ganiAcon.anih.cFrames = cFrames;
893: ganiAcon.anih.fl = AF_ICON | (fSeq ? AF_SEQUENCE : 0);
894:
895: cbTitle = GetDlgItemTextA(hwnd, DLG_MAIN_TITLE, ganiAcon.azTitle,
896: COUNTOF(ganiAcon.azTitle));
897:
898: cbAuthor = GetDlgItemTextA(hwnd, DLG_MAIN_AUTHOR, ganiAcon.azCreator,
899: COUNTOF(ganiAcon.azCreator));
900:
901: /*
902: * At this point, cbFram == the size required by all the frames,
903: * add in the rate, seq, anih, and INFO list sizes as well as
904: * all the other overhead.
905: */
906:
907: cbFram += sizeof(FOURCC); //fram type
908:
909: cbFile = cbFram;
910:
911: cbFile += sizeof(RTAG) + //RIFF tag
912: sizeof(FOURCC) + //ACON type
913: sizeof(RTAG) + //anih tag
914: PADUP(sizeof(ANIHEADER)) +
915: sizeof(RTAG); //LIST tag (for fram list)
916:
917:
918: if( cbTitle || cbAuthor) {
919: /*
920: * Remember, azCreator, and azTitle are ANSI strings!
921: */
922: if( cbTitle ) {
923: cbTitle = PADUP( cbTitle * sizeof(char));
924: cbINFO += sizeof(RTAG) + //INAM tag
925: cbTitle;
926: }
927:
928: if (cbAuthor) {
929: cbAuthor = PADUP(cbAuthor * sizeof(char));
930: cbINFO += sizeof(RTAG) + //IART tag
931: cbAuthor;
932: }
933:
934: cbINFO += sizeof(FOURCC); //INFO type
935:
936: cbFile += sizeof(RTAG) + //LIST tag
937: cbINFO;
938: }
939:
940:
941: if (fSeq) {
942: cbFile += sizeof(RTAG) + //seq tag
943: PADUP(cSteps * sizeof(DWORD));
944: }
945:
946: if (fRate) {
947: cbFile += sizeof(RTAG) + //rate tag
948: PADUP(cSteps * sizeof(JIF));
949: }
950:
951: /*
952: * Now we have all the structures built in memory, it's time to
953: * write them out in RIFF ACON format!
954: */
955: rtag.ckID = FOURCC_RIFF;
956: rtag.ckSize = cbFile;
957:
958: RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf );
959:
960: RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_ACON), hf );
961:
962: if( cbTitle || cbAuthor) {
963: rtag.ckID = FOURCC_LIST;
964: rtag.ckSize = cbINFO;
965:
966: RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf );
967:
968: RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_INFO), hf );
969:
970: if (cbTitle) {
971: rtag.ckID = FOURCC_INAM;
972: rtag.ckSize = cbTitle;
973: RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, ganiAcon.azTitle), hf );
974: }
975:
976: if (cbAuthor) {
977: rtag.ckID = FOURCC_IART;
978: rtag.ckSize = cbAuthor;
979: RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, ganiAcon.azCreator), hf );
980: }
981: }
982:
983: /* write anih */
984: rtag.ckID = FOURCC_anih;
985: rtag.ckSize = sizeof(ganiAcon.anih);
986:
987: RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, &(ganiAcon.anih)), hf );
988:
989: /* if rate then write it */
990: if (fRate) {
991: rtag.ckID = FOURCC_rate;
992: rtag.ckSize = cSteps * sizeof(JIF);
993:
994: RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, pjif), hf );
995: }
996:
997: /* if seq, then write it */
998: if (fSeq) {
999: rtag.ckID = FOURCC_seq;
1000: rtag.ckSize = cSteps * sizeof(DWORD);
1001:
1002: RET_CLOSE_IF_ERR( WriteTagData(hf, &rtag, pseq), hf );
1003: }
1004:
1005: /* write the fram list */
1006: rtag.ckID = FOURCC_LIST;
1007: rtag.ckSize = cbFram;
1008:
1009: RET_CLOSE_IF_ERR( WriteTag(hf, &rtag), hf );
1010: RET_CLOSE_IF_ERR( WriteType(hf, FOURCC_fram), hf );
1011:
1012: for( i = 0; i < cFrames; i++ ) {
1013: RET_CLOSE_IF_ERR( WriteTagData(hf, &(pfrm[i]->rtag), pfrm[i]->abIcon),
1014: hf);
1015: }
1016:
1017: /* Close the file */
1018: CloseHandle(hf);
1019:
1020: return TRUE;
1021: }
1022:
1023:
1024: /***************************************************************************\
1025: * WriteTag, WriteType, WriteTagData
1026: *
1027: * Some handy functions for writing RIFF files.
1028: *
1029: * History:
1030: * 30-Apr-1993 JonPa Created them.
1031: \***************************************************************************/
1032: BOOL WriteTag(HANDLE hf, PRTAG prtag) {
1033: DWORD cbWritten;
1034:
1035: return (WriteFile(hf, prtag, sizeof(RTAG), &cbWritten, NULL) &&
1036: cbWritten == sizeof(RTAG));
1037: }
1038:
1039: BOOL WriteType(HANDLE hf, FOURCC ckID ) {
1040: DWORD cbWritten;
1041:
1042: return (WriteFile(hf, &ckID, sizeof(FOURCC), &cbWritten, NULL) &&
1043: cbWritten == sizeof(FOURCC));
1044: }
1045:
1046: BOOL WriteTagData(HANDLE hf, PRTAG prtag, VOID *pvData ) {
1047: DWORD cbWritten;
1048: DWORD cbWrite = PADUP(prtag->ckSize);
1049:
1050: return WriteTag(hf, prtag) && WriteFile(hf, pvData, cbWrite,
1051: &cbWritten, NULL) && cbWritten == cbWrite;
1052: }
1053:
1054:
1055:
1056:
1057: /***************************************************************************\
1058: * VOID SaveFile(HWND hwnd, BOOL fPrompt)
1059: *
1060: * Conditionally Prompt the user for a name and then save the file
1061: *
1062: * History:
1063: * 04-May-1993 JonPa It
1064: \***************************************************************************/
1065: VOID SaveFile(HWND hwnd, BOOL fPrompt) {
1066: TCHAR szFileTitle[MAX_PATH];
1067: HANDLE hf;
1068:
1069: szFileTitle[0] = TEXT('\0');
1070:
1071: if (fPrompt || ganiAcon.szFile[0] == TEXT('\0')) {
1072: tryagain:
1073: if (!PromptForFile(hwnd, COUNTOF(szFileTitle), szFileTitle,
1074: COUNTOF(ganiAcon.szFile), ganiAcon.szFile, gpszAniFilter,
1075: NULL, TRUE)) {
1076: return;
1077: }
1078: }
1079:
1080: hf = CreateFile( ganiAcon.szFile, GENERIC_WRITE, 0, NULL,
1081: CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1082:
1083: if (hf == INVALID_HANDLE_VALUE) {
1084: FmtMessageBox(hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE,
1085: MSG_CANTCREATEFILE, ganiAcon.szFile);
1086:
1087: goto tryagain;
1088: }
1089:
1090: if( !SaveAniFile(hwnd, hf) ) {
1091: FmtMessageBox(hwnd, TITL_ERROR, NULL, MB_OK | MB_ICONSTOP, TRUE,
1092: MSG_FILEWRITEERR, ganiAcon.szFile);
1093: return;
1094: }
1095:
1096: if (szFileTitle[0] != TEXT('\0'))
1097: SetWindowFileTitle(hwnd, szFileTitle);
1098:
1099: ganiAcon.fDirty = FALSE;
1100: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.