text.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625
  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. #define FONT_COLOR_DEFAULT 0x4F
  28. #define FONT_COLOR_YELLOW 0x2D
  29. #define FONT_COLOR_RED 0x1A
  30. #define FONT_COLOR_CYAN 0x8D
  31. #define FONT_COLOR_CYAN_ALT 0x8C
  32. BOOL g_fUpdatedInBattle = FALSE;
  33. #define MESSAGE_MAX_BUFFER_SIZE 512
  34. #define INCLUDE_CODEPAGE_H
  35. #include "codepage.h"
  36. #ifndef PAL_CLASSIC
  37. static const WCHAR* gc_rgszAdditionalWords[CP_MAX][6] = {
  38. { L"\x6230\x9B25\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  39. { L"\x6218\x6597\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  40. { L"\x6226\x95D8\x901F\x5EA6", L"\x4E00", L"\x4E8C", L"\x4E09", L"\x56DB", L"\x4E94" },
  41. };
  42. static const WCHAR** g_rgszAdditionalWords;
  43. #endif
  44. typedef struct tagTEXTLIB
  45. {
  46. LPWSTR *lpWordBuf;
  47. LPWSTR *lpMsgBuf;
  48. int **lpIndexBuf;
  49. int nWords;
  50. int nMsgs;
  51. int nIndices;
  52. int nCurrentDialogLine;
  53. BYTE bCurrentFontColor;
  54. PAL_POS posIcon;
  55. PAL_POS posDialogTitle;
  56. PAL_POS posDialogText;
  57. BYTE bDialogPosition;
  58. BYTE bIcon;
  59. int iDelayTime;
  60. BOOL fUserSkip;
  61. BOOL fPlayingRNG;
  62. BYTE bufDialogIcons[282];
  63. } TEXTLIB, *LPTEXTLIB;
  64. static TEXTLIB g_TextLib;
  65. PAL_FORCE_INLINE int
  66. PAL_ParseLine(
  67. char *line,
  68. char **value,
  69. int *length
  70. )
  71. {
  72. //
  73. // Remove the leading spaces
  74. //
  75. while (*line && iswspace(*line)) line++;
  76. //
  77. // Skip comments starting with '#'
  78. //
  79. if (*line && *line != '#')
  80. {
  81. //
  82. // Split the index and value
  83. //
  84. LPSTR val = strchr(line, '=');
  85. if (val)
  86. {
  87. //
  88. // Remove the trailing spaces
  89. //
  90. LPSTR end = line + strlen(line);
  91. int index;
  92. if (end > line && end[-1] == '\n') *(--end) = 0;
  93. while (end > line && iswspace(end[-1])) *(--end) = 0;
  94. //
  95. // Parse the index and pass out value
  96. //
  97. if (sscanf(line, "%d", &index) == 1)
  98. {
  99. *value = val + 1;
  100. *length = end - *value;
  101. return index;
  102. }
  103. }
  104. }
  105. return 0;
  106. }
  107. PAL_FORCE_INLINE char *
  108. PAL_CheckLongLine(
  109. FILE *fp,
  110. char *temp
  111. )
  112. {
  113. int n = strlen(temp);
  114. if (n == MESSAGE_MAX_BUFFER_SIZE - 1 && temp[n - 1] != '\n' && !feof(fp))
  115. {
  116. // Line too long, try to read it as a whole
  117. int nn = 2;
  118. char *tmp = strdup(temp);
  119. while (!feof(fp))
  120. {
  121. if (!(tmp = (char *)realloc(tmp, nn * MESSAGE_MAX_BUFFER_SIZE)))
  122. {
  123. TerminateOnError("PAL_ReadFileAndSplitLine(): failed to allocate memory for long line!");
  124. }
  125. if (fgets(tmp + n, MESSAGE_MAX_BUFFER_SIZE + 1, fp))
  126. {
  127. n += strlen(tmp + n);
  128. if (n < MESSAGE_MAX_BUFFER_SIZE - 1 || temp[n - 1] == '\n')
  129. break;
  130. else
  131. nn++;
  132. }
  133. }
  134. return tmp;
  135. }
  136. else
  137. return temp;
  138. }
  139. static int
  140. PAL_ReadFileAndSplitLine(
  141. FILE *fp,
  142. LPWSTR **buffer
  143. )
  144. {
  145. char temp[MESSAGE_MAX_BUFFER_SIZE];
  146. struct _list_entry_1
  147. {
  148. struct _list_entry_1 *next;
  149. wchar_t *value;
  150. int length;
  151. int index;
  152. } *head = NULL, *item;
  153. int max = 0;
  154. while (!feof(fp))
  155. {
  156. if (fgets(temp, MESSAGE_MAX_BUFFER_SIZE, fp))
  157. {
  158. //
  159. // Read one line and parse it
  160. //
  161. char *buffer = PAL_CheckLongLine(fp, temp), *v;
  162. int l, n = PAL_ParseLine(buffer, &v, &l);
  163. if (n > 0)
  164. {
  165. //
  166. // First save values (converted wide string) into a linked list
  167. //
  168. if (head)
  169. {
  170. item->next = (struct _list_entry_1 *)malloc(sizeof(struct _list_entry_1));
  171. item = item->next;
  172. }
  173. else
  174. item = head = (struct _list_entry_1 *)malloc(sizeof(struct _list_entry_1));
  175. item->length = PAL_MultiByteToWideCharCP(CP_UTF_8, v, l, NULL, 0);
  176. item->value = (LPWSTR)malloc((item->length + 1) * sizeof(WCHAR));
  177. PAL_MultiByteToWideCharCP(CP_UTF_8, v, l + 1, item->value, item->length + 1);
  178. item->index = (max < n) ? (max = n) : n; item->next = NULL;
  179. }
  180. if (buffer != temp) free(buffer);
  181. }
  182. }
  183. if (max > 0)
  184. {
  185. //
  186. // Move values from linked list to array
  187. //
  188. LPWSTR *array = (LPWSTR *)calloc(max += 1, sizeof(LPWSTR));
  189. for (item = head; item; )
  190. {
  191. struct _list_entry_1 *temp = item->next;
  192. array[item->index] = item->value;
  193. free(item); item = temp;
  194. }
  195. *buffer = array;
  196. }
  197. fclose(fp);
  198. return max > 0 ? max : -1;
  199. }
  200. static int
  201. PAL_ReadIndexFile(
  202. FILE *fp,
  203. int ***buffer
  204. )
  205. {
  206. char temp[MESSAGE_MAX_BUFFER_SIZE];
  207. struct _index_entry
  208. {
  209. struct _index_entry *next;
  210. int value;
  211. };
  212. struct _list_entry_2
  213. {
  214. struct _list_entry_2 *next;
  215. struct _index_entry *value;
  216. int length;
  217. int index;
  218. } *head = NULL, *item;
  219. int max = 0;
  220. while (!feof(fp))
  221. {
  222. if (fgets(temp, MESSAGE_MAX_BUFFER_SIZE, fp))
  223. {
  224. //
  225. // Read one line and parse it
  226. //
  227. char *buffer = PAL_CheckLongLine(fp, temp), *v, *e;
  228. int l, n = PAL_ParseLine(buffer, &v, &l), i;
  229. if (n >= 0)
  230. {
  231. //
  232. // First save values into a linked list
  233. //
  234. struct _index_entry *j;
  235. if (head)
  236. {
  237. item->next = (struct _list_entry_2 *)malloc(sizeof(struct _list_entry_2));
  238. item = item->next;
  239. }
  240. else
  241. item = head = (struct _list_entry_2 *)malloc(sizeof(struct _list_entry_2));
  242. item->index = (max < n) ? (max = n) : n;
  243. item->value = NULL; item->next = NULL;
  244. item->length = 0;
  245. while (*v && (i = strtol(v, &e, 10)) >= 0)
  246. {
  247. //
  248. // Each message index is also first stored into a linked list
  249. //
  250. if (e > v)
  251. {
  252. if (item->value)
  253. {
  254. j->next = (struct _index_entry *)malloc(sizeof(struct _index_entry));
  255. j = j->next;
  256. }
  257. else
  258. j = item->value = (struct _index_entry *)malloc(sizeof(struct _index_entry));
  259. j->value = i; item->length++;
  260. }
  261. v = e + 1;
  262. }
  263. j->next = (struct _index_entry *)malloc(sizeof(struct _index_entry));
  264. j->next->value = -1; j->next->next = NULL; item->length++;
  265. }
  266. if (buffer != temp) free(buffer);
  267. }
  268. }
  269. if (max > 0)
  270. {
  271. //
  272. // Move values from linked lists to arrays
  273. //
  274. int **array = (int **)calloc(max += 1, sizeof(int *));
  275. for (item = head; item; )
  276. {
  277. struct _index_entry *j = item->value;
  278. struct _list_entry_2 *temp = item->next;
  279. int i = 0;
  280. array[item->index] = (int *)malloc(item->length * sizeof(int));
  281. while (j)
  282. {
  283. struct _index_entry *t = j->next;
  284. array[item->index][i++] = j->value;
  285. free(j); j = t;
  286. }
  287. free(item); item = temp;
  288. }
  289. *buffer = array;
  290. }
  291. fclose(fp);
  292. return max > 0 ? max : -1;
  293. }
  294. INT
  295. PAL_InitText(
  296. VOID
  297. )
  298. /*++
  299. Purpose:
  300. Initialize the in-game texts.
  301. Parameters:
  302. None.
  303. Return value:
  304. 0 = success.
  305. -1 = memory allocation error.
  306. --*/
  307. {
  308. FILE *fpMsg, *fpWord;
  309. int i;
  310. if (gpGlobals->pszMsgName)
  311. {
  312. FILE *fpIndex;
  313. char *filename = (char *)alloca((i = strlen(gpGlobals->pszMsgName)) + 5);
  314. //
  315. // Open the message, index and word data files.
  316. //
  317. strcpy(filename, gpGlobals->pszMsgName);
  318. strcpy(filename + i, ".msg"); fpMsg = UTIL_OpenRequiredFileForMode(filename, "r");
  319. strcpy(filename + i, ".idx"); fpIndex = UTIL_OpenRequiredFileForMode(filename, "r");
  320. strcpy(filename + i, ".wrd"); fpWord = UTIL_OpenRequiredFileForMode(filename, "r");
  321. //
  322. // Read the contents of the message, index and word data files.
  323. //
  324. if ((g_TextLib.nWords = PAL_ReadFileAndSplitLine(fpWord, &g_TextLib.lpWordBuf)) <= 0)
  325. {
  326. fclose(fpIndex);
  327. fclose(fpMsg);
  328. return -1;
  329. }
  330. else
  331. {
  332. DWORD dwWordLength = 0;
  333. for (i = 1; i < g_TextLib.nWords; i++)
  334. {
  335. LPWSTR ptr = g_TextLib.lpWordBuf[i];
  336. DWORD n = 0;
  337. while (*ptr) n += PAL_CharWidth(*ptr++) >> 3;
  338. if (dwWordLength < n) dwWordLength = n;
  339. }
  340. gpGlobals->dwWordLength = dwWordLength;
  341. }
  342. if ((g_TextLib.nMsgs = PAL_ReadFileAndSplitLine(fpMsg, &g_TextLib.lpMsgBuf)) <= 0)
  343. {
  344. fclose(fpIndex);
  345. return -1;
  346. }
  347. if ((g_TextLib.nIndices = PAL_ReadIndexFile(fpIndex, &g_TextLib.lpIndexBuf)) <= 0)
  348. {
  349. return -1;
  350. }
  351. }
  352. else
  353. {
  354. FILE *fpMsg, *fpWord;
  355. DWORD *offsets;
  356. LPWSTR tmp;
  357. LPBYTE temp;
  358. int wpos, wlen;
  359. //
  360. // Open the message and word data files.
  361. //
  362. fpMsg = UTIL_OpenRequiredFile("m.msg");
  363. fpWord = UTIL_OpenRequiredFile("word.dat");
  364. //
  365. // See how many words we have
  366. //
  367. fseek(fpWord, 0, SEEK_END);
  368. i = ftell(fpWord);
  369. //
  370. // Each word has 10 or 16 bytes
  371. //
  372. g_TextLib.nWords = (i + (gpGlobals->dwWordLength - 1)) / gpGlobals->dwWordLength;
  373. //
  374. // Read the words
  375. //
  376. temp = (LPBYTE)malloc(i);
  377. if (temp == NULL)
  378. {
  379. fclose(fpWord);
  380. fclose(fpMsg);
  381. return -1;
  382. }
  383. fseek(fpWord, 0, SEEK_SET);
  384. fread(temp, i, 1, fpWord);
  385. //
  386. // Close the words file
  387. //
  388. fclose(fpWord);
  389. // Split the words and do code page conversion
  390. for (i = 0, wlen = 0; i < g_TextLib.nWords; i++)
  391. {
  392. int base = i * gpGlobals->dwWordLength;
  393. int pos = base + gpGlobals->dwWordLength - 1;
  394. while (pos >= base && temp[pos] == ' ') temp[pos--] = 0;
  395. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + base, gpGlobals->dwWordLength, NULL, 0) + 1;
  396. }
  397. g_TextLib.lpWordBuf = (LPWSTR*)malloc(g_TextLib.nWords * sizeof(LPWSTR));
  398. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  399. for (i = 0, wpos = 0; i < g_TextLib.nWords; i++)
  400. {
  401. int l;
  402. g_TextLib.lpWordBuf[i] = tmp + wpos;
  403. l = PAL_MultiByteToWideChar((LPCSTR)temp + i * gpGlobals->dwWordLength, gpGlobals->dwWordLength, g_TextLib.lpWordBuf[i], wlen - wpos);
  404. if (l > 0 && g_TextLib.lpWordBuf[i][l - 1] == '1')
  405. g_TextLib.lpWordBuf[i][l - 1] = 0;
  406. g_TextLib.lpWordBuf[i][l] = 0;
  407. wpos += l + 1;
  408. }
  409. free(temp);
  410. //
  411. // Read the message offsets. The message offsets are in SSS.MKF #3
  412. //
  413. i = PAL_MKFGetChunkSize(3, gpGlobals->f.fpSSS) / sizeof(DWORD);
  414. g_TextLib.nMsgs = i - 1;
  415. offsets = (LPDWORD)malloc(i * sizeof(DWORD));
  416. if (offsets == NULL)
  417. {
  418. free(g_TextLib.lpWordBuf);
  419. fclose(fpMsg);
  420. return -1;
  421. }
  422. PAL_MKFReadChunk((LPBYTE)(offsets), i * sizeof(DWORD), 3, gpGlobals->f.fpSSS);
  423. //
  424. // Read the messages.
  425. //
  426. fseek(fpMsg, 0, SEEK_END);
  427. i = ftell(fpMsg);
  428. temp = (LPBYTE)malloc(i);
  429. if (temp == NULL)
  430. {
  431. free(offsets);
  432. free(g_TextLib.lpWordBuf[0]);
  433. free(g_TextLib.lpWordBuf);
  434. fclose(fpMsg);
  435. return -1;
  436. }
  437. fseek(fpMsg, 0, SEEK_SET);
  438. fread(temp, 1, i, fpMsg);
  439. fclose(fpMsg);
  440. // Split messages and do code page conversion here
  441. for (i = 0, wlen = 0; i < g_TextLib.nMsgs; i++)
  442. {
  443. wlen += PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), NULL, 0) + 1;
  444. }
  445. g_TextLib.lpMsgBuf = (LPWSTR*)malloc(g_TextLib.nMsgs * sizeof(LPWSTR));
  446. tmp = (LPWSTR)malloc(wlen * sizeof(WCHAR));
  447. for (i = 0, wpos = 0; i < g_TextLib.nMsgs; i++)
  448. {
  449. int l;
  450. g_TextLib.lpMsgBuf[i] = tmp + wpos;
  451. l = PAL_MultiByteToWideChar((LPCSTR)temp + SDL_SwapLE32(offsets[i]), SDL_SwapLE32(offsets[i + 1]) - SDL_SwapLE32(offsets[i]), g_TextLib.lpMsgBuf[i], wlen - wpos);
  452. g_TextLib.lpMsgBuf[i][l] = 0;
  453. wpos += l + 1;
  454. }
  455. free(temp);
  456. free(offsets);
  457. g_TextLib.lpIndexBuf = NULL;
  458. }
  459. #ifndef PAL_CLASSIC
  460. g_rgszAdditionalWords = gc_rgszAdditionalWords[gpGlobals->iCodePage];
  461. #endif
  462. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  463. g_TextLib.bIcon = 0;
  464. g_TextLib.posIcon = 0;
  465. g_TextLib.nCurrentDialogLine = 0;
  466. g_TextLib.iDelayTime = 3;
  467. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  468. g_TextLib.posDialogText = PAL_XY(44, 26);
  469. g_TextLib.bDialogPosition = kDialogUpper;
  470. g_TextLib.fUserSkip = FALSE;
  471. PAL_MKFReadChunk(g_TextLib.bufDialogIcons, 282, 12, gpGlobals->f.fpDATA);
  472. return 0;
  473. }
  474. VOID
  475. PAL_FreeText(
  476. VOID
  477. )
  478. /*++
  479. Purpose:
  480. Free the memory used by the texts.
  481. Parameters:
  482. None.
  483. Return value:
  484. None.
  485. --*/
  486. {
  487. int i;
  488. if (g_TextLib.lpMsgBuf != NULL)
  489. {
  490. if (gpGlobals->pszMsgName)
  491. for(i = 0; i < g_TextLib.nMsgs; i++) free(g_TextLib.lpMsgBuf[i]);
  492. else
  493. free(g_TextLib.lpMsgBuf[0]);
  494. free(g_TextLib.lpMsgBuf);
  495. g_TextLib.lpMsgBuf = NULL;
  496. }
  497. if (g_TextLib.lpWordBuf != NULL)
  498. {
  499. if (gpGlobals->pszMsgName)
  500. for(i = 0; i < g_TextLib.nWords; i++) free(g_TextLib.lpWordBuf[i]);
  501. else
  502. free(g_TextLib.lpWordBuf[0]);
  503. free(g_TextLib.lpWordBuf);
  504. g_TextLib.lpWordBuf = NULL;
  505. }
  506. if (g_TextLib.lpIndexBuf != NULL)
  507. {
  508. if (gpGlobals->pszMsgName)
  509. for(i = 0; i < g_TextLib.nIndices; i++) free(g_TextLib.lpIndexBuf[i]);
  510. else
  511. free(g_TextLib.lpIndexBuf[0]);
  512. free(g_TextLib.lpIndexBuf);
  513. g_TextLib.lpIndexBuf = NULL;
  514. }
  515. }
  516. LPCWSTR
  517. PAL_GetWord(
  518. int iNumWord
  519. )
  520. /*++
  521. Purpose:
  522. Get the specified word.
  523. Parameters:
  524. [IN] wNumWord - the number of the requested word.
  525. Return value:
  526. Pointer to the requested word. NULL if not found.
  527. --*/
  528. {
  529. #ifndef PAL_CLASSIC
  530. if (wNumWord >= PAL_ADDITIONAL_WORD_FIRST)
  531. {
  532. return g_rgszAdditionalWords[wNumWord - PAL_ADDITIONAL_WORD_FIRST];
  533. }
  534. #endif
  535. return (iNumWord >= g_TextLib.nWords || !g_TextLib.lpWordBuf[iNumWord]) ? L"" : g_TextLib.lpWordBuf[iNumWord];
  536. }
  537. LPCWSTR
  538. PAL_GetMsg(
  539. int iNumMsg
  540. )
  541. /*++
  542. Purpose:
  543. Get the specified message.
  544. Parameters:
  545. [IN] wNumMsg - the number of the requested message.
  546. Return value:
  547. Pointer to the requested message. NULL if not found.
  548. --*/
  549. {
  550. return (iNumMsg >= g_TextLib.nMsgs || !g_TextLib.lpMsgBuf[iNumMsg]) ? L"" : g_TextLib.lpMsgBuf[iNumMsg];
  551. }
  552. int
  553. PAL_GetMsgNum(
  554. int iIndex,
  555. int iOrder
  556. )
  557. /*++
  558. Purpose:
  559. Get the number of specified message from index & order.
  560. Parameters:
  561. [IN] iMsgIndex - index.
  562. [IN] iOrder - order inside the index.
  563. Return value:
  564. The number of message. Zero means pausing for key, and -1 means end.
  565. --*/
  566. {
  567. return (iIndex >= g_TextLib.nMsgs || !g_TextLib.lpIndexBuf[iIndex]) ? -1 : g_TextLib.lpIndexBuf[iIndex][iOrder];
  568. }
  569. VOID
  570. PAL_DrawText(
  571. LPCWSTR lpszText,
  572. PAL_POS pos,
  573. BYTE bColor,
  574. BOOL fShadow,
  575. BOOL fUpdate
  576. )
  577. /*++
  578. Purpose:
  579. Draw text on the screen.
  580. Parameters:
  581. [IN] lpszText - the text to be drawn.
  582. [IN] pos - Position of the text.
  583. [IN] bColor - Color of the text.
  584. [IN] fShadow - TRUE if the text is shadowed or not.
  585. [IN] fUpdate - TRUE if update the screen area.
  586. Return value:
  587. None.
  588. --*/
  589. {
  590. SDL_Rect rect, urect;
  591. rect.x = PAL_X(pos);
  592. rect.y = PAL_Y(pos);
  593. urect.x = rect.x;
  594. urect.y = rect.y;
  595. urect.h = gpGlobals->fUseEmbeddedFonts ? 16 : 17;
  596. urect.w = 0;
  597. while (*lpszText)
  598. {
  599. //
  600. // Draw the character
  601. //
  602. int char_width = PAL_CharWidth(*lpszText);
  603. if (fShadow)
  604. {
  605. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y + 1), 0);
  606. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x + 1, rect.y), 0);
  607. }
  608. PAL_DrawCharOnSurface(*lpszText, gpScreen, PAL_XY(rect.x, rect.y), bColor);
  609. lpszText++;
  610. rect.x += char_width;
  611. urect.w += char_width;
  612. }
  613. //
  614. // Update the screen area
  615. //
  616. if (fUpdate && urect.w > 0)
  617. {
  618. if (gpGlobals->fIsWIN95)
  619. {
  620. urect.w++;
  621. if (urect.x + urect.w > 320)
  622. {
  623. urect.w = 320 - urect.x;
  624. }
  625. }
  626. VIDEO_UpdateScreen(&urect);
  627. }
  628. }
  629. VOID
  630. PAL_DialogSetDelayTime(
  631. INT iDelayTime
  632. )
  633. /*++
  634. Purpose:
  635. Set the delay time for dialog.
  636. Parameters:
  637. [IN] iDelayTime - the delay time to be set.
  638. Return value:
  639. None.
  640. --*/
  641. {
  642. g_TextLib.iDelayTime = iDelayTime;
  643. }
  644. VOID
  645. PAL_StartDialog(
  646. BYTE bDialogLocation,
  647. BYTE bFontColor,
  648. INT iNumCharFace,
  649. BOOL fPlayingRNG
  650. )
  651. /*++
  652. Purpose:
  653. Start a new dialog.
  654. Parameters:
  655. [IN] bDialogLocation - the location of the text on the screen.
  656. [IN] bFontColor - the font color of the text.
  657. [IN] iNumCharFace - number of the character face in RGM.MKF.
  658. [IN] fPlayingRNG - whether we are playing a RNG video or not.
  659. Return value:
  660. None.
  661. --*/
  662. {
  663. PAL_LARGE BYTE buf[16384];
  664. SDL_Rect rect;
  665. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  666. {
  667. //
  668. // Update the screen in battle, or the graphics may seem messed up
  669. //
  670. VIDEO_UpdateScreen(NULL);
  671. g_fUpdatedInBattle = TRUE;
  672. }
  673. g_TextLib.bIcon = 0;
  674. g_TextLib.posIcon = 0;
  675. g_TextLib.nCurrentDialogLine = 0;
  676. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  677. g_TextLib.fUserSkip = FALSE;
  678. if (bFontColor != 0)
  679. {
  680. g_TextLib.bCurrentFontColor = bFontColor;
  681. }
  682. if (fPlayingRNG && iNumCharFace)
  683. {
  684. VIDEO_BackupScreen();
  685. g_TextLib.fPlayingRNG = TRUE;
  686. }
  687. switch (bDialogLocation)
  688. {
  689. case kDialogUpper:
  690. if (iNumCharFace > 0)
  691. {
  692. //
  693. // Display the character face at the upper part of the screen
  694. //
  695. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  696. {
  697. rect.w = PAL_RLEGetWidth((LPCBITMAPRLE)buf);
  698. rect.h = PAL_RLEGetHeight((LPCBITMAPRLE)buf);
  699. rect.x = 48 - rect.w / 2;
  700. rect.y = 55 - rect.h / 2;
  701. if (rect.x < 0)
  702. {
  703. rect.x = 0;
  704. }
  705. if (rect.y < 0)
  706. {
  707. rect.y = 0;
  708. }
  709. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  710. if (rect.x < 0)
  711. {
  712. rect.x = 0;
  713. }
  714. if (rect.y < 0)
  715. {
  716. rect.y = 0;
  717. }
  718. VIDEO_UpdateScreen(&rect);
  719. }
  720. }
  721. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 80 : 12, 8);
  722. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 96 : 44, 26);
  723. break;
  724. case kDialogCenter:
  725. g_TextLib.posDialogText = PAL_XY(80, 40);
  726. break;
  727. case kDialogLower:
  728. if (iNumCharFace > 0)
  729. {
  730. //
  731. // Display the character face at the lower part of the screen
  732. //
  733. if (PAL_MKFReadChunk(buf, 16384, iNumCharFace, gpGlobals->f.fpRGM) > 0)
  734. {
  735. rect.x = 270 - PAL_RLEGetWidth((LPCBITMAPRLE)buf) / 2;
  736. rect.y = 144 - PAL_RLEGetHeight((LPCBITMAPRLE)buf) / 2;
  737. PAL_RLEBlitToSurface((LPCBITMAPRLE)buf, gpScreen, PAL_XY(rect.x, rect.y));
  738. VIDEO_UpdateScreen(NULL);
  739. }
  740. }
  741. g_TextLib.posDialogTitle = PAL_XY(iNumCharFace > 0 ? 4 : 12, 108);
  742. g_TextLib.posDialogText = PAL_XY(iNumCharFace > 0 ? 20 : 44, 126);
  743. break;
  744. case kDialogCenterWindow:
  745. g_TextLib.posDialogText = PAL_XY(160, 40);
  746. break;
  747. }
  748. g_TextLib.bDialogPosition = bDialogLocation;
  749. }
  750. static VOID
  751. PAL_DialogWaitForKey(
  752. VOID
  753. )
  754. /*++
  755. Purpose:
  756. Wait for player to press a key after showing a dialog.
  757. Parameters:
  758. None.
  759. Return value:
  760. None.
  761. --*/
  762. {
  763. PAL_LARGE SDL_Color palette[256];
  764. SDL_Color *pCurrentPalette, t;
  765. int i;
  766. //
  767. // get the current palette
  768. //
  769. pCurrentPalette = PAL_GetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  770. memcpy(palette, pCurrentPalette, sizeof(palette));
  771. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  772. g_TextLib.bDialogPosition != kDialogCenter)
  773. {
  774. //
  775. // show the icon
  776. //
  777. LPCBITMAPRLE p = PAL_SpriteGetFrame(g_TextLib.bufDialogIcons, g_TextLib.bIcon);
  778. if (p != NULL)
  779. {
  780. SDL_Rect rect;
  781. rect.x = PAL_X(g_TextLib.posIcon);
  782. rect.y = PAL_Y(g_TextLib.posIcon);
  783. rect.w = 16;
  784. rect.h = 16;
  785. PAL_RLEBlitToSurface(p, gpScreen, g_TextLib.posIcon);
  786. VIDEO_UpdateScreen(&rect);
  787. }
  788. }
  789. PAL_ClearKeyState();
  790. while (TRUE)
  791. {
  792. UTIL_Delay(100);
  793. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  794. g_TextLib.bDialogPosition != kDialogCenter)
  795. {
  796. //
  797. // palette shift
  798. //
  799. t = palette[0xF9];
  800. for (i = 0xF9; i < 0xFE; i++)
  801. {
  802. palette[i] = palette[i + 1];
  803. }
  804. palette[0xFE] = t;
  805. VIDEO_SetPalette(palette);
  806. }
  807. if (g_InputState.dwKeyPress != 0)
  808. {
  809. break;
  810. }
  811. }
  812. if (g_TextLib.bDialogPosition != kDialogCenterWindow &&
  813. g_TextLib.bDialogPosition != kDialogCenter)
  814. {
  815. PAL_SetPalette(gpGlobals->wNumPalette, gpGlobals->fNightPalette);
  816. }
  817. PAL_ClearKeyState();
  818. g_TextLib.fUserSkip = FALSE;
  819. }
  820. VOID
  821. PAL_ShowDialogText(
  822. LPCWSTR lpszText
  823. )
  824. /*++
  825. Purpose:
  826. Show one line of the dialog text.
  827. Parameters:
  828. [IN] lpszText - the text to be shown.
  829. Return value:
  830. None.
  831. --*/
  832. {
  833. SDL_Rect rect;
  834. int x, y;
  835. PAL_ClearKeyState();
  836. g_TextLib.bIcon = 0;
  837. if (gpGlobals->fInBattle && !g_fUpdatedInBattle)
  838. {
  839. //
  840. // Update the screen in battle, or the graphics may seem messed up
  841. //
  842. VIDEO_UpdateScreen(NULL);
  843. g_fUpdatedInBattle = TRUE;
  844. }
  845. if (g_TextLib.nCurrentDialogLine > 3)
  846. {
  847. //
  848. // The rest dialogs should be shown in the next page.
  849. //
  850. PAL_DialogWaitForKey();
  851. g_TextLib.nCurrentDialogLine = 0;
  852. VIDEO_RestoreScreen();
  853. VIDEO_UpdateScreen(NULL);
  854. }
  855. x = PAL_X(g_TextLib.posDialogText);
  856. y = PAL_Y(g_TextLib.posDialogText) + g_TextLib.nCurrentDialogLine * 18;
  857. if (g_TextLib.bDialogPosition == kDialogCenterWindow)
  858. {
  859. //
  860. // The text should be shown in a small window at the center of the screen
  861. //
  862. #ifndef PAL_CLASSIC
  863. if (gpGlobals->fInBattle && g_Battle.BattleResult == kBattleResultOnGoing)
  864. {
  865. PAL_BattleUIShowText(lpszText, 1400);
  866. }
  867. else
  868. #endif
  869. {
  870. PAL_POS pos;
  871. LPBOX lpBox;
  872. int i, w = wcslen(lpszText), len = 0;
  873. for (i = 0; i < w; i++)
  874. len += PAL_CharWidth(lpszText[i]) >> 3;
  875. //
  876. // Create the window box
  877. //
  878. pos = PAL_XY(PAL_X(g_TextLib.posDialogText) - len * 4, PAL_Y(g_TextLib.posDialogText));
  879. lpBox = PAL_CreateSingleLineBox(pos, (len + 1) / 2, TRUE);
  880. rect.x = PAL_X(pos);
  881. rect.y = PAL_Y(pos);
  882. rect.w = 320 - rect.x * 2 + 32;
  883. rect.h = 64;
  884. //
  885. // Show the text on the screen
  886. //
  887. pos = PAL_XY(PAL_X(pos) + 8 + ((len & 1) << 2), PAL_Y(pos) + 10);
  888. PAL_DrawText(lpszText, pos, 0, FALSE, FALSE);
  889. VIDEO_UpdateScreen(&rect);
  890. PAL_DialogWaitForKey();
  891. //
  892. // Delete the box
  893. //
  894. PAL_DeleteBox(lpBox);
  895. VIDEO_UpdateScreen(&rect);
  896. PAL_EndDialog();
  897. }
  898. }
  899. else
  900. {
  901. int len = wcslen(lpszText);
  902. if (g_TextLib.nCurrentDialogLine == 0 &&
  903. g_TextLib.bDialogPosition != kDialogCenter &&
  904. (lpszText[len - 1] == 0xff1a ||
  905. lpszText[len - 1] == 0x2236 || // Special case for Pal WIN95 Simplified Chinese version
  906. lpszText[len - 1] == ':')
  907. )
  908. {
  909. //
  910. // name of character
  911. //
  912. PAL_DrawText(lpszText, g_TextLib.posDialogTitle, FONT_COLOR_CYAN_ALT, TRUE, TRUE);
  913. }
  914. else
  915. {
  916. //
  917. // normal texts
  918. //
  919. WCHAR text[2];
  920. if (!g_TextLib.fPlayingRNG && g_TextLib.nCurrentDialogLine == 0)
  921. {
  922. //
  923. // Save the screen before we show the first line of dialog
  924. //
  925. VIDEO_BackupScreen();
  926. }
  927. while (lpszText != NULL && *lpszText != '\0')
  928. {
  929. switch (*lpszText)
  930. {
  931. case '-':
  932. //
  933. // Set the font color to Cyan
  934. //
  935. if (g_TextLib.bCurrentFontColor == FONT_COLOR_CYAN)
  936. {
  937. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  938. }
  939. else
  940. {
  941. g_TextLib.bCurrentFontColor = FONT_COLOR_CYAN;
  942. }
  943. lpszText++;
  944. break;
  945. #if 0
  946. /* Not used */
  947. case '\'':
  948. //
  949. // Set the font color to Red
  950. //
  951. if (g_TextLib.bCurrentFontColor == FONT_COLOR_RED)
  952. {
  953. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  954. }
  955. else
  956. {
  957. g_TextLib.bCurrentFontColor = FONT_COLOR_RED;
  958. }
  959. lpszText++;
  960. break;
  961. #endif
  962. case '\"':
  963. //
  964. // Set the font color to Yellow
  965. //
  966. if (g_TextLib.bCurrentFontColor == FONT_COLOR_YELLOW)
  967. {
  968. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  969. }
  970. else
  971. {
  972. g_TextLib.bCurrentFontColor = FONT_COLOR_YELLOW;
  973. }
  974. lpszText++;
  975. break;
  976. case '$':
  977. //
  978. // Set the delay time of text-displaying
  979. //
  980. g_TextLib.iDelayTime = wcstol(lpszText + 1, NULL, 10) * 10 / 7;
  981. lpszText += 3;
  982. break;
  983. case '~':
  984. //
  985. // Delay for a period and quit
  986. //
  987. UTIL_Delay(wcstol(lpszText + 1, NULL, 10) * 80 / 7);
  988. g_TextLib.nCurrentDialogLine = 0;
  989. g_TextLib.fUserSkip = FALSE;
  990. return; // don't go further
  991. case ')':
  992. //
  993. // Set the waiting icon
  994. //
  995. g_TextLib.bIcon = 1;
  996. lpszText++;
  997. break;
  998. case '(':
  999. //
  1000. // Set the waiting icon
  1001. //
  1002. g_TextLib.bIcon = 2;
  1003. lpszText++;
  1004. break;
  1005. case '\\':
  1006. lpszText++;
  1007. default:
  1008. text[0] = *lpszText++;
  1009. text[1] = 0;
  1010. PAL_DrawText(text, PAL_XY(x, y), g_TextLib.bCurrentFontColor, TRUE, TRUE);
  1011. x += PAL_CharWidth(text[0]);
  1012. if (!g_TextLib.fUserSkip)
  1013. {
  1014. PAL_ClearKeyState();
  1015. UTIL_Delay(g_TextLib.iDelayTime * 8);
  1016. if (g_InputState.dwKeyPress & (kKeySearch | kKeyMenu))
  1017. {
  1018. //
  1019. // User pressed a key to skip the dialog
  1020. //
  1021. g_TextLib.fUserSkip = TRUE;
  1022. }
  1023. }
  1024. }
  1025. }
  1026. g_TextLib.posIcon = PAL_XY(x, y);
  1027. g_TextLib.nCurrentDialogLine++;
  1028. }
  1029. }
  1030. }
  1031. VOID
  1032. PAL_ClearDialog(
  1033. BOOL fWaitForKey
  1034. )
  1035. /*++
  1036. Purpose:
  1037. Clear the state of the dialog.
  1038. Parameters:
  1039. [IN] fWaitForKey - whether wait for any key or not.
  1040. Return value:
  1041. None.
  1042. --*/
  1043. {
  1044. if (g_TextLib.nCurrentDialogLine > 0 && fWaitForKey)
  1045. {
  1046. PAL_DialogWaitForKey();
  1047. }
  1048. g_TextLib.nCurrentDialogLine = 0;
  1049. if (g_TextLib.bDialogPosition == kDialogCenter)
  1050. {
  1051. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1052. g_TextLib.posDialogText = PAL_XY(44, 26);
  1053. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1054. g_TextLib.bDialogPosition = kDialogUpper;
  1055. }
  1056. }
  1057. VOID
  1058. PAL_EndDialog(
  1059. VOID
  1060. )
  1061. /*++
  1062. Purpose:
  1063. Ends a dialog.
  1064. Parameters:
  1065. None.
  1066. Return value:
  1067. None.
  1068. --*/
  1069. {
  1070. PAL_ClearDialog(TRUE);
  1071. //
  1072. // Set some default parameters, as there are some parts of script
  1073. // which doesn't have a "start dialog" instruction before showing the dialog.
  1074. //
  1075. g_TextLib.posDialogTitle = PAL_XY(12, 8);
  1076. g_TextLib.posDialogText = PAL_XY(44, 26);
  1077. g_TextLib.bCurrentFontColor = FONT_COLOR_DEFAULT;
  1078. g_TextLib.bDialogPosition = kDialogUpper;
  1079. g_TextLib.fUserSkip = FALSE;
  1080. g_TextLib.fPlayingRNG = FALSE;
  1081. }
  1082. BOOL
  1083. PAL_IsInDialog(
  1084. VOID
  1085. )
  1086. /*++
  1087. Purpose:
  1088. Check if there are dialog texts on the screen.
  1089. Parameters:
  1090. None.
  1091. Return value:
  1092. TRUE if there are dialog texts on the screen, FALSE if not.
  1093. --*/
  1094. {
  1095. return (g_TextLib.nCurrentDialogLine != 0);
  1096. }
  1097. BOOL
  1098. PAL_DialogIsPlayingRNG(
  1099. VOID
  1100. )
  1101. /*++
  1102. Purpose:
  1103. Check if the script used the RNG playing parameter when displaying texts.
  1104. Parameters:
  1105. None.
  1106. Return value:
  1107. TRUE if the script used the RNG playing parameter, FALSE if not.
  1108. --*/
  1109. {
  1110. return g_TextLib.fPlayingRNG;
  1111. }
  1112. INT
  1113. PAL_MultiByteToWideCharCP(
  1114. CODEPAGE cp,
  1115. LPCSTR mbs,
  1116. int mbslength,
  1117. LPWSTR wcs,
  1118. int wcslength
  1119. )
  1120. /*++
  1121. Purpose:
  1122. Convert multi-byte string into the corresponding unicode string.
  1123. Parameters:
  1124. [IN] cp - Code page for conversion.
  1125. [IN] mbs - Pointer to the multi-byte string.
  1126. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1127. [IN] wcs - Pointer to the wide string buffer.
  1128. [IN] wcslength - Length of the wide string buffer.
  1129. Return value:
  1130. The length of converted wide string. If mbslength is set to -1, the returned
  1131. value includes the terminal null-char; otherwise, the null-char is not included.
  1132. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1133. required length of the wide string buffer.
  1134. --*/
  1135. {
  1136. int i = 0, state = 0, wlen = 0, null = 0;
  1137. if (mbslength == -1)
  1138. {
  1139. mbslength = strlen(mbs);
  1140. null = 1;
  1141. }
  1142. if (!wcs)
  1143. {
  1144. switch (cp)
  1145. {
  1146. case CP_SHIFTJIS:
  1147. for (i = 0; i < mbslength && mbs[i]; i++)
  1148. {
  1149. if (state == 0)
  1150. {
  1151. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] >= 0xfd || ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf))
  1152. wlen++;
  1153. else
  1154. state = 1;
  1155. }
  1156. else
  1157. {
  1158. wlen++;
  1159. state = 0;
  1160. }
  1161. }
  1162. break;
  1163. case CP_GBK:
  1164. case CP_BIG5:
  1165. for (i = 0; i < mbslength && mbs[i]; i++)
  1166. {
  1167. if (state == 0)
  1168. {
  1169. if ((BYTE)mbs[i] <= 0x80 || (BYTE)mbs[i] == 0xff)
  1170. wlen++;
  1171. else
  1172. state = 1;
  1173. }
  1174. else
  1175. {
  1176. wlen++;
  1177. state = 0;
  1178. }
  1179. }
  1180. break;
  1181. case CP_UTF_8:
  1182. for (i = 0; i < mbslength && mbs[i]; i++)
  1183. {
  1184. if (state == 0)
  1185. {
  1186. if ((BYTE)mbs[i] >= 0x80)
  1187. {
  1188. BYTE s = (BYTE)mbs[i] << 1;
  1189. while (s >= 0x80) { state++; s <<= 1; }
  1190. if (state < 1 || state > 3)
  1191. {
  1192. state = 0;
  1193. wlen++;
  1194. }
  1195. }
  1196. else
  1197. wlen++;
  1198. }
  1199. else
  1200. {
  1201. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1202. {
  1203. if (--state == 0) wlen++;
  1204. }
  1205. else
  1206. {
  1207. state = 0; wlen++;
  1208. }
  1209. }
  1210. }
  1211. break;
  1212. default:
  1213. return -1;
  1214. }
  1215. if (i < mbslength && !mbs[i]) null = 1;
  1216. return wlen + null + (state != 0);
  1217. }
  1218. else
  1219. {
  1220. WCHAR invalid_char;
  1221. switch (cp)
  1222. {
  1223. case CP_SHIFTJIS:
  1224. invalid_char = 0x30fb;
  1225. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1226. {
  1227. if (state == 0)
  1228. {
  1229. if ((BYTE)mbs[i] <= 0x80)
  1230. wcs[wlen++] = mbs[i];
  1231. else if ((BYTE)mbs[i] >= 0xa0 && (BYTE)mbs[i] <= 0xdf)
  1232. wcs[wlen++] = cptbl_jis_half[(BYTE)mbs[i] - 0xa0];
  1233. else if ((BYTE)mbs[i] == 0xfd)
  1234. wcs[wlen++] = 0xf8f1;
  1235. else if ((BYTE)mbs[i] == 0xfe)
  1236. wcs[wlen++] = 0xf8f2;
  1237. else if ((BYTE)mbs[i] == 0xff)
  1238. wcs[wlen++] = 0xf8f3;
  1239. else
  1240. state = 1;
  1241. }
  1242. else
  1243. {
  1244. if ((BYTE)mbs[i] < 0x40)
  1245. wcs[wlen++] = 0x30fb;
  1246. else if ((BYTE)mbs[i - 1] < 0xa0)
  1247. wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1248. else
  1249. wcs[wlen++] = cptbl_jis[(BYTE)mbs[i - 1] - 0xc1][(BYTE)mbs[i] - 0x40];
  1250. state = 0;
  1251. }
  1252. }
  1253. break;
  1254. case CP_GBK:
  1255. invalid_char = 0x3f;
  1256. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1257. {
  1258. if (state == 0)
  1259. {
  1260. if ((BYTE)mbs[i] < 0x80)
  1261. wcs[wlen++] = mbs[i];
  1262. else if ((BYTE)mbs[i] == 0x80)
  1263. wcs[wlen++] = 0x20ac;
  1264. else if ((BYTE)mbs[i] == 0xff)
  1265. wcs[wlen++] = 0xf8f5;
  1266. else
  1267. state = 1;
  1268. }
  1269. else
  1270. {
  1271. if ((BYTE)mbs[i] < 0x40)
  1272. wcs[wlen++] = invalid_char;
  1273. else
  1274. wcs[wlen++] = cptbl_gbk[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1275. state = 0;
  1276. }
  1277. }
  1278. break;
  1279. case CP_BIG5:
  1280. invalid_char = 0x3f;
  1281. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1282. {
  1283. if (state == 0)
  1284. {
  1285. if ((BYTE)mbs[i] <= 0x80)
  1286. wcs[wlen++] = mbs[i];
  1287. else if ((BYTE)mbs[i] == 0xff)
  1288. wcs[wlen++] = 0xf8f8;
  1289. else
  1290. state = 1;
  1291. }
  1292. else
  1293. {
  1294. if ((BYTE)mbs[i] < 0x40 || ((BYTE)mbs[i] >= 0x7f && (BYTE)mbs[i] <= 0xa0))
  1295. wcs[wlen++] = invalid_char;
  1296. else if ((BYTE)mbs[i] <= 0x7e)
  1297. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x40];
  1298. else
  1299. wcs[wlen++] = cptbl_big5[(BYTE)mbs[i - 1] - 0x81][(BYTE)mbs[i] - 0x60];
  1300. state = 0;
  1301. }
  1302. }
  1303. break;
  1304. case CP_UTF_8:
  1305. invalid_char = 0x3f;
  1306. for (i = 0; i < mbslength && wlen < wcslength && mbs[i]; i++)
  1307. {
  1308. if (state == 0)
  1309. {
  1310. if ((BYTE)mbs[i] >= 0x80)
  1311. {
  1312. BYTE s = (BYTE)mbs[i] << 1;
  1313. while (s >= 0x80) { state++; s <<= 1; }
  1314. if (state < 1 || state > 3)
  1315. {
  1316. state = 0;
  1317. wcs[wlen++] = invalid_char;
  1318. }
  1319. else
  1320. {
  1321. wcs[wlen] = s >> (state + 1);
  1322. }
  1323. }
  1324. else
  1325. wcs[wlen++] = mbs[i];
  1326. }
  1327. else
  1328. {
  1329. if ((BYTE)mbs[i] >= 0x80 && (BYTE)mbs[i] < 0xc0)
  1330. {
  1331. wcs[wlen] <<= 6;
  1332. wcs[wlen] |= (BYTE)mbs[i] & 0x3f;
  1333. if (--state == 0) wlen++;
  1334. }
  1335. else
  1336. {
  1337. state = 0;
  1338. wcs[wlen++] = invalid_char;
  1339. }
  1340. }
  1341. }
  1342. break;
  1343. default:
  1344. return -1;
  1345. }
  1346. if (state != 0 && wlen < wcslength)
  1347. {
  1348. wcs[wlen++] = invalid_char;
  1349. }
  1350. if (null || (i < mbslength && !mbs[i]))
  1351. {
  1352. if (wlen < wcslength)
  1353. wcs[wlen++] = 0;
  1354. else
  1355. wcs[wlen - 1] = 0;
  1356. }
  1357. return wlen;
  1358. }
  1359. }
  1360. INT
  1361. PAL_MultiByteToWideChar(
  1362. LPCSTR mbs,
  1363. int mbslength,
  1364. LPWSTR wcs,
  1365. int wcslength
  1366. )
  1367. /*++
  1368. Purpose:
  1369. Convert multi-byte string into the corresponding unicode string.
  1370. Parameters:
  1371. [IN] mbs - Pointer to the multi-byte string.
  1372. [IN] mbslength - Length of the multi-byte string, or -1 for auto-detect.
  1373. [IN] wcs - Pointer to the wide string buffer.
  1374. [IN] wcslength - Length of the wide string buffer.
  1375. Return value:
  1376. The length of converted wide string. If mbslength is set to -1, the returned
  1377. value includes the terminal null-char; otherwise, the null-char is not included.
  1378. If wcslength is set to 0, wcs can be set to NULL and the return value is the
  1379. required length of the wide string buffer.
  1380. --*/
  1381. {
  1382. return PAL_MultiByteToWideCharCP(gpGlobals->iCodePage, mbs, mbslength, wcs, wcslength);
  1383. }
  1384. WCHAR
  1385. PAL_GetInvalidChar(
  1386. CODEPAGE iCodePage
  1387. )
  1388. {
  1389. switch(iCodePage)
  1390. {
  1391. case CP_BIG5: return 0x3f;
  1392. case CP_GBK: return 0x3f;
  1393. case CP_SHIFTJIS: return 0x30fb;
  1394. case CP_UTF_8: return 0x3f;
  1395. default: return 0;
  1396. }
  1397. }