text.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107
  1. /* -*- mode: c; tab-width: 4; c-basic-offset: 3; c-file-style: "linux" -*- */
  2. //
  3. // Copyright (c) 2008, Wei Mingzhi <whistler_wmz@users.sf.net>.
  4. // All rights reserved.
  5. //
  6. // Portions based on PALx Project by palxex.
  7. // Copyright (c) 2006-2008, Pal Lockheart <palxex@gmail.com>.
  8. //
  9. // This file is part of SDLPAL.
  10. //
  11. // SDLPAL is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. // Modified by Lou Yihua <louyihua@21cn.com> with Unicode support, 2015
  25. //
  26. #include "main.h"
  27. #include <errno.h>
  28. #define FONT_COLOR_DEFAULT 0x4F
  29. #define FONT_COLOR_YELLOW 0x2D
  30. #define FONT_COLOR_RED 0x1A
  31. #define FONT_COLOR_CYAN 0x8D
  32. #define FONT_COLOR_CYAN_ALT 0x8C
  33. BOOL g_fUpdatedInBattle = FALSE;
  34. #define MESSAGE_MAX_BUFFER_SIZE 512
  35. #define INCLUDE_CODEPAGE_H
  36. #include "codepage.h"
  37. #ifndef PAL_CLASSIC
  38. # define ATB_WORD_COUNT 6
  39. static LPWSTR gc_rgszAdditionalWords[CP_MAX][ATB_WORD_COUNT] = {
  40. { L"\x6230\x9B25\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  41. { L"\x6218\x6597\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  42. //{ L"\x6226\x95D8\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  43. };
  44. static LPWSTR gc_rgszDefaultAdditionalWords[ATB_WORD_COUNT] = { NULL, L"\xFF11", L"\xFF12", L"\xFF13", L"\xFF14", L"\xFF15" };
  45. #endif
  46. #define SDLPAL_EXTRA_WORD_COUNT 1
  47. static LPWSTR gc_rgszSDLPalWords[CP_MAX][SDLPAL_EXTRA_WORD_COUNT] = {
  48. { L"\x8FD4\x56DE\x8A2D\x5B9A" },
  49. { L"\x8FD4\x56DE\x8BBE\x7F6E" },
  50. };
  51. LPWSTR g_rcCredits[12];
  52. typedef struct tagTEXTLIB
  53. {
  54. LPWSTR *lpWordBuf;
  55. LPWSTR *lpMsgBuf;
  56. int **lpIndexBuf;
  57. int nWords;
  58. int nMsgs;
  59. int nIndices;
  60. int nCurrentDialogLine;
  61. BYTE bCurrentFontColor;
  62. PAL_POS posIcon;
  63. PAL_POS posDialogTitle;
  64. PAL_POS posDialogText;
  65. BYTE bDialogPosition;
  66. BYTE bIcon;
  67. int iDelayTime;
  68. BOOL fUserSkip;
  69. BOOL fPlayingRNG;
  70. BYTE bufDialogIcons[282];
  71. } TEXTLIB, *LPTEXTLIB;
  72. static TEXTLIB g_TextLib;
  73. PAL_FORCE_INLINE int
  74. PAL_ParseLine(
  75. char *line,
  76. char **value,
  77. int *length,
  78. int deltrail
  79. )
  80. {
  81. //
  82. // Remove the leading spaces
  83. //
  84. while (*line && iswspace(*line)) line++;
  85. //
  86. // Skip comments starting with '#'
  87. //
  88. if (*line && *line != '#')
  89. {
  90. //
  91. // Split the index and value
  92. //
  93. LPSTR val = strchr(line, '=');
  94. if (val)
  95. {
  96. //
  97. // Remove the trailing spaces
  98. //
  99. LPSTR end = line + strlen(line);
  100. int index;
  101. if (end > line && end[-1] == '\n') *(--end) = 0;
  102. if (deltrail) while (end > line && iswspace(end[-1])) *(--end) = 0;
  103. //
  104. // Parse the index and pass out value
  105. //
  106. if (sscanf(line, "%d", &index) == 1)
  107. {
  108. *value = val + 1;
  109. *length = end - *value;
  110. return index;
  111. }
  112. }
  113. }
  114. return 0;
  115. }
  116. PAL_FORCE_INLINE char *
  117. PAL_ReadOneLine(
  118. char *temp,
  119. int limit,
  120. FILE *fp
  121. )
  122. {
  123. if (fgets(temp, limit, fp))
  124. {
  125. int n = strlen(temp);
  126. if (n == limit - 1 && temp[n - 1] != '\n' && !feof(fp))
  127. {
  128. // Line too long, try to read it as a whole
  129. int nn = 2;
  130. char *tmp = strdup(temp);
  131. while (!feof(fp))
  132. {
  133. if (!(tmp = (char *)realloc(tmp, nn * limit)))
  134. {
  135. TerminateOnError("PAL_ReadOneLine(): failed to allocate memory for long line!");
  136. }
  137. if (fgets(tmp + n, limit + 1, fp))
  138. {
  139. n += strlen(tmp + n);
  140. if (n < limit - 1 || temp[n - 1] == '\n')
  141. break;
  142. else
  143. nn++;
  144. }
  145. }
  146. if (tmp[n - 1] == '\n') tmp[n - 1] = 0;
  147. return tmp;
  148. }
  149. else
  150. {
  151. while (n > 0 && (temp[n - 1] == '\n' || temp[n - 1] == '\r')) temp[--n] = 0;
  152. return temp;
  153. }
  154. }
  155. else
  156. return NULL;
  157. }
  158. static int
  159. PAL_ReadMessageFile(
  160. FILE *fp
  161. )
  162. {
  163. char temp[MESSAGE_MAX_BUFFER_SIZE];
  164. struct _msg_entry
  165. {
  166. struct _msg_entry *next;
  167. wchar_t *value;
  168. } *cur_val = NULL;
  169. struct _msg_list_entry
  170. {
  171. struct _msg_list_entry *next;
  172. struct _msg_entry *value;
  173. int index;
  174. int count;
  175. } *head = NULL, *item = NULL;
  176. struct _word_list_entry
  177. {
  178. struct _word_list_entry *next;
  179. wchar_t *value;
  180. int index;
  181. } whead = { NULL, NULL }, *witem = NULL;
  182. enum _message_state
  183. {
  184. ST_OUTSIDE,
  185. ST_DIALOG,
  186. ST_WORD,
  187. ST_CREDIT,
  188. ST_LAYOUT
  189. } state = ST_OUTSIDE;
  190. int idx_cnt = 0, msg_cnt = 0, word_cnt = 0, sid, eid = -1;
  191. while (!feof(fp))
  192. {
  193. char *buffer;
  194. if (buffer = PAL_ReadOneLine(temp, MESSAGE_MAX_BUFFER_SIZE, fp))
  195. {
  196. switch(state)
  197. {
  198. case ST_OUTSIDE:
  199. //
  200. // Skip comments starting with '#'
  201. //
  202. if (*buffer && *buffer != '#')
  203. {
  204. if (strncmp(buffer, "[BEGIN MESSAGE]", 15) == 0 &&
  205. sscanf(buffer + 15, "%d", &sid) == 1 && sid > eid)
  206. {
  207. state = ST_DIALOG;
  208. //
  209. // First save values (converted wide string) into a linked list
  210. //
  211. if (head)
  212. {
  213. item->next = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  214. item = item->next;
  215. }
  216. else
  217. {
  218. head = (struct _msg_list_entry *)UTIL_malloc(sizeof(struct _msg_list_entry));
  219. item = head;
  220. }
  221. item->value = NULL; item->index = sid;
  222. item->count = 0; item->next = NULL; cur_val = NULL;
  223. if (idx_cnt < item->index) idx_cnt = item->index;
  224. }
  225. else if (strncmp(buffer, "[BEGIN WORDS]", 13) == 0 && !witem)
  226. {
  227. state = ST_WORD;
  228. //
  229. // First save values (converted wide string) into a linked list
  230. //
  231. witem = &whead;
  232. }
  233. else if (strncmp(buffer, "[BEGIN CREDITS]", 15) == 0 && !witem)
  234. {
  235. state = ST_CREDIT;
  236. }
  237. else if (strncmp(buffer, "[BEGIN LAYOUT]", 14) == 0 && !witem)
  238. {
  239. state = ST_LAYOUT;
  240. gConfig.fUseCustomScreenLayout = TRUE;
  241. }
  242. else
  243. {
  244. // Just ignore invalid lines
  245. #ifdef ENABLE_LOG
  246. UTIL_WriteLog(LOG_ERR, "PAL_ReadMessageFile(): encounter invalid line '%s'!\n", line);
  247. #endif
  248. }
  249. }
  250. break;
  251. case ST_DIALOG:
  252. //
  253. // Check if to end one dialog
  254. //
  255. if (strncmp(buffer, "[END MESSAGE]", 13) == 0 &&
  256. sscanf(buffer + 13, "%d", &eid) == 1 && eid >= sid)
  257. {
  258. // End dialog
  259. state = ST_OUTSIDE;
  260. }
  261. else
  262. {
  263. if (cur_val)
  264. {
  265. cur_val->next = (struct _msg_entry *)UTIL_malloc(sizeof(struct _msg_entry));
  266. cur_val = cur_val->next;
  267. }
  268. else
  269. cur_val = (struct _msg_entry *)UTIL_malloc(sizeof(struct _msg_entry));
  270. if (strncmp(buffer, "[CLEAR MESSAGE]", 15) == 0)
  271. {
  272. cur_val->value = NULL;
  273. }
  274. else
  275. {
  276. int len = PAL_MultiByteToWideCharCP(CP_UTF_8, buffer, -1, NULL, 0);
  277. cur_val->value = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  278. PAL_MultiByteToWideCharCP(CP_UTF_8, buffer, -1, cur_val->value, len);
  279. msg_cnt++;
  280. }
  281. if (!item->value) item->value = cur_val;
  282. cur_val->next = NULL; item->count++;
  283. }
  284. break;
  285. case ST_WORD:
  286. //
  287. // Check if to end word list
  288. //
  289. if (strncmp(buffer, "[END WORDS]", 11) == 0)
  290. {
  291. // End word list
  292. state = ST_OUTSIDE;
  293. }
  294. else
  295. {
  296. char *v;
  297. int l, i = PAL_ParseLine(buffer, &v, &l, FALSE);
  298. if (i > 0)
  299. {
  300. int len = PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, NULL, 0);
  301. struct _word_list_entry *val = (struct _word_list_entry *)UTIL_malloc(sizeof(struct _word_list_entry));
  302. val->value = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  303. PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, val->value, len);
  304. val->index = i; val->next = NULL;
  305. witem->next = val; witem = witem->next;
  306. if (word_cnt < i) word_cnt = i;
  307. }
  308. }
  309. break;
  310. case ST_CREDIT:
  311. //
  312. // Check if to end credit list
  313. //
  314. if (strncmp(buffer, "[END CREDITS]", 13) == 0)
  315. {
  316. // End credit list
  317. state = ST_OUTSIDE;
  318. }
  319. else
  320. {
  321. char *v;
  322. int l, i = PAL_ParseLine(buffer, &v, &l, FALSE);
  323. if ((i == 1 || (i >= 6 && i <= 11)) && !g_rcCredits[i])
  324. {
  325. int limit = (i == 1) ? 24 * 8 : 40 * 8, w = 0, j = 0, len;
  326. if (i == 6 || i == 7)
  327. {
  328. if (PAL_PLATFORM && PAL_CREDIT && PAL_PORTYEAR)
  329. {
  330. const char *templates[] = { "${platform}", "${author}", "${year}" };
  331. const char *values[] = { PAL_PLATFORM, PAL_CREDIT, PAL_PORTYEAR };
  332. const int matchlen[] = { 11, 9, 7 };
  333. const int valuelen[] = { sizeof(PAL_PLATFORM) - 1, sizeof(PAL_CREDIT) - 1, sizeof(PAL_PORTYEAR) - 1 };
  334. char *tmp = (char *)alloca(valuelen[0] + valuelen[1] + valuelen[2] + l + 1);
  335. char *dst = tmp, *src = v;
  336. while (*src)
  337. {
  338. if (*src == '$')
  339. {
  340. int k;
  341. for (k = 0; k < 3 && strncmp(src, templates[k], matchlen[k]); k++);
  342. if (k < 3)
  343. {
  344. strcpy(dst, values[k]);
  345. dst += valuelen[k];
  346. src += matchlen[k];
  347. continue;
  348. }
  349. }
  350. *dst++ = *src++;
  351. }
  352. *dst = 0;
  353. len = PAL_MultiByteToWideCharCP(CP_UTF_8, tmp, -1, NULL, 0);
  354. g_rcCredits[i] = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  355. PAL_MultiByteToWideCharCP(CP_UTF_8, tmp, -1, g_rcCredits[i], len);
  356. }
  357. }
  358. else
  359. {
  360. len = PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, NULL, 0);
  361. g_rcCredits[i] = (wchar_t *)UTIL_malloc(len * sizeof(wchar_t));
  362. PAL_MultiByteToWideCharCP(CP_UTF_8, v, -1, g_rcCredits[i], len);
  363. }
  364. if (g_rcCredits[i])
  365. {
  366. // Limit the length of texts
  367. while (w < limit && j < len - 1) w += PAL_CharWidth(g_rcCredits[i][j++]);
  368. if (w >= limit) g_rcCredits[i][w > limit ? j - 1 : j] = 0;
  369. }
  370. }
  371. }
  372. break;
  373. case ST_LAYOUT:
  374. if (strncmp(buffer, "[END LAYOUT]", 12) == 0)
  375. {
  376. // End layout
  377. state = ST_OUTSIDE;
  378. }
  379. else
  380. {
  381. char *v;
  382. int x, y, f, n, l, i = PAL_ParseLine(buffer, &v, &l, FALSE);
  383. if (i >= 1 && i <= (sizeof(SCREENLAYOUT) / sizeof(PAL_POS)))
  384. {
  385. if ((n = sscanf(v, "%d,%d,%d", &x, &y, &f)) >= 2 && x < 320 && y < 200)
  386. {
  387. gConfig.ScreenLayoutArray[i - 1] = PAL_XY(x, y);
  388. if (n == 3) gConfig.ScreenLayoutFlag[i - 1] = f;
  389. }
  390. }
  391. }
  392. break;
  393. default:
  394. TerminateOnError("PAL_ReadMessageFile(): Reached an unknown state. Something really wrong may have happened!");
  395. break;
  396. }
  397. if (buffer != temp) free(buffer);
  398. }
  399. }
  400. if (msg_cnt > 0)
  401. {
  402. //
  403. // Move values from linked list to array
  404. //
  405. int idx_msg = 1;
  406. g_TextLib.nIndices = (idx_cnt += 1);
  407. g_TextLib.nMsgs = (msg_cnt += 1);
  408. g_TextLib.lpIndexBuf = (int **)UTIL_calloc(idx_cnt, sizeof(int *));
  409. g_TextLib.lpMsgBuf = (LPWSTR *)UTIL_calloc(msg_cnt, sizeof(LPWSTR));
  410. for (item = head; item; )
  411. {
  412. struct _msg_list_entry *temp = item->next;
  413. struct _msg_entry *msg = item->value;
  414. int index = 0;
  415. g_TextLib.lpIndexBuf[item->index] = (int *)UTIL_calloc(item->count + 1, sizeof(int));
  416. while (msg)
  417. {
  418. struct _msg_entry *tmp = msg->next;
  419. if (msg->value)
  420. {
  421. g_TextLib.lpIndexBuf[item->index][index++] = idx_msg;
  422. g_TextLib.lpMsgBuf[idx_msg++] = msg->value;
  423. }
  424. else
  425. g_TextLib.lpIndexBuf[item->index][index++] = 0;
  426. free(msg); msg = tmp;
  427. }
  428. g_TextLib.lpIndexBuf[item->index][item->count] = -1;
  429. free(item); item = temp;
  430. }
  431. }
  432. if (word_cnt > 0)
  433. {
  434. //
  435. // Move values from linked list to array
  436. //
  437. #ifndef PAL_CLASSIC
  438. int i;
  439. #endif
  440. if (word_cnt < MINIMAL_WORD_COUNT - 1) word_cnt = MINIMAL_WORD_COUNT - 1;
  441. g_TextLib.nWords = (word_cnt += 1);
  442. g_TextLib.lpWordBuf = (LPWSTR *)UTIL_calloc(word_cnt, sizeof(LPWSTR));
  443. for (witem = whead.next; witem; )
  444. {
  445. struct _word_list_entry *temp = witem->next;
  446. g_TextLib.lpWordBuf[witem->index] = witem->value;
  447. free(witem); witem = temp;
  448. }
  449. #ifndef PAL_CLASSIC
  450. for (i = 1; i < ATB_WORD_COUNT; i++)
  451. if (!g_TextLib.lpWordBuf[i + SYSMENU_LABEL_BATTLEMODE])
  452. g_TextLib.lpWordBuf[i + SYSMENU_LABEL_BATTLEMODE] = gc_rgszDefaultAdditionalWords[i];
  453. #endif
  454. }
  455. fclose(fp);
  456. return (msg_cnt > 0 && word_cnt > 0) ? 1 : 0;
  457. }
  458. INT
  459. PAL_InitText(
  460. VOID
  461. )
  462. /*++
  463. Purpose:
  464. Initialize the in-game texts.
  465. Parameters:
  466. None.
  467. Return value:
  468. 0 = success.
  469. -1 = memory allocation error.
  470. --*/
  471. {
  472. if (gConfig.pszMsgFile)
  473. {
  474. //
  475. // Open the message, index and word data files.
  476. //
  477. FILE *fp = UTIL_OpenRequiredFileForMode(gConfig.pszMsgFile, "r");
  478. //
  479. // Read the contents of the message, index and word data files.
  480. //
  481. if (!PAL_ReadMessageFile(fp))
  482. {
  483. return -1;
  484. }
  485. else
  486. {
  487. DWORD dwWordLength = 0;
  488. int i;
  489. for (i = 1; i < g_TextLib.nWords; i++)
  490. {
  491. if (g_TextLib.lpWordBuf[i])
  492. {
  493. LPWSTR ptr = g_TextLib.lpWordBuf[i];
  494. DWORD n = 0;
  495. while (*ptr) n += PAL_CharWidth(*ptr++) >> 3;
  496. if (dwWordLength < n) dwWordLength = n;
  497. }
  498. }
  499. gConfig.dwWordLength = dwWordLength;
  500. for (i = 0; i < 12; i++)
  501. {
  502. if (!g_rcCredits[i])
  503. g_rcCredits[i] = L"";
  504. }
  505. }
  506. }
  507. else
  508. {
  509. FILE *fpMsg, *fpWord;
  510. DWORD *offsets;
  511. LPWSTR tmp;
  512. LPBYTE temp;
  513. int wpos, wlen, i;
  514. //
  515. // Open the message and word data files.
  516. //
  517. fpMsg = UTIL_OpenRequiredFile("m.msg");
  518. fpWord = UTIL_OpenRequiredFile("word.dat");
  519. //
  520. // See how many words we have
  521. //
  522. fseek(fpWord, 0, SEEK_END);
  523. i = ftell(fpWord);
  524. //
  525. // Each word has 10 bytes
  526. //
  527. g_TextLib.nWords = (i + (gConfig.dwWordLength - 1)) / gConfig.dwWordLength;
  528. if (g_TextLib.nWords < MINIMAL_WORD_COUNT) g_TextLib.nWords = MINIMAL_WORD_COUNT;
  529. //
  530. // Read the words
  531. //
  532. temp = (LPBYTE)malloc(gConfig.dwWordLength * g_TextLib.nWords);
  533. if (temp == NULL)
  534. {
  535. fclose(fpWord);
  536. fclose(fpMsg);
  537. return -1;
  538. }
  539. fseek(fpWord, 0, SEEK_SET);
  540. fread(temp, i, 1, fpWord);
  541. memset(temp + i, 0, gConfig.dwWordLength * g_TextLib.nWords - i);
  542. //
  543. // Close the words file
  544. //
  545. fclose(fpWord);
  546. // Split the words and do code page conversion
  547. for (i = 0, wlen = 0; i < g_TextLib.nWords; i++)
  548. {
  549. int base = i * gConfig.dwWordLength;
  550. int pos = base + gConfig.dwWordLength - 1;
  551. while (pos >= base && temp[pos] == ' ') temp[pos--] = 0;
  552. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + base, gConfig.dwWordLength, NULL, 0) + 1;
  553. }
  554. g_TextLib.lpWordBuf = (LPWSTR*)malloc(g_TextLib.nWords * sizeof(LPWSTR));
  555. if (g_TextLib.lpWordBuf == NULL)
  556. {
  557. free(temp);
  558. fclose(fpWord);
  559. fclose(fpMsg);
  560. return -1;
  561. }
  562. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  563. if (tmp == NULL)
  564. {
  565. free(g_TextLib.lpWordBuf);
  566. free(temp);
  567. fclose(fpWord);
  568. fclose(fpMsg);
  569. return -1;
  570. }
  571. for (i = 0, wpos = 0; i < g_TextLib.nWords; i++)
  572. {
  573. int l;
  574. g_TextLib.lpWordBuf[i] = tmp + wpos;
  575. l = PAL_MultiByteToWideChar((LPCSTR)temp + i * gConfig.dwWordLength, gConfig.dwWordLength, g_TextLib.lpWordBuf[i], wlen - wpos);
  576. if (l > 0 && g_TextLib.lpWordBuf[i][l - 1] == '1')
  577. g_TextLib.lpWordBuf[i][l - 1] = 0;
  578. g_TextLib.lpWordBuf[i][l] = 0;
  579. wpos += l + 1;
  580. }
  581. free(temp);
  582. //
  583. // Read the message offsets. The message offsets are in SSS.MKF #3
  584. //
  585. i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD);
  586. g_TextLib.nMsgs = i - 1;
  587. offsets = (LPDWORD)malloc(i * sizeof(DWORD));
  588. if (offsets == NULL)
  589. {
  590. free(g_TextLib.lpWordBuf);
  591. fclose(fpMsg);
  592. return -1;
  593. }
  594. PAL_MKFReadChunk((LPBYTE)(offsets), i * sizeof(DWORD), 3, gpGlobals->f.fpSSS);
  595. //
  596. // Read the messages.
  597. //
  598. fseek(fpMsg, 0, SEEK_END);
  599. i = ftell(fpMsg);
  600. temp = (LPBYTE)malloc(i);
  601. if (temp == NULL)
  602. {
  603. free(offsets);
  604. free(g_TextLib.lpWordBuf[0]);
  605. free(g_TextLib.lpWordBuf);
  606. fclose(fpMsg);
  607. return -1;
  608. }
  609. fseek(fpMsg, 0, SEEK_SET);
  610. fread(temp, 1, i, fpMsg);
  611. fclose(fpMsg);
  612. // Split messages and do code page conversion here
  613. for (i = 0, wlen = 0; i < g_TextLib.nMsgs; i++)
  614. {
  615. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), NULL, 0) + 1;
  616. }
  617. g_TextLib.lpMsgBuf = (LPWSTR*)malloc(g_TextLib.nMsgs * sizeof(LPWSTR));
  618. if (g_TextLib.lpMsgBuf == NULL)
  619. {
  620. free(g_TextLib.lpWordBuf);
  621. free(offsets);
  622. return -1;
  623. }
  624. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  625. if (tmp == NULL)
  626. {
  627. free(g_TextLib.lpMsgBuf);
  628. free(g_TextLib.lpWordBuf);
  629. free(offsets);
  630. return -1;
  631. }
  632. for (i = 0, wpos = 0; i < g_TextLib.nMsgs; i++)
  633. {
  634. int l;
  635. g_TextLib.lpMsgBuf[i] = tmp + wpos;
  636. l = PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), g_TextLib.lpMsgBuf[i], wlen - wpos);
  637. g_TextLib.lpMsgBuf[i][l] = 0;
  638. wpos += l + 1;
  639. }
  640. free(temp);
  641. free(offsets);
  642. g_TextLib.lpIndexBuf = NULL;
  643. memcpy(g_TextLib.lpWordBuf + SYSMENU_LABEL_LAUNCHSETTING, gc_rgszSDLPalWords[gConfig.uCodePage], SDLPAL_EXTRA_WORD_COUNT * sizeof(LPCWSTR));
  644. #ifndef PAL_CLASSIC
  645. memcpy(g_TextLib.lpWordBuf + SYSMENU_LABEL_BATTLEMODE, gc_rgszAdditionalWords[gConfig.uCodePage], ATB_WORD_COUNT * sizeof(LPCWSTR));
  646. #endif
  647. }
  648. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  649. g_TextLib.bIcon = 0;
  650. g_TextLib.posIcon = 0;
  651. g_TextLib.nCurrentDialogLine = 0;
  652. g_TextLib.iDelayTime = 3;
  653. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  654. g_TextLib.posDialogText = PAL_XY(44, 26);
  655. g_TextLib.bDialogPosition = kDialogUpper;
  656. g_TextLib.fUserSkip = FALSE;
  657. PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA);
  658. return 0;
  659. }
  660. VOID
  661. PAL_FreeText(
  662. VOID
  663. )
  664. /*++
  665. Purpose:
  666. Free the memory used by the texts.
  667. Parameters:
  668. None.
  669. Return value:
  670. None.
  671. --*/
  672. {
  673. int i;
  674. if (g_TextLib.lpMsgBuf != NULL)
  675. {
  676. if (gConfig.pszMsgFile)
  677. for(i = 0; i < g_TextLib.nMsgs; i++) free(g_TextLib.lpMsgBuf[i]);
  678. else
  679. free(g_TextLib.lpMsgBuf[0]);
  680. free(g_TextLib.lpMsgBuf);
  681. g_TextLib.lpMsgBuf = NULL;
  682. }
  683. if (g_TextLib.lpWordBuf != NULL)
  684. {
  685. if (gConfig.pszMsgFile)
  686. for(i = 0; i < g_TextLib.nWords; i++) free(g_TextLib.lpWordBuf[i]);
  687. else
  688. free(g_TextLib.lpWordBuf[0]);
  689. free(g_TextLib.lpWordBuf);
  690. g_TextLib.lpWordBuf = NULL;
  691. }
  692. if (g_TextLib.lpIndexBuf != NULL)
  693. {
  694. if (gConfig.pszMsgFile)
  695. for(i = 0; i < g_TextLib.nIndices; i++) free(g_TextLib.lpIndexBuf[i]);
  696. else
  697. free(g_TextLib.lpIndexBuf[0]);
  698. free(g_TextLib.lpIndexBuf);
  699. g_TextLib.lpIndexBuf = NULL;
  700. }
  701. }
  702. LPCWSTR
  703. PAL_GetWord(
  704. int iNumWord
  705. )
  706. /*++
  707. Purpose:
  708. Get the specified word.
  709. Parameters:
  710. [IN] wNumWord - the number of the requested word.
  711. Return value:
  712. Pointer to the requested word. NULL if not found.
  713. --*/
  714. {
  715. return (iNumWord >= g_TextLib.nWords || !g_TextLib.lpWordBuf[iNumWord]) ? L"" : g_TextLib.lpWordBuf[iNumWord];
  716. }
  717. LPCWSTR
  718. PAL_GetMsg(
  719. int iNumMsg
  720. )
  721. /*++
  722. Purpose:
  723. Get the specified message.
  724. Parameters:
  725. [IN] wNumMsg - the number of the requested message.
  726. Return value:
  727. Pointer to the requested message. NULL if not found.
  728. --*/
  729. {
  730. return (iNumMsg >= g_TextLib.nMsgs || !g_TextLib.lpMsgBuf[iNumMsg]) ? L"" : g_TextLib.lpMsgBuf[iNumMsg];
  731. }
  732. int
  733. PAL_GetMsgNum(
  734. int iIndex,
  735. int iOrder
  736. )
  737. /*++
  738. Purpose:
  739. Get the number of specified message from index & order.
  740. Parameters:
  741. [IN] iMsgIndex - index.
  742. [IN] iOrder - order inside the index.
  743. Return value:
  744. The number of message. Zero means pausing for key, and -1 means end.
  745. --*/
  746. {
  747. return (iIndex >= g_TextLib.nMsgs || !g_TextLib.lpIndexBuf[iIndex]) ? -1 : g_TextLib.lpIndexBuf[iIndex][iOrder];
  748. }
  749. VOID
  750. PAL_DrawText(
  751. LPCWSTR lpszText,
  752. PAL_POS pos,
  753. BYTE bColor,
  754. BOOL fShadow,
  755. BOOL fUpdate,
  756. BOOL fUse8x8Font
  757. )
  758. /*++
  759. Purpose:
  760. Draw text on the screen.
  761. Parameters:
  762. [IN] lpszText - the text to be drawn.
  763. [IN] pos - Position of the text.
  764. [IN] bColor - Color of the text.
  765. [IN] fShadow - TRUE if the text is shadowed or not.
  766. [IN] fUpdate - TRUE if update the screen area.
  767. [IN] fUse8x8Font - TRUE if use 8x8 font.
  768. Return value:
  769. None.
  770. --*/
  771. {
  772. SDL_Rect rect, urect;
  773. urect.x = rect.x = PAL_X(pos);
  774. urect.y = rect.y = PAL_Y(pos);
  775. urect.h = (fUse8x8Font ? 8 : PAL_FontHeight()) + (fShadow ? 1 : 0);
  776. urect.w = 0;
  777. while (*lpszText)
  778. {
  779. //
  780. // Draw the character
  781. //
  782. int char_width = fUse8x8Font ? 8 : PAL_CharWidth(*lpszText);
  783. if (fShadow)
  784. {
  785. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0, fUse8x8Font);
  786. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0, fUse8x8Font);
  787. }
  788. PAL_DrawCharOnSurface(*lpszText++, gpScreen, PAL_XY(rect.x, rect.y), bColor, fUse8x8Font);
  789. rect.x += char_width; urect.w += char_width;
  790. }
  791. //
  792. // Update the screen area
  793. //
  794. if (fUpdate && urect.w > 0)
  795. {
  796. if (fShadow) urect.w++;
  797. if (urect.x + urect.w > 320)
  798. {
  799. urect.w = 320 - urect.x;
  800. }
  801. VIDEO_UpdateScreen(&urect);
  802. }
  803. }
  804. VOID
  805. PAL_DialogSetDelayTime(
  806. INT iDelayTime
  807. )
  808. /*++
  809. Purpose:
  810. Set the delay time for dialog.
  811. Parameters:
  812. [IN] iDelayTime - the delay time to be set.
  813. Return value:
  814. None.
  815. --*/
  816. {
  817. g_TextLib.iDelayTime = iDelayTime;
  818. }
  819. VOID
  820. PAL_StartDialog(
  821. BYTE bDialogLocation,
  822. BYTE bFontColor,
  823. INT iNumCharFace,
  824. BOOL fPlayingRNG
  825. )
  826. /*++
  827. Purpose:
  828. Start a new dialog.
  829. Parameters:
  830. [IN] bDialogLocation - the location of the text on the screen.
  831. [IN] bFontColor - the font color of the text.
  832. [IN] iNumCharFace - number of the character face in RGM.MKF.
  833. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  834. Return value:
  835. None.
  836. --*/
  837. {
  838. PAL_LARGE BYTE buf[16384];
  839. SDL_Rect rect;
  840. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  841. {
  842. //
  843. // Update the screen in battle, or the graphics may seem messed up
  844. //
  845. VIDEO_UpdateScreen(NULL);
  846. g_fUpdatedInBattle = TRUE;
  847. }
  848. g_TextLib.bIcon = 0;
  849. g_TextLib.posIcon = 0;
  850. g_TextLib.nCurrentDialogLine = 0;
  851. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  852. g_TextLib.fUserSkip = FALSE;
  853. if (bFontColor != 0)
  854. {
  855. g_TextLib.bCurrentFontColor = bFontColor;
  856. }
  857. if (fPlayingRNG && iNumCharFace)
  858. {
  859. VIDEO_BackupScreen();
  860. g_TextLib.fPlayingRNG = TRUE;
  861. }
  862. switch (bDialogLocation)
  863. {
  864. case kDialogUpper:
  865. if (iNumCharFace > 0)
  866. {
  867. //
  868. // Display the character face at the upper part of the screen
  869. //
  870. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  871. {
  872. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  873. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  874. rect.x = 48 - rect.w / 2;
  875. rect.y = 55 - rect.h / 2;
  876. if (rect.x < 0)
  877. {
  878. rect.x = 0;
  879. }
  880. if (rect.y < 0)
  881. {
  882. rect.y = 0;
  883. }
  884. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  885. if (rect.x < 0)
  886. {
  887. rect.x = 0;
  888. }
  889. if (rect.y < 0)
  890. {
  891. rect.y = 0;
  892. }
  893. VIDEO_UpdateScreen(&rect);
  894. }
  895. }
  896. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  897. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  898. break;
  899. case kDialogCenter:
  900. g_TextLib.posDialogText = PAL_XY(80, 40);
  901. break;
  902. case kDialogLower:
  903. if (iNumCharFace > 0)
  904. {
  905. //
  906. // Display the character face at the lower part of the screen
  907. //
  908. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  909. {
  910. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  911. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  912. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  913. VIDEO_UpdateScreen(NULL);
  914. }
  915. }
  916. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  917. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  918. break;
  919. case kDialogCenterWindow:
  920. g_TextLib.posDialogText = PAL_XY(160, 40);
  921. break;
  922. }
  923. g_TextLib.bDialogPosition = bDialogLocation;
  924. }
  925. static VOID
  926. PAL_DialogWaitForKey(
  927. VOID
  928. )
  929. /*++
  930. Purpose:
  931. Wait for player to press a key after showing a dialog.
  932. Parameters:
  933. None.
  934. Return value:
  935. None.
  936. --*/
  937. {
  938. PAL_LARGE SDL_Color palette[256];
  939. SDL_Color *pCurrentPalette, t;
  940. int i;
  941. //
  942. // get the current palette
  943. //
  944. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  945. memcpy(palette, pCurrentPalette, sizeof(palette));
  946. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  947. g_TextLib.bDialogPosition != kDialogCenter)
  948. {
  949. //
  950. // show the icon
  951. //
  952. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  953. if (p != NULL)
  954. {
  955. SDL_Rect rect;
  956. rect.x = PAL_X(g_TextLib.posIcon);
  957. rect.y = PAL_Y(g_TextLib.posIcon);
  958. rect.w = 16;
  959. rect.h = 16;
  960. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  961. VIDEO_UpdateScreen(&rect);
  962. }
  963. }
  964. PAL_ClearKeyState();
  965. while (TRUE)
  966. {
  967. UTIL_Delay(100);
  968. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  969. g_TextLib.bDialogPosition != kDialogCenter)
  970. {
  971. //
  972. // palette shift
  973. //
  974. t = palette[0xF9];
  975. for (i = 0xF9; i < 0xFE; i++)
  976. {
  977. palette[i] = palette[i + 1];
  978. }
  979. palette[0xFE] = t;
  980. VIDEO_SetPalette(palette);
  981. }
  982. if (g_InputState.dwKeyPress != 0)
  983. {
  984. break;
  985. }
  986. }
  987. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  988. g_TextLib.bDialogPosition != kDialogCenter)
  989. {
  990. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  991. }
  992. PAL_ClearKeyState();
  993. g_TextLib.fUserSkip = FALSE;
  994. }
  995. VOID
  996. PAL_ShowDialogText(
  997. LPCWSTR lpszText
  998. )
  999. /*++
  1000. Purpose:
  1001. Show one line of the dialog text.
  1002. Parameters:
  1003. [IN] lpszText - the text to be shown.
  1004. Return value:
  1005. None.
  1006. --*/
  1007. {
  1008. SDL_Rect rect;
  1009. int x, y;
  1010. PAL_ClearKeyState();
  1011. g_TextLib.bIcon = 0;
  1012. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  1013. {
  1014. //
  1015. // Update the screen in battle, or the graphics may seem messed up
  1016. //
  1017. VIDEO_UpdateScreen(NULL);
  1018. g_fUpdatedInBattle = TRUE;
  1019. }
  1020. if (g_TextLib.nCurrentDialogLine > 3)
  1021. {
  1022. //
  1023. // The rest dialogs should be shown in the next page.
  1024. //
  1025. PAL_DialogWaitForKey();
  1026. g_TextLib.nCurrentDialogLine = 0;
  1027. VIDEO_RestoreScreen();
  1028. VIDEO_UpdateScreen(NULL);
  1029. }
  1030. x = PAL_X(g_TextLib.posDialogText);
  1031. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  1032. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  1033. {
  1034. //
  1035. // The text should be shown in a small window at the center of the screen
  1036. //
  1037. #ifndef PAL_CLASSIC
  1038. if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  1039. {
  1040. PAL_BattleUIShowText(lpszText, 1400);
  1041. }
  1042. else
  1043. #endif
  1044. {
  1045. PAL_POS pos;
  1046. LPBOX lpBox;
  1047. int i, w = wcslen(lpszText), len = 0;
  1048. for (i = 0; i < w; i++)
  1049. len += PAL_CharWidth(lpszText[i]) >> 3;
  1050. //
  1051. // Create the window box
  1052. //
  1053. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  1054. // Follow behavior of original version
  1055. lpBox = PAL_CreateSingleLineBoxWithShadow(pos, (len + 1) / 2, FALSE, 0);
  1056. rect.x = PAL_X(pos);
  1057. rect.y = PAL_Y(pos);
  1058. rect.w = 320 - rect.x * 2 + 32;
  1059. rect.h = 64;
  1060. //
  1061. // Show the text on the screen
  1062. //
  1063. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  1064. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE, FALSE);
  1065. VIDEO_UpdateScreen(&rect);
  1066. PAL_DialogWaitForKey();
  1067. //
  1068. // Delete the box
  1069. //
  1070. PAL_DeleteBox(lpBox);
  1071. VIDEO_UpdateScreen(&rect);
  1072. PAL_EndDialog();
  1073. }
  1074. }
  1075. else
  1076. {
  1077. int len = wcslen(lpszText);
  1078. if (g_TextLib.nCurrentDialogLine == 0 &&
  1079. g_TextLib.bDialogPosition != kDialogCenter &&
  1080. (lpszText[len - 1] == 0xff1a ||
  1081. lpszText[len - 1] == 0x2236 || // Special case for Pal WIN95 Simplified Chinese version
  1082. lpszText[len - 1] == ':')
  1083. )
  1084. {
  1085. //
  1086. // name of character
  1087. //
  1088. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE, FALSE);
  1089. }
  1090. else
  1091. {
  1092. //
  1093. // normal texts
  1094. //
  1095. WCHAR text[2];
  1096. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  1097. {
  1098. //
  1099. // Save the screen before we show the first line of dialog
  1100. //
  1101. VIDEO_BackupScreen();
  1102. }
  1103. while (lpszText != NULL && *lpszText != '\0')
  1104. {
  1105. switch (*lpszText)
  1106. {
  1107. case '-':
  1108. //
  1109. // Set the font color to Cyan
  1110. //
  1111. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  1112. {
  1113. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1114. }
  1115. else
  1116. {
  1117. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  1118. }
  1119. lpszText++;
  1120. break;
  1121. #if 0
  1122. /* Not used */
  1123. case '\'':
  1124. //
  1125. // Set the font color to Red
  1126. //
  1127. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  1128. {
  1129. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1130. }
  1131. else
  1132. {
  1133. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  1134. }
  1135. lpszText++;
  1136. break;
  1137. #endif
  1138. case '\"':
  1139. //
  1140. // Set the font color to Yellow
  1141. //
  1142. if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW)
  1143. {
  1144. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1145. }
  1146. else
  1147. {
  1148. g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW;
  1149. }
  1150. lpszText++;
  1151. break;
  1152. case '$':
  1153. //
  1154. // Set the delay time of text-displaying
  1155. //
  1156. g_TextLib.iDelayTime = wcstol(lpszText + 1, NULL, 10) * 10 / 7;
  1157. lpszText += 3;
  1158. break;
  1159. case '~':
  1160. //
  1161. // Delay for a period and quit
  1162. //
  1163. UTIL_Delay(wcstol(lpszText + 1, NULL, 10) * 80 / 7);
  1164. g_TextLib.nCurrentDialogLine = 0;
  1165. g_TextLib.fUserSkip = FALSE;
  1166. return; // don't go further
  1167. case ')':
  1168. //
  1169. // Set the waiting icon
  1170. //
  1171. g_TextLib.bIcon = 1;
  1172. lpszText++;
  1173. break;
  1174. case '(':
  1175. //
  1176. // Set the waiting icon
  1177. //
  1178. g_TextLib.bIcon = 2;
  1179. lpszText++;
  1180. break;
  1181. case '\\':
  1182. lpszText++;
  1183. default:
  1184. text[0] = *lpszText++;
  1185. text[1] = 0;
  1186. PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE, FALSE);
  1187. x += PAL_CharWidth(text[0]);
  1188. if (!g_TextLib.fUserSkip)
  1189. {
  1190. PAL_ClearKeyState();
  1191. UTIL_Delay(g_TextLib.iDelayTime * 8);
  1192. if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu))
  1193. {
  1194. //
  1195. // User pressed a key to skip the dialog
  1196. //
  1197. g_TextLib.fUserSkip = TRUE;
  1198. }
  1199. }
  1200. }
  1201. }
  1202. g_TextLib.posIcon = PAL_XY(x, y);
  1203. g_TextLib.nCurrentDialogLine++;
  1204. }
  1205. }
  1206. }
  1207. VOID
  1208. PAL_ClearDialog(
  1209. BOOL fWaitForKey
  1210. )
  1211. /*++
  1212. Purpose:
  1213. Clear the state of the dialog.
  1214. Parameters:
  1215. [IN] fWaitForKey - whether wait for any key or not.
  1216. Return value:
  1217. None.
  1218. --*/
  1219. {
  1220. if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey)
  1221. {
  1222. PAL_DialogWaitForKey();
  1223. }
  1224. g_TextLib.nCurrentDialogLine = 0;
  1225. if (g_TextLib.bDialogPosition == kDialogCenter)
  1226. {
  1227. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1228. g_TextLib.posDialogText = PAL_XY(44, 26);
  1229. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1230. g_TextLib.bDialogPosition = kDialogUpper;
  1231. }
  1232. }
  1233. VOID
  1234. PAL_EndDialog(
  1235. VOID
  1236. )
  1237. /*++
  1238. Purpose:
  1239. Ends a dialog.
  1240. Parameters:
  1241. None.
  1242. Return value:
  1243. None.
  1244. --*/
  1245. {
  1246. PAL_ClearDialog(TRUE);
  1247. //
  1248. // Set some default parameters, as there are some parts of script
  1249. // which doesn't have a "start dialog" instruction before showing the dialog.
  1250. //
  1251. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1252. g_TextLib.posDialogText = PAL_XY(44, 26);
  1253. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1254. g_TextLib.bDialogPosition = kDialogUpper;
  1255. g_TextLib.fUserSkip = FALSE;
  1256. g_TextLib.fPlayingRNG = FALSE;
  1257. }
  1258. BOOL
  1259. PAL_IsInDialog(
  1260. VOID
  1261. )
  1262. /*++
  1263. Purpose:
  1264. Check if there are dialog texts on the screen.
  1265. Parameters:
  1266. None.
  1267. Return value:
  1268. TRUE if there are dialog texts on the screen, FALSE if not.
  1269. --*/
  1270. {
  1271. return (g_TextLib.nCurrentDialogLine != 0);
  1272. }
  1273. BOOL
  1274. PAL_DialogIsPlayingRNG(
  1275. VOID
  1276. )
  1277. /*++
  1278. Purpose:
  1279. Check if the script used the RNG playing parameter when displaying texts.
  1280. Parameters:
  1281. None.
  1282. Return value:
  1283. TRUE if the script used the RNG playing parameter, FALSE if not.
  1284. --*/
  1285. {
  1286. return g_TextLib.fPlayingRNG;
  1287. }
  1288. INT
  1289. PAL_MultiByteToWideCharCP(
  1290. CODEPAGE cp,
  1291. LPCSTR mbs,
  1292. int mbslength,
  1293. LPWSTR wcs,
  1294. int wcslength
  1295. )
  1296. /*++
  1297. Purpose:
  1298. Convert multi-byte string into the corresponding unicode string.
  1299. Parameters:
  1300. [IN] cp - Code page for conversion.
  1301. [IN] mbs - Pointer to the multi-byte string.
  1302. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1303. [IN] wcs - Pointer to the wide string buffer.
  1304. [IN] wcslength - Length of the wide string buffer.
  1305. Return value:
  1306. The length of converted wide string. If mbslength is set to -1, the returned
  1307. value includes the terminal null-char; otherwise, the null-char is not included.
  1308. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1309. required length of the wide string buffer.
  1310. --*/
  1311. {
  1312. int i = 0, state = 0, wlen = 0, null = 0;
  1313. if (mbslength == -1)
  1314. {
  1315. mbslength = strlen(mbs);
  1316. null = 1;
  1317. }
  1318. if (!wcs)
  1319. {
  1320. switch (cp)
  1321. {
  1322. //case CP_SHIFTJIS:
  1323. // for (i = 0; i < mbslength && mbs[i]; i++)
  1324. // {
  1325. // if (state == 0)
  1326. // {
  1327. // if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] >= 0xfd || ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf))
  1328. // wlen++;
  1329. // else
  1330. // state = 1;
  1331. // }
  1332. // else
  1333. // {
  1334. // wlen++;
  1335. // state = 0;
  1336. // }
  1337. // }
  1338. // break;
  1339. case CP_GBK:
  1340. case CP_BIG5:
  1341. for (i = 0; i < mbslength && mbs[i]; i++)
  1342. {
  1343. if (state == 0)
  1344. {
  1345. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] == 0xff)
  1346. wlen++;
  1347. else
  1348. state = 1;
  1349. }
  1350. else
  1351. {
  1352. wlen++;
  1353. state = 0;
  1354. }
  1355. }
  1356. break;
  1357. case CP_UTF_8:
  1358. for (i = 0; i < mbslength && mbs[i]; i++)
  1359. {
  1360. if (state == 0)
  1361. {
  1362. if ((BYTE)mbs[i] >= 0x80)
  1363. {
  1364. BYTE s = (BYTE)mbs[i] << 1;
  1365. while (s >= 0x80) { state++; s <<= 1; }
  1366. if (state < 1 || state > 3)
  1367. {
  1368. state = 0;
  1369. wlen++;
  1370. }
  1371. }
  1372. else
  1373. wlen++;
  1374. }
  1375. else
  1376. {
  1377. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1378. {
  1379. if (--state == 0) wlen++;
  1380. }
  1381. else
  1382. {
  1383. state = 0; wlen++;
  1384. }
  1385. }
  1386. }
  1387. break;
  1388. default:
  1389. return -1;
  1390. }
  1391. if (i < mbslength && !mbs[i]) null = 1;
  1392. return wlen + null + (state != 0);
  1393. }
  1394. else
  1395. {
  1396. WCHAR invalid_char;
  1397. switch (cp)
  1398. {
  1399. //case CP_SHIFTJIS:
  1400. // invalid_char = 0x30fb;
  1401. // for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1402. // {
  1403. // if (state == 0)
  1404. // {
  1405. // if ((BYTE)mbs[i] <= 0x80)
  1406. // wcs[wlen++] = mbs[i];
  1407. // else if ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf)
  1408. // wcs[wlen++] = cptbl_jis_half[(BYTE)mbs[i] - 0xa0];
  1409. // else if ((BYTE)mbs[i] == 0xfd)
  1410. // wcs[wlen++] = 0xf8f1;
  1411. // else if ((BYTE)mbs[i] == 0xfe)
  1412. // wcs[wlen++] = 0xf8f2;
  1413. // else if ((BYTE)mbs[i] == 0xff)
  1414. // wcs[wlen++] = 0xf8f3;
  1415. // else
  1416. // state = 1;
  1417. // }
  1418. // else
  1419. // {
  1420. // if ((BYTE)mbs[i] < 0x40)
  1421. // wcs[wlen++] = 0x30fb;
  1422. // else if ((BYTE)mbs[i - 1] < 0xa0)
  1423. // wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1424. // else
  1425. // wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0xc1][(BYTE)mbs[i] - 0x40];
  1426. // state = 0;
  1427. // }
  1428. // }
  1429. // break;
  1430. case CP_GBK:
  1431. invalid_char = 0x3f;
  1432. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1433. {
  1434. if (state == 0)
  1435. {
  1436. if ((BYTE)mbs[i] < 0x80)
  1437. wcs[wlen++] = mbs[i];
  1438. else if ((BYTE)mbs[i] == 0x80)
  1439. wcs[wlen++] = 0x20ac;
  1440. else if ((BYTE)mbs[i] == 0xff)
  1441. wcs[wlen++] = 0xf8f5;
  1442. else
  1443. state = 1;
  1444. }
  1445. else
  1446. {
  1447. if ((BYTE)mbs[i] < 0x40)
  1448. wcs[wlen++] = invalid_char;
  1449. else
  1450. wcs[wlen++] = cptbl_gbk[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1451. state = 0;
  1452. }
  1453. }
  1454. break;
  1455. case CP_BIG5:
  1456. invalid_char = 0x3f;
  1457. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1458. {
  1459. if (state == 0)
  1460. {
  1461. if ((BYTE)mbs[i] <= 0x80)
  1462. wcs[wlen++] = mbs[i];
  1463. else if ((BYTE)mbs[i] == 0xff)
  1464. wcs[wlen++] = 0xf8f8;
  1465. else
  1466. state = 1;
  1467. }
  1468. else
  1469. {
  1470. if ((BYTE)mbs[i] < 0x40 || ((BYTE)mbs[i] >= 0x7f && (BYTE)mbs[i] <= 0xa0))
  1471. wcs[wlen++] = invalid_char;
  1472. else if ((BYTE)mbs[i] <= 0x7e)
  1473. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1474. else
  1475. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x60];
  1476. state = 0;
  1477. }
  1478. }
  1479. break;
  1480. case CP_UTF_8:
  1481. invalid_char = 0x3f;
  1482. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1483. {
  1484. if (state == 0)
  1485. {
  1486. if ((BYTE)mbs[i] >= 0x80)
  1487. {
  1488. BYTE s = (BYTE)mbs[i] << 1;
  1489. while (s >= 0x80) { state++; s <<= 1; }
  1490. if (state < 1 || state > 3)
  1491. {
  1492. state = 0;
  1493. wcs[wlen++] = invalid_char;
  1494. }
  1495. else
  1496. {
  1497. wcs[wlen] = s >> (state + 1);
  1498. }
  1499. }
  1500. else
  1501. wcs[wlen++] = mbs[i];
  1502. }
  1503. else
  1504. {
  1505. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1506. {
  1507. wcs[wlen] <<= 6;
  1508. wcs[wlen] |= (BYTE)mbs[i] & 0x3f;
  1509. if (--state == 0) wlen++;
  1510. }
  1511. else
  1512. {
  1513. state = 0;
  1514. wcs[wlen++] = invalid_char;
  1515. }
  1516. }
  1517. }
  1518. break;
  1519. default:
  1520. return -1;
  1521. }
  1522. if (state != 0 && wlen < wcslength)
  1523. {
  1524. wcs[wlen++] = invalid_char;
  1525. }
  1526. if (null || (i < mbslength && !mbs[i]))
  1527. {
  1528. if (wlen < wcslength)
  1529. wcs[wlen++] = 0;
  1530. else
  1531. wcs[wlen - 1] = 0;
  1532. }
  1533. return wlen;
  1534. }
  1535. }
  1536. INT
  1537. PAL_MultiByteToWideChar(
  1538. LPCSTR mbs,
  1539. int mbslength,
  1540. LPWSTR wcs,
  1541. int wcslength
  1542. )
  1543. /*++
  1544. Purpose:
  1545. Convert multi-byte string into the corresponding unicode string.
  1546. Parameters:
  1547. [IN] mbs - Pointer to the multi-byte string.
  1548. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1549. [IN] wcs - Pointer to the wide string buffer.
  1550. [IN] wcslength - Length of the wide string buffer.
  1551. Return value:
  1552. The length of converted wide string. If mbslength is set to -1, the returned
  1553. value includes the terminal null-char; otherwise, the null-char is not included.
  1554. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1555. required length of the wide string buffer.
  1556. --*/
  1557. {
  1558. return PAL_MultiByteToWideCharCP(gConfig.uCodePage, mbs, mbslength, wcs, wcslength);
  1559. }
  1560. INT
  1561. PAL_swprintf(
  1562. LPWSTR buffer,
  1563. size_t count,
  1564. LPCWSTR format,
  1565. ...
  1566. )
  1567. /*++
  1568. Purpose:
  1569. Formatted wide-character output conversion that output Chinese characters correctly.
  1570. This function supported a subset of format strings that are commonly supported by
  1571. various C libraries, which can be formalized as following:
  1572. %[flags] [width] [.precision] [{h | l | ll}] type
  1573. When handling '%c' and '%s', this function follows the Linux's library convention,
  1574. which means '%c' and '%s' always output multi-byte strings, and '%lc' and '%ls'
  1575. always output wide-char strings.
  1576. Parameters:
  1577. [IN] buffer - Storage location for output.
  1578. [IN] count - Length of the output buffer in characters including the termination null one.
  1579. [IN] format - Format-control string.
  1580. [IN] ... - Optional arguments.
  1581. Return value:
  1582. The length of outputed wide string, not including the termination null character.
  1583. --*/
  1584. {
  1585. va_list ap;
  1586. const WCHAR * const format_end = format + wcslen(format);
  1587. const WCHAR * const buffer_end = buffer + count - 1;
  1588. WCHAR chr_buf[2] = { 0, 0 };
  1589. LPCWSTR fmt_start = NULL;
  1590. LPWSTR cur_fmt = NULL;
  1591. size_t fmt_len = 0;
  1592. int precision, width;
  1593. int state, left_aligned, wide, narrow, width_var, precision_var, precision_defined;
  1594. // Buffer & length check
  1595. if (buffer == NULL || format == NULL)
  1596. {
  1597. errno = EINVAL;
  1598. return -1;
  1599. }
  1600. if (buffer_end <= buffer)
  1601. return 0;
  1602. va_start(ap, format);
  1603. count = 0; state = 0;
  1604. while (buffer < buffer_end && format < format_end)
  1605. {
  1606. switch (state)
  1607. {
  1608. case 0: // Outside format spec
  1609. if (*format != L'%')
  1610. {
  1611. *buffer++ = *format++;
  1612. count++;
  1613. }
  1614. else
  1615. {
  1616. fmt_start = format++;
  1617. left_aligned = wide = narrow = 0;
  1618. precision_var = width_var = 0;
  1619. precision_defined = 0;
  1620. state = 1;
  1621. }
  1622. continue;
  1623. case 1: // [flags]
  1624. switch (*format)
  1625. {
  1626. case L'-':
  1627. left_aligned = 1;
  1628. case L'+':
  1629. case L' ':
  1630. case L'#':
  1631. case L'0':
  1632. format++;
  1633. continue;
  1634. default:
  1635. state = 2;
  1636. width = width_var = 0;
  1637. }
  1638. case 2: // [width]
  1639. switch (*format)
  1640. {
  1641. case '0':
  1642. case '1':
  1643. case '2':
  1644. case '3':
  1645. case '4':
  1646. case '5':
  1647. case '6':
  1648. case '7':
  1649. case '8':
  1650. case '9':
  1651. if (width >= 0)
  1652. width = width * 10 + (*format - L'0');
  1653. format++;
  1654. continue;
  1655. case '*':
  1656. if (width == 0)
  1657. width_var = 1;
  1658. format++;
  1659. continue;
  1660. case '.':
  1661. format++;
  1662. precision = precision_var = 0;
  1663. precision_defined = 1;
  1664. state = 3;
  1665. continue;
  1666. default:
  1667. state = 4;
  1668. continue;
  1669. }
  1670. case 3: // [.precision]
  1671. switch (*format)
  1672. {
  1673. case '0':
  1674. case '1':
  1675. case '2':
  1676. case '3':
  1677. case '4':
  1678. case '5':
  1679. case '6':
  1680. case '7':
  1681. case '8':
  1682. case '9':
  1683. if (precision >= 0)
  1684. precision = precision * 10 + (*format - L'0');
  1685. format++;
  1686. continue;
  1687. case '*':
  1688. if (precision == 0)
  1689. precision_var = 1;
  1690. format++;
  1691. continue;
  1692. default:
  1693. state = 4;
  1694. }
  1695. case 4: // [{h | l | ll}]
  1696. switch (*format)
  1697. {
  1698. case 'l': if (narrow == 0) wide++; format++; continue;
  1699. case 'h': if (wide == 0) narrow++; format++; continue;
  1700. default: state = 5;
  1701. }
  1702. case 5: // type
  1703. if (*format == 'c' || *format == 's')
  1704. {
  1705. // We handle char & str specially
  1706. LPWSTR buf;
  1707. size_t len;
  1708. int i;
  1709. // Check width
  1710. if (width_var)
  1711. {
  1712. width = va_arg(ap, int);
  1713. left_aligned = (width < 0);
  1714. width = left_aligned ? -width : width;
  1715. }
  1716. // Although precision has no meaning to '%c' output, however
  1717. // the argument still needs to be read if '.*' is provided
  1718. if (precision_var)
  1719. precision = va_arg(ap, int);
  1720. else if (!precision_defined)
  1721. precision = INT_MAX;
  1722. if (*format == 's')
  1723. {
  1724. // For ANSI string, convert it through PAL_MultiByteToWideChar
  1725. // To improve effciency, here just test the length and left
  1726. // actual conversion later directly into the output buffer
  1727. if (wide)
  1728. {
  1729. buf = va_arg(ap, LPWSTR);
  1730. len = wcslen(buf);
  1731. }
  1732. else
  1733. {
  1734. buf = (LPWSTR)va_arg(ap, LPSTR);
  1735. len = PAL_MultiByteToWideChar((LPCSTR)buf, -1, NULL, 0) - 1;
  1736. }
  1737. }
  1738. else
  1739. {
  1740. // For ANSI character, put it into the internal buffer
  1741. if (wide)
  1742. chr_buf[0] = va_arg(ap, WCHAR);
  1743. else
  1744. chr_buf[0] = va_arg(ap, int);
  1745. buf = chr_buf; len = 1;
  1746. }
  1747. // Limit output length no longer then precision
  1748. if (precision > (int)len)
  1749. precision = len;
  1750. // Left-side padding
  1751. for (i = 0; !left_aligned && i < width - precision && buffer < buffer_end; i++)
  1752. *buffer++ = L' ', count++;
  1753. // Do not overflow the output buffer
  1754. if (buffer + precision > buffer_end)
  1755. precision = buffer_end - buffer;
  1756. // Convert or copy string (char) into output buffer
  1757. if (*format == 's' && !wide)
  1758. PAL_MultiByteToWideChar((LPCSTR)buf, -1, buffer, precision);
  1759. else
  1760. wcsncpy(buffer, buf, precision);
  1761. buffer += precision; count += precision;
  1762. // Right-side padding
  1763. for (i = 0; left_aligned && i < width - precision && buffer < buffer_end; i++)
  1764. *buffer++ = L' ', count++;
  1765. }
  1766. else
  1767. {
  1768. // For other types, pass them directly into vswprintf
  1769. int cur_cnt = 0;
  1770. va_list apd;
  1771. // We copy this argument's format string into internal buffer
  1772. if (fmt_len < (size_t)(format - fmt_start + 1))
  1773. cur_fmt = realloc(cur_fmt, ((fmt_len = format - fmt_start + 1) + 1) * sizeof(WCHAR));
  1774. wcsncpy(cur_fmt, fmt_start, fmt_len);
  1775. cur_fmt[fmt_len] = L'\0';
  1776. // And pass it into vswprintf to get the output
  1777. va_copy(apd, ap);
  1778. cur_cnt = vswprintf(buffer, buffer_end - buffer, cur_fmt, apd);
  1779. va_end(apd);
  1780. buffer += cur_cnt; count += cur_cnt;
  1781. // Then we need to move the argument pointer into next one
  1782. // Check if width/precision should be read from arguments
  1783. if (width_var) va_arg(ap, int);
  1784. if (precision_var) va_arg(ap, int);
  1785. // Move pointer to pass the actual value argument
  1786. switch (*format)
  1787. {
  1788. case 'd':
  1789. case 'i':
  1790. case 'o':
  1791. case 'u':
  1792. case 'x':
  1793. case 'X':
  1794. if (wide == 1)
  1795. va_arg(ap, long);
  1796. else if (wide >= 2)
  1797. va_arg(ap, long long);
  1798. else
  1799. va_arg(ap, int);
  1800. break;
  1801. case 'e':
  1802. case 'E':
  1803. case 'f':
  1804. case 'g':
  1805. case 'G':
  1806. case 'a':
  1807. case 'A':
  1808. va_arg(ap, double);
  1809. break;
  1810. case 'p':
  1811. case 'n':
  1812. va_arg(ap, void*);
  1813. break;
  1814. }
  1815. }
  1816. state = 0;
  1817. format++;
  1818. break;
  1819. }
  1820. }
  1821. // If the format string is malformed, try to copy it into the dest buffer
  1822. if (state && buffer < buffer_end)
  1823. {
  1824. int fmt_len = format - fmt_start;
  1825. int buf_len = buffer_end - buffer;
  1826. if (fmt_len <= buf_len)
  1827. {
  1828. wcsncpy(buffer, fmt_start, buf_len);
  1829. buffer += fmt_len;
  1830. }
  1831. else
  1832. {
  1833. wcsncpy(buffer, fmt_start, buf_len);
  1834. buffer += buf_len;
  1835. }
  1836. }
  1837. // NULL-terminate the string
  1838. *buffer = L'\0';
  1839. va_end(ap);
  1840. return count;
  1841. }
  1842. WCHAR
  1843. PAL_GetInvalidChar(
  1844. CODEPAGE uCodePage
  1845. )
  1846. {
  1847. switch(uCodePage)
  1848. {
  1849. case CP_BIG5: return 0x3f;
  1850. case CP_GBK: return 0x3f;
  1851. //case CP_SHIFTJIS: return 0x30fb;
  1852. case CP_UTF_8: return 0x3f;
  1853. default: return 0;
  1854. }
  1855. }