CAPTOKEN.CPP 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************
  19. *
  20. * C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
  21. *
  22. *----------------------------------------------------------------------------
  23. *
  24. * FILE
  25. * captoken.c
  26. *
  27. * DESCRIPTION
  28. * Tokenize a caption script for playback processing.
  29. *
  30. * PROGRAMMER
  31. * Denzil E. Long, Jr.
  32. *
  33. * DATE
  34. * July 26, 1995
  35. *
  36. ****************************************************************************/
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <errno.h>
  40. #include <string.h>
  41. #include <ctype.h>
  42. #include "captoken.h"
  43. /*---------------------------------------------------------------------------
  44. * PRIVATE DECLARATIONS
  45. *-------------------------------------------------------------------------*/
  46. #define STRING_LENGTH 256
  47. #define PADSIZE(size) (((size)+1)&(~1))
  48. typedef enum {
  49. TOKEN_NULL = 0,
  50. TOKEN_BGCOL,
  51. TOKEN_FGCOL,
  52. TOKEN_XPOS,
  53. TOKEN_YPOS,
  54. TOKEN_ABS,
  55. TOKEN_LEFT,
  56. TOKEN_RIGHT,
  57. TOKEN_CENTER,
  58. TOKEN_FLASH,
  59. TOKEN_CPF,
  60. TOKEN_END
  61. } TokenTag;
  62. typedef struct _Token {
  63. char *name;
  64. long tag;
  65. } Token;
  66. /* Script tokens:
  67. * BG/BGCOL - Background pen color (EX: BG=<color name>)
  68. * FG/FGCOL - Foreground pen color (EX: FG=<color name>)
  69. * X/XPOS - X pixel position of text (EX: X=<pixel cord>)
  70. * Y/YPOS - Y pixel position of text (EX: Y=<pixel cord>)
  71. * ABS/ABSOLUTE - Absolute justification
  72. * LEFT - Left side justification
  73. * RIGHT - Right side justification
  74. * CENTER - Center justification
  75. * FLASH - Enable flashing of text
  76. * CPF - Print rate in characters per frame (EX: CPF=<rate>)
  77. * END - Terminate compilation of caption script
  78. */
  79. Token tokens[] = {
  80. "BG", TOKEN_BGCOL,
  81. "BGCOL", TOKEN_BGCOL,
  82. "FG", TOKEN_FGCOL,
  83. "FGCOL", TOKEN_FGCOL,
  84. "X", TOKEN_XPOS,
  85. "XPOS", TOKEN_XPOS,
  86. "Y", TOKEN_YPOS,
  87. "YPOS", TOKEN_YPOS,
  88. "ABS", TOKEN_ABS,
  89. "ABSOLUTE", TOKEN_ABS,
  90. "LEFT", TOKEN_LEFT,
  91. "RIGHT", TOKEN_RIGHT,
  92. "CENTER", TOKEN_CENTER,
  93. "FLASH", TOKEN_FLASH,
  94. "CPF", TOKEN_CPF,
  95. "END", TOKEN_END,
  96. NULL, TOKEN_NULL,
  97. };
  98. Token colors[] = {
  99. "BLACK", 0,
  100. "WHITE", 251,
  101. "RED", 252,
  102. "GREEN", 253,
  103. "SHADOW", 254,
  104. "CYCLE", 255,
  105. NULL, -1,
  106. };
  107. /* Prototypes. */
  108. static long GetColorNum(char *name);
  109. static long IsNumeric(char *string);
  110. static void FormatString(char *string);
  111. /****************************************************************************
  112. *
  113. * NAME
  114. * BuildCaptions - Compile a caption script.
  115. *
  116. * SYNOPSIS
  117. * Size = BuildCaptions(Name, Buffer)
  118. *
  119. * long BuildCaptions(char *, char *);
  120. *
  121. * FUNCTION
  122. * Generate a compiled caption script for use in VQA playback.
  123. *
  124. * INPUTS
  125. * Name - Name of caption script file to compile.
  126. * Buffer - Buffer to put compiled captions into.
  127. *
  128. * RESULT
  129. * Size - Size of compiled captions (in bytes).
  130. *
  131. ****************************************************************************/
  132. long BuildCaptions(char *name, char *buffer)
  133. {
  134. FILE *fp;
  135. char *ptr;
  136. char *ptr1;
  137. long size = 0;
  138. long error;
  139. long i;
  140. long tag;
  141. CaptionText caption;
  142. char string[STRING_LENGTH];
  143. /* Initialize the caption parameters. */
  144. memset(&caption, 0, sizeof(CaptionText));
  145. /* Open the captions script file. */
  146. fp = fopen(name, "r");
  147. if (fp != NULL) {
  148. error = 0;
  149. while (!error) {
  150. if (fgets(string, STRING_LENGTH, fp) == NULL) {
  151. if (errno == 0) {
  152. error = 1;
  153. }
  154. break;
  155. }
  156. /* Replace the newline with a NULL terminator. */
  157. string[strlen(string) - 1] = 0;
  158. /* Ignore comment lines. */
  159. if (string[0] == ';') continue;
  160. ptr = strtok(string, "=");
  161. if (ptr != NULL) {
  162. /* Check for a comma */
  163. ptr1 = strchr(ptr, ',');
  164. if (ptr1 != NULL) {
  165. *ptr1++ = 0;
  166. }
  167. /* Is this a frame number. */
  168. if (IsNumeric(ptr) && IsNumeric(ptr1)) {
  169. i = atoi(ptr);
  170. /* Frames must be defined in ascending order. */
  171. if ((unsigned short)i >= caption.OnFrame) {
  172. caption.OnFrame = i;
  173. caption.OffFrame = atoi(ptr1);
  174. caption.Size = sizeof(CaptionText);
  175. /* Get caption text. */
  176. ptr = strtok(NULL, "");
  177. if (ptr != NULL) {
  178. FormatString(ptr);
  179. i = strlen(ptr) + 1;
  180. caption.Size += PADSIZE(i);
  181. size += caption.Size;
  182. /* Copy the caption structure. */
  183. memcpy(buffer, &caption, sizeof(CaptionText));
  184. buffer += sizeof(CaptionText);
  185. /* Copy the caption text. */
  186. memcpy(buffer, ptr, i);
  187. buffer += i;
  188. /* WORD align */
  189. if (PADSIZE(i) > i) {
  190. *buffer++ = 0;
  191. }
  192. }
  193. } else {
  194. error = 1;
  195. break;
  196. }
  197. } else {
  198. /* Search for matching token. */
  199. tag = TOKEN_NULL;
  200. i = 0;
  201. while (tokens[i].name != NULL) {
  202. if (strcmpi(tokens[i].name, ptr) == 0) {
  203. tag = tokens[i].tag;
  204. break;
  205. }
  206. i++;
  207. }
  208. /* Get the data element. */
  209. ptr = strtok(NULL, "");
  210. switch (tag) {
  211. case TOKEN_BGCOL:
  212. caption.BgPen = (char)GetColorNum(ptr);
  213. break;
  214. case TOKEN_FGCOL:
  215. caption.FgPen = (char)GetColorNum(ptr);
  216. break;
  217. case TOKEN_XPOS:
  218. caption.Xpos = (unsigned short)atoi(ptr);
  219. break;
  220. case TOKEN_YPOS:
  221. caption.Ypos = (unsigned short)atoi(ptr);
  222. break;
  223. case TOKEN_ABS:
  224. caption.Flags &= ~CTF_JUSTIFY;
  225. caption.Flags |= CTF_ABS;
  226. break;
  227. case TOKEN_LEFT:
  228. caption.Flags &= ~CTF_JUSTIFY;
  229. caption.Flags |= CTF_LEFT;
  230. break;
  231. case TOKEN_RIGHT:
  232. caption.Flags &= ~CTF_JUSTIFY;
  233. caption.Flags |= CTF_RIGHT;
  234. break;
  235. case TOKEN_CENTER:
  236. caption.Flags &= ~CTF_JUSTIFY;
  237. caption.Flags |= CTF_CENTER;
  238. break;
  239. case TOKEN_FLASH:
  240. if (strcmpi(ptr, "OFF") == 0) {
  241. caption.Flags &= ~CTF_FLASH;
  242. } else {
  243. caption.Flags |= CTF_FLASH;
  244. }
  245. break;
  246. case TOKEN_CPF:
  247. caption.CPF = (char)atoi(ptr);
  248. break;
  249. /* Termination captions */
  250. case TOKEN_END:
  251. caption.Size = sizeof(CaptionText);
  252. caption.OnFrame = (unsigned short)-1;
  253. memcpy(buffer, &caption, sizeof(CaptionText));
  254. buffer += sizeof(CaptionText);
  255. break;
  256. default:
  257. break;
  258. }
  259. }
  260. }
  261. }
  262. /* Close the script file. */
  263. fclose(fp);
  264. }
  265. return (size);
  266. }
  267. /****************************************************************************
  268. *
  269. * NAME
  270. * GetColorNum - Get the color number from the color name.
  271. *
  272. * SYNOPSIS
  273. * Color = GetColorNum(Name)
  274. *
  275. * long GetColorNum(char *);
  276. *
  277. * FUNCTION
  278. * Look the color number that corresponds to the color name.
  279. *
  280. * INPUTS
  281. * Name - Name of color.
  282. *
  283. * RESULT
  284. * Color - Color number.
  285. *
  286. ****************************************************************************/
  287. static long GetColorNum(char *name)
  288. {
  289. long color = -1;
  290. long i;
  291. i = 0;
  292. /* Scan for a matching name and return the corresponding color number. */
  293. while (colors[i].name != NULL) {
  294. if (strcmpi(colors[i].name, name) == 0) {
  295. color = colors[i].tag;
  296. }
  297. i++;
  298. }
  299. return (color);
  300. }
  301. /****************************************************************************
  302. *
  303. * NAME
  304. * IsNumeric - Check if a string is numeric.
  305. *
  306. * SYNOPSIS
  307. * Condition = IsNumeric(String)
  308. *
  309. * long IsNumeric(char *);
  310. *
  311. * FUNCTION
  312. * Interogate the string to see if it represents a numeric value. Each
  313. * byte of the string must be between 0x30 and 0x39 inclusively.
  314. *
  315. * INPUTS
  316. * String - String to check.
  317. *
  318. * RESULT
  319. * Condition - 1 if numeric, 0 if not.
  320. *
  321. ****************************************************************************/
  322. static long IsNumeric(char *string)
  323. {
  324. long flag = 1;
  325. /* Ignore any proceeding sign designation. */
  326. if ((*string == '-') || (*string == '+')) {
  327. string++;
  328. }
  329. /* Check to see if every byte in the string is a digit. */
  330. while (flag && (*string != 0)) {
  331. if (!isdigit(*string++)) {
  332. flag = 0;
  333. }
  334. }
  335. return (flag);
  336. }
  337. /****************************************************************************
  338. *
  339. * NAME
  340. * FormatString - Parse any format codes in the string.
  341. *
  342. * SYNOPSIS
  343. * FormatString(String)
  344. *
  345. * void FormatString(char *);
  346. *
  347. * FUNCTION
  348. * Format a string with any embedded format commands contained in the
  349. * input string.
  350. *
  351. * Supported format commands:
  352. * /n - Insert carriage return. (0x0D)
  353. * /r - Insert carriage return. (0x0D)
  354. * // - Literal backslash.
  355. *
  356. * INPUTS
  357. * String - Pointer to string to format.
  358. *
  359. * RESULT
  360. * NONE
  361. *
  362. ****************************************************************************/
  363. static void FormatString(char *string)
  364. {
  365. char *ptr;
  366. /* NULL strings are invalid. */
  367. if (string != NULL) {
  368. ptr = string;
  369. /* Scan the string for embedded format commands. */
  370. while ((ptr = strchr(ptr, '/')) != NULL) {
  371. switch (*(ptr + 1)) {
  372. /* Carriage return. */
  373. case 'n':
  374. case 'r':
  375. *ptr = 0x0D;
  376. break;
  377. /* Literal backslash. */
  378. case '/':
  379. break;
  380. default:
  381. break;
  382. }
  383. /* Remove the unwanted character. */
  384. strcpy((ptr + 1), (ptr + 2));
  385. }
  386. }
  387. }