Windows NT 4.0 source code leak
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.

538 lines
14 KiB

4 years ago
  1. /****************************************************************************\
  2. * MAKEANI -
  3. *
  4. * File: MAKEANI.c
  5. *
  6. * by Darrin Massena
  7. *
  8. * LATER:
  9. * ------
  10. * - Chunks must be DWORD padded so tags & data are DWORD-aligned.
  11. *
  12. * History
  13. * -------
  14. * 06-30-90 darrinm Wrote to build animation files for PM's AniPointers.
  15. * 10-01-91 darrinm Ported to Windows NT.
  16. * 08-09-92 darrinm Added frame sequence control.
  17. * 08-17-92 darrinm Changed to RIFF format.
  18. * 12-28-92 byrond Allowed both '-' and '/' on command line.
  19. * Renamed to makeani instead of makerad.
  20. * 03-39-92 jonpa Merged new RIFF code with old RAD version for NT
  21. \****************************************************************************/
  22. #include <windows.h>
  23. #include <winuserp.h>
  24. #include <stdio.h>
  25. #include <string.h>
  26. #include <malloc.h>
  27. #include <stdlib.h>
  28. #include <io.h>
  29. #include <asdf.h> // BUGBUG LATER:incorporate this into winuserp.h
  30. VOID PrintHelp(BOOL fFullHelp);
  31. BOOL QueryAniInfo(char *pszFile);
  32. BOOL AddFrame(char *pszFile, JIF jifRate);
  33. BOOL WriteAniFile(char *pszOutFile, char *pszTitle, char *pszAuthor);
  34. BOOL ReadTag(FILE *hf, PRTAG ptag);
  35. BOOL WriteTag(FILE *hf, DWORD type, DWORD len);
  36. BOOL DumpList(FILE *hf, PRTAG ptag, char *pszIndent, BOOL fList);
  37. #define WORDALIGN(n) ((n + 1) & 0xFFFFFFFE)
  38. #define CFRMMAX 250 // max frames MAKEANI will concatenate
  39. typedef struct _FRAME { // frm
  40. char *pszFile;
  41. } FRAME, *PFRAME;
  42. typedef struct _STEP { // step
  43. int ifrm;
  44. JIF jifRate;
  45. } STEP, *PSTEP;
  46. FRAME gafrm[CFRMMAX];
  47. STEP gastep[CFRMMAX];
  48. int gcfrm = 0;
  49. int gcstep = 0;
  50. BOOL gfSequenced = FALSE;
  51. /*
  52. * MAIN
  53. */
  54. VOID _CRTAPI1 main(int argc, char **argv)
  55. {
  56. int i, j;
  57. JIF jifRate = 2;
  58. int cchT;
  59. DWORD fl = 0;
  60. BOOL fSwitches;
  61. char *pch;
  62. // disgusting use of stack space.
  63. char szAuthor[256], szTitle[256], szOut[FILENAME_MAX];
  64. BOOL fTitled = FALSE, fAuthored = FALSE;
  65. // This is where the fun starts.
  66. if (argc <= 1) {
  67. /*
  68. * If we're passed no args, print help.
  69. */
  70. PrintHelp(FALSE);
  71. goto lbExit;
  72. }
  73. // Initialize a default output filename.
  74. strcpy(szOut, "temp.ani");
  75. for (i = 1; i < argc; i++) {
  76. cchT = strlen(argv[i]);
  77. pch = argv[i];
  78. fSwitches = FALSE;
  79. for (j = 0; j < cchT; j++) {
  80. if (!fSwitches) {
  81. if (pch[j] == '-' || pch[j] == '/') {
  82. fSwitches = TRUE;
  83. } else {
  84. // Add this file to the output ANI file.
  85. AddFrame(argv[i], jifRate);
  86. j = cchT; // so we advance to the next arg after continue
  87. }
  88. continue;
  89. }
  90. // Parse the switches.
  91. switch (pch[j]) {
  92. case '?':
  93. // Give a little friendly advice.
  94. PrintHelp(TRUE);
  95. goto lbExit;
  96. case 't': // get the image title
  97. i++;
  98. strcpy(szTitle, argv[i]);
  99. fTitled = TRUE;
  100. break;
  101. case 'a':
  102. i++;
  103. strcpy(szAuthor, argv[i]);
  104. fAuthored = TRUE;
  105. break;
  106. case 'o':
  107. i++; // NOTE: no error check here
  108. strcpy(szOut, argv[i]);
  109. break;
  110. case 'q': // Query file info.
  111. case 'i': // I just can't decide which is better
  112. i++;
  113. QueryAniInfo(argv[i]);
  114. break;
  115. case 'r':
  116. // This allows both '-r10' and '-r 10'
  117. if ((pch[j+1] >= '0') && (pch[j+1] <= '9')) {
  118. jifRate = atoi(argv[i] + j + 1);
  119. j = cchT;
  120. } else {
  121. i++;
  122. jifRate = atoi(argv[i]);
  123. }
  124. break;
  125. }
  126. }
  127. }
  128. if (gcfrm > 0)
  129. WriteAniFile(szOut, fTitled ? szTitle : NULL,
  130. fAuthored ? szAuthor : NULL);
  131. lbExit:
  132. exit(0);
  133. }
  134. BOOL AddFrame(char *pszFile, JIF jifRate)
  135. {
  136. int cch;
  137. char *psz;
  138. int ifrm;
  139. // See if this frame already exists. If it does then add a step
  140. // that references the first instance of this frame instead of
  141. // adding a new frame.
  142. for (ifrm = 0; ifrm < gcfrm; ifrm++) {
  143. if (_strcmpi(pszFile, gafrm[ifrm].pszFile) == 0)
  144. break;
  145. }
  146. if (ifrm == gcfrm) {
  147. cch = strlen(pszFile) + 1;
  148. psz = malloc(cch);
  149. if (psz == NULL)
  150. return FALSE;
  151. strcpy(psz, pszFile);
  152. gafrm[ifrm].pszFile = psz;
  153. gcfrm++;
  154. } else {
  155. // Since we're referencing an existing frame, this animation
  156. // must be sequenced!
  157. gfSequenced = TRUE;
  158. }
  159. gastep[gcstep].ifrm = ifrm;
  160. gastep[gcstep].jifRate = jifRate;
  161. gcstep++;
  162. return TRUE;
  163. }
  164. BOOL WriteAniFile(char *pszOutFile, char *pszTitle, char *pszAuthor)
  165. {
  166. int i;
  167. FILE *hfOut, *hfIn;
  168. ANIHEADER anih;
  169. JIF jifRate, *pjif;
  170. DWORD len, cbIn, ulNewPtr;
  171. char *pbIn, szT[80];
  172. DWORD *pseq;
  173. long offICLst;
  174. DWORD cbICLst;
  175. // Open the output file.
  176. printf("MAKEANI: Opening output file \"%s\"...\r", pszOutFile);
  177. hfOut = fopen(pszOutFile, "wb");
  178. if (hfOut == NULL)
  179. return FALSE;
  180. printf("MAKEANI: Writing header... \r");
  181. // Write out the RIFF file identifier.
  182. WriteTag(hfOut, FOURCC_RIFF, sizeof(DWORD));
  183. len = FOURCC_ACON;
  184. fwrite(&len, 1, sizeof(DWORD), hfOut);
  185. // If we have any info to add, write an INFO list.
  186. if (pszTitle != NULL || pszAuthor != NULL) {
  187. len = 0;
  188. if (pszTitle != NULL)
  189. len += WORDALIGN(strlen(pszTitle) + 1) + sizeof(RTAG);
  190. if (pszAuthor != NULL)
  191. len += WORDALIGN(strlen(pszAuthor) + 1) + sizeof(RTAG);
  192. WriteTag(hfOut, FOURCC_LIST, len + sizeof(DWORD));
  193. len = FOURCC_INFO;
  194. fwrite(&len, 1, sizeof(DWORD), hfOut);
  195. }
  196. // Write out the title string if one is passed in.
  197. if (pszTitle != NULL) {
  198. printf("MAKEANI: Writing title... \n");
  199. // Write the INAM (Name) RTAG.
  200. len = strlen(pszTitle) + 1; // + 1 for 0 terminator.
  201. WriteTag(hfOut, FOURCC_INAM, len);
  202. // Write out the title string itself.
  203. fwrite(pszTitle, 1, WORDALIGN(len), hfOut);
  204. }
  205. // Write out the author string if one is passed in.
  206. if (pszAuthor != NULL) {
  207. printf("MAKEANI: Writing author... \n");
  208. // Write the IART (Artist) RTAG.
  209. len = strlen(pszAuthor) + 1; // + 1 for 0 terminator.
  210. WriteTag(hfOut, FOURCC_IART, len);
  211. // Write out the author string itself.
  212. fwrite(pszAuthor, 1, WORDALIGN(len), hfOut);
  213. }
  214. // Write out the ANIHEADER RTAG.
  215. WriteTag(hfOut, FOURCC_anih, sizeof(ANIHEADER));
  216. // Write out the ANIHEADER.
  217. anih.cbSizeof = sizeof(ANIHEADER);
  218. anih.cFrames = gcfrm;
  219. anih.cSteps = gcstep;
  220. anih.cx = anih.cy = anih.cBitCount = anih.cPlanes = 0;
  221. anih.jifRate = gastep[0].jifRate;
  222. if (gfSequenced)
  223. anih.fl = AF_ICON | AF_SEQUENCE;
  224. else
  225. anih.fl = AF_ICON;
  226. fwrite(&anih, 1, WORDALIGN(sizeof(ANIHEADER)), hfOut);
  227. // Determine if all frames are to be played at the same rate. If not,
  228. // write out a RATE chunk.
  229. jifRate = gastep[0].jifRate;
  230. for (i = 1; i < gcstep; i++) {
  231. if (gastep[i].jifRate != jifRate) {
  232. printf("MAKEANI: Writing RATE chunk...\n");
  233. len = sizeof(JIF) * gcstep;
  234. WriteTag(hfOut, FOURCC_rate, len);
  235. pjif = malloc(len);
  236. for (i = 0; i < gcstep; i++)
  237. pjif[i] = gastep[i].jifRate;
  238. fwrite(pjif, 1, WORDALIGN(len), hfOut);
  239. free(pjif);
  240. break;
  241. }
  242. }
  243. // Write a sequence step array if the animation is sequenced.
  244. if (gfSequenced) {
  245. printf("MAKEANI: Writing SEQ chunk...\n");
  246. len = sizeof(DWORD) * gcstep;
  247. WriteTag(hfOut, FOURCC_seq, len);
  248. pseq = malloc(len);
  249. for (i = 0; i < gcstep; i++)
  250. pseq[i] = gastep[i].ifrm;
  251. fwrite(pseq, 1, WORDALIGN(len), hfOut);
  252. free(pseq);
  253. }
  254. // Write out the ICON List */
  255. WriteTag(hfOut, FOURCC_LIST, 0);
  256. offICLst = ftell(hfOut);
  257. len = FOURCC_fram;
  258. fwrite(&len, 1, sizeof(DWORD), hfOut);
  259. for (i = 0; i < gcfrm; i++) {
  260. // Note the spaces for clearing to the end of the previous line.
  261. printf("MAKEANI: Reading frame %3d: \"%s\"", i, gafrm[i].pszFile);
  262. // Find out how big the file is so we can read the whole thing in.
  263. hfIn = fopen(gafrm[i].pszFile, "rb");
  264. if (hfIn == NULL) {
  265. // Maybe the user just forgot to give the .CUR file extension.
  266. strcpy(szT, gafrm[i].pszFile);
  267. strcat(szT, ".cur");
  268. hfIn = fopen(szT, "rb");
  269. if (hfIn == NULL) {
  270. printf("...failed\n");
  271. continue;
  272. }
  273. }
  274. printf("\r");
  275. cbIn = _filelength(_fileno(hfIn));
  276. // Allocate buffer to read the mouse pointer images into.
  277. pbIn = malloc(WORDALIGN(cbIn));
  278. if (pbIn == NULL) {
  279. fclose(hfIn);
  280. printf("...out of memory\n");
  281. continue;
  282. }
  283. // Read the mouse pointer image in.
  284. fread(pbIn, 1, cbIn, hfIn);
  285. fclose(hfIn);
  286. printf("MAKEANI: Writing frame %3d: \"%s\"\n", i, gafrm[i].pszFile);
  287. WriteTag(hfOut, FOURCC_icon, cbIn);
  288. fwrite(pbIn, 1, WORDALIGN(cbIn), hfOut);
  289. // Free up that mouse pointer buffer.
  290. free(pbIn);
  291. }
  292. // Backpatch length of file, and frame list length
  293. cbICLst = ftell(hfOut) - offICLst;
  294. printf("MAKEANI: Back-patching lengths... \r");
  295. len = ftell(hfOut) - sizeof(RTAG);
  296. fseek(hfOut, sizeof(DWORD), SEEK_SET);
  297. fwrite(&len, 1, sizeof(DWORD), hfOut);
  298. fseek(hfOut, offICLst - sizeof(DWORD), SEEK_SET);
  299. fwrite(&cbICLst, 1, sizeof(DWORD), hfOut);
  300. fclose(hfOut);
  301. printf("MAKEANI: Done. \n");
  302. return TRUE;
  303. }
  304. BOOL QueryAniInfo(char *pszFile)
  305. {
  306. FILE *hf;
  307. char szIndent[80];
  308. RTAG tag;
  309. DWORD dw;
  310. szIndent[0] = 0;
  311. hf = fopen(pszFile, "rb");
  312. if (hf == NULL) {
  313. printf("MAKEANI: Can't open \"%s\".\n", pszFile);
  314. return FALSE;
  315. }
  316. ReadTag(hf, &tag);
  317. // First tag must always be RIFF.
  318. if (tag.ckID != FOURCC_RIFF) {
  319. printf("MAKEANI: \"%s\" is not a valid RIFF file.\n", pszFile);
  320. fclose(hf);
  321. return FALSE;
  322. }
  323. printf("\n\"%s\"\n", pszFile);
  324. DumpList(hf, &tag, szIndent, FALSE);
  325. fclose(hf);
  326. return TRUE;
  327. }
  328. BOOL DumpList(FILE *hf, PRTAG ptag, char *pszIndent, BOOL fList)
  329. {
  330. int len;
  331. char szType[5] = "TEMP";
  332. char *pbT;
  333. fread(szType, 1, sizeof(DWORD), hf);
  334. if (fList) {
  335. printf("%sLIST %s (%d)\n", pszIndent, szType, ptag->ckSize);
  336. len = WORDALIGN(ptag->ckSize) - sizeof(DWORD);
  337. } else {
  338. printf("%sRIFF %s (%d)\n", pszIndent, szType, ptag->ckSize);
  339. len = 1000000000;
  340. }
  341. strcat(pszIndent, " ");
  342. while (len > 0) {
  343. if (!ReadTag(hf, ptag))
  344. return FALSE;
  345. len -= WORDALIGN(ptag->ckSize) + sizeof(RTAG);
  346. if (ptag->ckID == FOURCC_LIST) {
  347. // Recurse on lists.
  348. DumpList(hf, ptag, pszIndent, TRUE);
  349. } else {
  350. *(DWORD *)szType = ptag->ckID;
  351. printf("%s%s (%d)\t", pszIndent, szType, ptag->ckSize);
  352. if ((ptag->ckID == FOURCC_INAM) || (ptag->ckID == FOURCC_IART)) {
  353. pbT = malloc(WORDALIGN(ptag->ckSize));
  354. fread(pbT, 1, WORDALIGN(ptag->ckSize), hf);
  355. printf("\"%s\"\n", pbT);
  356. free(pbT);
  357. } else {
  358. printf("\n");
  359. fseek(hf, WORDALIGN(ptag->ckSize), SEEK_CUR);
  360. }
  361. }
  362. }
  363. pszIndent[strlen(pszIndent) - 4] = 0;
  364. return TRUE;
  365. }
  366. VOID PrintHelp(BOOL fFullHelp)
  367. {
  368. printf("Microsoft(R) Animated Cursor Tool Version 1.0\n");
  369. printf("(C) 1993 Microsoft Corp. All rights reserved.\n\n");
  370. printf("Usage:\n");
  371. printf(" makeani [-?] [-t <title>] [-a <author>] [-o <outfile>] [-r #] [<file> ...]\n");
  372. if (!fFullHelp)
  373. return;
  374. printf("\nOptions:\n");
  375. printf(" -o <outfile>: Designates output file.\n");
  376. printf(" -q <file> : Queries an existing ANI file, displaying file info.\n");
  377. printf(" -t <title> : Put title string in output file.\n");
  378. printf(" -a <author> : Put author string in output file.\n");
  379. printf(" -r # : Set inter-frame delay rate (in jiffies - 1/60 sec) for all\n");
  380. printf(" frames following. This option may be repeated multiple times.\n");
  381. printf(" If unspecified, the rate defaults to 1 (fastest possible).\n");
  382. printf(" -? : Print this help message.\n\n");
  383. printf("Example:\n");
  384. printf(" makeani -t \"New\" -o new.ani -r 4 frame1.cur frame2.cur -r 20 frame3.cur\n");
  385. }
  386. BOOL ReadTag(FILE *hf, PRTAG ptag)
  387. {
  388. ptag->ckID = ptag->ckSize = 0L;
  389. if (fread(ptag, 1, sizeof(RTAG), hf) != 0)
  390. return TRUE;
  391. else
  392. return FALSE;
  393. }
  394. BOOL WriteTag(FILE *hf, DWORD type, DWORD len)
  395. {
  396. RTAG tag;
  397. tag.ckID = type;
  398. tag.ckSize = len;
  399. if (fwrite(&tag, 1, sizeof(RTAG), hf) != 0)
  400. return TRUE;
  401. return FALSE;
  402. }