locale.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* Copyright (C) Electronic Arts Canada Inc. 1998-1999. All rights reserved. */
  19. #include <string.h>
  20. #include <assert.h>
  21. #include "gimex.h" /* for file and memory IO only */
  22. #include "locale.h"
  23. //#include "wnd_file.h"
  24. #define ASSERT assert
  25. #define VERIFY ASSERT
  26. /*************************************************************************/
  27. /* File Format Structures */
  28. /*************************************************************************/
  29. #define LOCALEFILE_HEADERCHUNKID 0x48434f4c /* 'LOCH' */
  30. #define LOCALEFILE_INDEXCHUNKID 0x49434f4c /* 'LOCI' */
  31. #define LOCALEFILE_LANGUAGECHUNKID 0x4c434f4c /* 'LOCL' */
  32. typedef struct
  33. {
  34. unsigned int ChunkID; /* 'LOCH' LOCALEFILE_HEADERCHUNKID */
  35. unsigned int ChunkSize; /* size of chunk in bytes */
  36. unsigned int Flags; /* 0=no index chunk present,1=index chunk present */
  37. unsigned int LanguageCount; /* number of language chunks in this file */
  38. /* unsigned int LanguageOffset[LanguageCount]; \\ offsets in bytes from start of file to language chunk */
  39. } LOCALEFILE_HEADERCHUNK;
  40. /* offset LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET bytes from the start of the chunk to the language offset table */
  41. #define LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET sizeof(LOCALEFILE_HEADERCHUNK)
  42. typedef struct
  43. {
  44. unsigned int ChunkID; /* 'LOCI' LOCALEFILE_INDEXCHUNKID */
  45. unsigned int ChunkSize; /* size of chunk in bytes */
  46. unsigned int StringCount; /* number of string ids in this chunk (same value in all language chunks) */
  47. unsigned int pad; /* must be zero */
  48. /* STRINGID StringID[StringCount]; */
  49. /* { */
  50. /* unsigned short ID; \\ id that user gives to look up value */
  51. /* unsigned short Index; \\ index to look up value in language chunks */
  52. /* } */
  53. } LOCALEFILE_INDEXCHUNK;
  54. /* offset LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET bytes from the start of the chunk to the string id table */
  55. #define LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET sizeof(LOCALEFILE_INDEXCHUNK)
  56. typedef struct
  57. {
  58. unsigned int ChunkID; /* 'LOCL' LOCALEFILE_LANGUAGECHUNKID */
  59. unsigned int ChunkSize; /* size of chunk in bytes including this header and all string data */
  60. unsigned int LanguageID; /* language strings are in for this bank */
  61. unsigned int StringCount; /* number of strings in this chunk */
  62. /* unsigned int StringOffset[StringCount]; \\ offsets in bytes from start of chunk to string */
  63. /* const char* Data[StringCount]; \\ StringCount null terminated strings */
  64. } LOCALEFILE_LANGUAGECHUNK;
  65. /* offset LOCALEFILE_LANGUAGECHUNK_STRING_OFFSETbytes from the start of the chunk to the string offset table */
  66. #define LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET sizeof(LOCALEFILE_LANGUAGECHUNK)
  67. /*************************************************************************/
  68. /* LOCALE_INSTANCE declaration */
  69. /*************************************************************************/
  70. typedef LOCALEFILE_HEADERCHUNK HEADER;
  71. typedef LOCALEFILE_INDEXCHUNK INDEX;
  72. typedef LOCALEFILE_LANGUAGECHUNK BANK;
  73. typedef struct
  74. {
  75. int BankIndex; /* current language bank set (0..BANK_COUNT-1) */
  76. BANK* pBank[LOCALE_BANK_COUNT]; /* array of string banks */
  77. INDEX* pIndex[LOCALE_BANK_COUNT]; /* array of string indices */
  78. } LOCALE_INSTANCE;
  79. static LOCALE_INSTANCE *lx = NULL;
  80. /*************************************************************************/
  81. /* initialization/restore */
  82. /*************************************************************************/
  83. /* helper function to make assertions for initialization clearer */
  84. int LOCALE_isinitialized( void )
  85. {
  86. if ( lx == NULL ) {
  87. // TRACE("LOCALE API is not initialized - call LOCALE_init before calling LOCALE functions\n");
  88. }
  89. return( lx != NULL );
  90. }
  91. /*
  92. ;
  93. ; ABSTRACT
  94. ;
  95. ; LOCALE_init - Init the localization module
  96. ;
  97. ;
  98. ; SUMMARY
  99. ;
  100. ; #include "realfont.h"
  101. ;
  102. ; int LOCALE_init(void)
  103. ;
  104. ; DESCRIPTION
  105. ;
  106. ; Initilizes everything needed to use the locale API. Can only be called
  107. ; once until LOCALE_restore is called.
  108. ;
  109. ; Returns non-zero if everything went ok.
  110. ;
  111. ; SEE ALSO
  112. ;
  113. ; LOCALE_restore
  114. ;
  115. ;
  116. ; EXAMPLE
  117. ;
  118. ; locale_eg.c
  119. ;
  120. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  121. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  122. ;
  123. ;
  124. ; END ABSTRACT
  125. ;
  126. */
  127. int LOCALE_init(void)
  128. {
  129. int ok = 0;
  130. /* ensure locale module is NOT already initialized */
  131. ASSERT(lx == NULL); /* can only call LOCALE_init after a restore or once, cannot double init locale API */
  132. if( lx != NULL )
  133. return ok;
  134. /* allocate instance */
  135. lx = (LOCALE_INSTANCE*)galloc(sizeof(LOCALE_INSTANCE));
  136. if (lx != NULL) {
  137. memset(lx, 0, sizeof(LOCALE_INSTANCE));
  138. ok = 1;
  139. }
  140. return ok;
  141. }
  142. /*
  143. ;
  144. ; ABSTRACT
  145. ;
  146. ; LOCALE_restore - Free resources used by the locale module
  147. ;
  148. ;
  149. ; SUMMARY
  150. ;
  151. ; #include "realfont.h"
  152. ;
  153. ; void LOCALE_restore(void)
  154. ;
  155. ; DESCRIPTION
  156. ;
  157. ; Restores all resources used by the locale API. Can only be called after
  158. ; LOCALE_init, and only once.
  159. ;
  160. ; SEE ALSO
  161. ;
  162. ; LOCALE_init
  163. ;
  164. ;
  165. ; EXAMPLE
  166. ;
  167. ; locale_eg.c
  168. ;
  169. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  170. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  171. ;
  172. ;
  173. ; END ABSTRACT
  174. ;
  175. */
  176. void LOCALE_restore(void)
  177. {
  178. int i;
  179. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  180. ASSERT(lx != NULL);
  181. if( lx != NULL ) {
  182. /* free any language tables */
  183. for (i = 0; i < LOCALE_BANK_COUNT; i++) {
  184. if (lx->pBank[i]) {
  185. LOCALE_setbank(i);
  186. LOCALE_freetable();
  187. }
  188. }
  189. /* free instance */
  190. gfree(lx);
  191. lx = NULL;
  192. }
  193. }
  194. /*************************************************************************/
  195. /* attributes */
  196. /*************************************************************************/
  197. /*
  198. ;
  199. ; ABSTRACT
  200. ;
  201. ; LOCALE_setbank - Set the current bank
  202. ;
  203. ;
  204. ; SUMMARY
  205. ;
  206. ; #include "realfont.h"
  207. ;
  208. ; void LOCALE_setbank(BankIndex)
  209. ; int BankIndex; Number between 0 and LOCALE_BANK_COUNT - 1
  210. ;
  211. ; DESCRIPTION
  212. ;
  213. ; Sets the current bank to be active. All functions will now use this
  214. ; bank for strings. A bank is slot where a string table is loaded.
  215. ; More than one bank can have a table loaded but the locale functions
  216. ; only work on one bank at a time, the active bank set by this function.
  217. ;
  218. ; SEE ALSO
  219. ;
  220. ; LOCALE_getbank
  221. ;
  222. ;
  223. ; EXAMPLE
  224. ;
  225. ; locale_eg.c
  226. ;
  227. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  228. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  229. ;
  230. ;
  231. ; END ABSTRACT
  232. ;
  233. */
  234. void LOCALE_setbank(int BankIndex)
  235. {
  236. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  237. if( lx != NULL ) {
  238. lx->BankIndex = BankIndex;
  239. }
  240. }
  241. /*
  242. ;
  243. ; ABSTRACT
  244. ;
  245. ; LOCALE_getbank - Get the current bank
  246. ;
  247. ;
  248. ; SUMMARY
  249. ;
  250. ; #include "realfont.h"
  251. ;
  252. ; int LOCALE_getbank(void)
  253. ;
  254. ; DESCRIPTION
  255. ;
  256. ; Returns the bank index of the current bank.
  257. ;
  258. ; SEE ALSO
  259. ;
  260. ; LOCALE_setbank
  261. ;
  262. ;
  263. ; EXAMPLE
  264. ;
  265. ; locale_eg.c
  266. ;
  267. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  268. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  269. ;
  270. ;
  271. ; END ABSTRACT
  272. ;
  273. */
  274. int LOCALE_getbank(void)
  275. {
  276. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  277. if( lx != NULL ) {
  278. return lx->BankIndex;
  279. } else {
  280. return -1;
  281. }
  282. }
  283. /*
  284. ;
  285. ; ABSTRACT
  286. ;
  287. ; LOCALE_getbanklanguageid - Get the language id for the current bank
  288. ;
  289. ;
  290. ; SUMMARY
  291. ;
  292. ; #include "realfont.h"
  293. ;
  294. ; int LOCALE_getbanklanguageid(void)
  295. ;
  296. ; DESCRIPTION
  297. ;
  298. ; Returns the language id of the current bank. This id will match
  299. ; the lanugage id in the header file generated by Locomoto
  300. ;
  301. ; SEE ALSO
  302. ;
  303. ; LOCALE_loadtable
  304. ;
  305. ; EXAMPLE
  306. ;
  307. ; locale_eg.c
  308. ;
  309. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  310. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  311. ;
  312. ;
  313. ; END ABSTRACT
  314. ;
  315. */
  316. int LOCALE_getbanklanguageid(void)
  317. {
  318. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  319. ASSERT(lx->pBank[lx->BankIndex]); /* must load a table into bank before calling this function */
  320. if( lx != NULL && lx->pBank[lx->BankIndex] != NULL ) {
  321. return (int)(lx->pBank[lx->BankIndex]->LanguageID);
  322. } else {
  323. return -1;
  324. }
  325. }
  326. /*
  327. ;
  328. ; ABSTRACT
  329. ;
  330. ; LOCALE_getbankstringcount - Get the string count for the current bank
  331. ;
  332. ;
  333. ; SUMMARY
  334. ;
  335. ; #include "realfont.h"
  336. ;
  337. ; int LOCALE_getbankstringcount(void)
  338. ;
  339. ; DESCRIPTION
  340. ;
  341. ; Returns the number of strings in the current bank. If zero is
  342. ; returned then this bank is empty.
  343. ;
  344. ; SEE ALSO
  345. ;
  346. ; LOCALE_loadtable
  347. ;
  348. ; EXAMPLE
  349. ;
  350. ; locale_eg.c
  351. ;
  352. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  353. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  354. ;
  355. ;
  356. ; END ABSTRACT
  357. ;
  358. */
  359. int LOCALE_getbankstringcount(void)
  360. {
  361. int StringCount = 0;
  362. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  363. if (lx != NULL && lx->pBank[lx->BankIndex]) {
  364. StringCount = lx->pBank[lx->BankIndex]->StringCount;
  365. }
  366. return StringCount;
  367. }
  368. /*************************************************************************/
  369. /* operations */
  370. /*************************************************************************/
  371. /*
  372. ;
  373. ; ABSTRACT
  374. ;
  375. ; LOCALE_loadtable - Load a string table into the current bank
  376. ;
  377. ;
  378. ; SUMMARY
  379. ;
  380. ; #include "realfont.h"
  381. ;
  382. ; int LOCALE_loadtable(pathname, languageid)
  383. ;
  384. ; const char* pathname; // pathname of .loc file to load
  385. ; int languageid; // language id to load (from .h file)
  386. ;
  387. ; DESCRIPTION
  388. ;
  389. ; Loads the specified language from the string file into the
  390. ; current bank. Returns non zero if the operation was succesful.
  391. ; The bank must be free before you can call LOCALE_loadtable. To
  392. ; free a bank use the LOCALE_freetable function. To determine
  393. ; if the bank is free use the LOCALE_getbankstringcount function.
  394. ;
  395. ; The languageid value is available in the .h file created by
  396. ; locomoto.
  397. ;
  398. ; Returns non-zero if everthing is ok.
  399. ;
  400. ; SEE ALSO
  401. ;
  402. ; LOCALE_freetable, LOCALE_getbankstringcount
  403. ;
  404. ; EXAMPLE
  405. ;
  406. ; locale_eg.c
  407. ;
  408. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  409. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  410. ;
  411. ;
  412. ; END ABSTRACT
  413. ;
  414. */
  415. static int readheader( GSTREAM* g )
  416. {
  417. int ok = 0;
  418. /* read file header */
  419. LOCALEFILE_HEADERCHUNK header;
  420. int HeaderChunkSize = sizeof(LOCALEFILE_HEADERCHUNK);
  421. // VERIFY(gread(g, &header, HeaderChunkSize) == HeaderChunkSize);
  422. if( gread(g, &header, HeaderChunkSize) != HeaderChunkSize ) {
  423. return ok;
  424. }
  425. ASSERT( header.ChunkID == LOCALEFILE_HEADERCHUNKID ); /* ensure that this is a valid .loc file */
  426. if ( header.ChunkID != LOCALEFILE_HEADERCHUNKID ) {
  427. return ok;
  428. }
  429. /* read index chunk if present */
  430. if ( header.Flags == 1 ) {
  431. int IndexChunkSize;
  432. int IndexChunkPos = header.ChunkSize;
  433. /* read index chunk size */
  434. // VERIFY(gseek(g, IndexChunkPos + 4));
  435. if( !gseek( g, IndexChunkPos + 4)) {
  436. return ok;
  437. }
  438. // VERIFY(gread(g, &IndexChunkSize, 4) == 4);
  439. if( gread( g, &IndexChunkSize, 4) != 4 ) {
  440. return ok;
  441. }
  442. /* alloc and read index chunk */
  443. lx->pIndex[lx->BankIndex] = (LOCALEFILE_INDEXCHUNK *)galloc((long)IndexChunkSize );
  444. if (lx->pIndex[lx->BankIndex]) {
  445. // VERIFY(gseek(g, IndexChunkPos));
  446. gseek( g, IndexChunkPos );
  447. // VERIFY(gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize) == IndexChunkSize);
  448. if ( gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize ) != IndexChunkSize ) {
  449. return ok;
  450. }
  451. ASSERT( lx->pIndex[lx->BankIndex]->ChunkID == LOCALEFILE_INDEXCHUNKID );
  452. if( lx->pIndex[lx->BankIndex]->ChunkID == LOCALEFILE_INDEXCHUNKID ) {
  453. ok = 1;
  454. }
  455. }
  456. }
  457. return ok;
  458. }
  459. /////////////////////////////////////////////////////////////////////////////
  460. //
  461. // readstrings
  462. //
  463. /////////////////////////////////////////////////////////////////////////////
  464. static int readstrings( GSTREAM* g, int LanguageID )
  465. {
  466. int ok = 0;
  467. int LanguageChunkOffsetPos = 16 + LanguageID*4;
  468. int LanguageChunkPos = 0;
  469. int LanguageChunkSize = -1;
  470. /* read offset to language chunk */
  471. // VERIFY(gseek(g, (int)LanguageChunkOffsetPos));
  472. // VERIFY(gread(g, &LanguageChunkPos, 4) == 4);
  473. if( !gseek( g, (int)LanguageChunkOffsetPos )) {
  474. return ok;
  475. }
  476. if( gread( g, &LanguageChunkPos, 4 ) != 4 ) {
  477. return ok;
  478. }
  479. /* read language chunk size */
  480. // VERIFY(gseek(g, LanguageChunkPos + 4));
  481. // VERIFY(gread(g, &LanguageChunkSize, 4) == 4);
  482. if( !gseek( g, LanguageChunkPos + 4 )) {
  483. return ok;
  484. }
  485. if( gread( g, &LanguageChunkSize, 4 ) != 4 ) {
  486. return ok;
  487. }
  488. /* alloc and read language chunk */
  489. lx->pBank[lx->BankIndex] = (LOCALEFILE_LANGUAGECHUNK *)galloc((long)LanguageChunkSize);
  490. if (lx->pBank[lx->BankIndex]) {
  491. // VERIFY(gseek(g, LanguageChunkPos));
  492. // VERIFY(gread(g, lx->pBank[lx->BankIndex], LanguageChunkSize) == LanguageChunkSize);
  493. if( !gseek( g, LanguageChunkPos )) {
  494. return ok;
  495. }
  496. if( gread( g, lx->pBank[lx->BankIndex], LanguageChunkSize ) != LanguageChunkSize ) {
  497. return ok;
  498. }
  499. ASSERT(lx->pBank[lx->BankIndex]->ChunkID == LOCALEFILE_LANGUAGECHUNKID);
  500. ok = 1;
  501. }
  502. return ok;
  503. }
  504. /////////////////////////////////////////////////////////////////////////////
  505. //
  506. // LOCALE_loadtable
  507. //
  508. /////////////////////////////////////////////////////////////////////////////
  509. int LOCALE_loadtable( const char* PathName, int LanguageID )
  510. {
  511. int ok = 0;
  512. GSTREAM* g;
  513. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  514. ASSERT(lx->pBank[lx->BankIndex] == NULL); /* bank must be empty before loading a new table */
  515. ASSERT(lx->pIndex[lx->BankIndex] == NULL); /* bank must be empty before loading a new table */
  516. if ( !LOCALE_isinitialized())
  517. return ok;
  518. if( lx->pBank[lx->BankIndex] != NULL)
  519. return ok;
  520. if( lx->pIndex[lx->BankIndex] != NULL)
  521. return ok;
  522. g = gopen( PathName );
  523. if( g != NULL ) {
  524. if( readheader(g)) {
  525. ok = readstrings( g, LanguageID );
  526. }
  527. gclose(g);
  528. }
  529. return ok;
  530. }
  531. /*
  532. ;
  533. ; ABSTRACT
  534. ;
  535. ; LOCALE_purgetable - OBSOLETE
  536. ;
  537. ; Make all references to LOCALE_freetable
  538. ;
  539. ; END ABSTRACT
  540. ;
  541. */
  542. /*
  543. ;
  544. ; ABSTRACT
  545. ;
  546. ; LOCALE_freetable - Free the string table in the current bank
  547. ;
  548. ;
  549. ; SUMMARY
  550. ;
  551. ; #include "realfont.h"
  552. ;
  553. ; void LOCALE_freetable(void)
  554. ;
  555. ; DESCRIPTION
  556. ;
  557. ; Frees the table loaded in the current bank. There must be a
  558. ; table loaded in the current bank. Use LOCALE_getbankstringcount
  559. ; to determine if the bank is free or not.
  560. ;
  561. ; SEE ALSO
  562. ;
  563. ; LOCALE_loadtable, LOCALE_getbankstringcount
  564. ;
  565. ; EXAMPLE
  566. ;
  567. ; locale_eg.c
  568. ;
  569. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  570. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  571. ;
  572. ;
  573. ; END ABSTRACT
  574. ;
  575. */
  576. void LOCALE_freetable(void)
  577. {
  578. if( lx != NULL ) {
  579. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  580. ASSERT(lx->pBank[lx->BankIndex]); /* table must be loaded before calling this function */
  581. /* free string bank */
  582. if( lx->pBank[lx->BankIndex] != NULL ) {
  583. gfree(lx->pBank[lx->BankIndex]);
  584. lx->pBank[lx->BankIndex] = NULL;
  585. }
  586. /* if the bank has an index loaded, free that as well */
  587. if ( lx->pIndex[lx->BankIndex] != NULL ) {
  588. gfree(lx->pIndex[lx->BankIndex]);
  589. lx->pIndex[lx->BankIndex] = NULL;
  590. }
  591. }
  592. }
  593. /*
  594. ;
  595. ; ABSTRACT
  596. ;
  597. ; LOCALE_getstring - Return the specified string from the current bank
  598. ;
  599. ; SUMMARY
  600. ;
  601. ; #include "realfont.h"
  602. ;
  603. ; const char* LOCALE_getstring( StringID )
  604. ; int StringID; ID of string to return
  605. ;
  606. ; DESCRIPTION
  607. ;
  608. ; Returns the string specified from the current bank. There must
  609. ; be a string table loaded into the current bank. Use the String
  610. ; ID specified in the header file created by Locomoto. Note that
  611. ; the string pointer is a const pointer. Do not modify the string
  612. ; or the Locale library may return invalid results.
  613. ;
  614. ; If the .loc file was created with an index StringID can be any
  615. ; valid integer in the range 0..65535. If no index was created
  616. ; with the .loc file StringID will be a zero based array index.
  617. ;
  618. ; String is returned by const for a reason. Bad things will happen
  619. ; if you modify it. You have been warned.
  620. ;
  621. ; SEE ALSO
  622. ;
  623. ; LOCALE_loadtable, LOCALE_getbankstringcount
  624. ;
  625. ; EXAMPLE
  626. ;
  627. ; locale_eg.c
  628. ;
  629. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  630. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  631. ;
  632. ;
  633. ; END ABSTRACT
  634. ;
  635. */
  636. #include <stdlib.h> // for bsearch function
  637. /////////////////////////////////////////////////////////////////////////////
  638. //
  639. // compare
  640. //
  641. /////////////////////////////////////////////////////////////////////////////
  642. static int compare ( const void* arg1, const void* arg2 )
  643. {
  644. const unsigned short* s1 = (const unsigned short*)(arg1);
  645. const unsigned short* s2 = (const unsigned short*)(arg2);
  646. return (*s1) - (*s2);
  647. }
  648. /////////////////////////////////////////////////////////////////////////////
  649. //
  650. // getstringbyindex
  651. //
  652. /////////////////////////////////////////////////////////////////////////////
  653. static int getstringbyindex( unsigned short key, const INDEX* pIndex )
  654. {
  655. int index = 0;
  656. unsigned short* result;
  657. unsigned char* base; /* pointer to base of string id table */
  658. ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  659. ASSERT(pIndex != NULL); /* index not loaded - .loc file must have index created (use -i option) */
  660. if( !LOCALE_isinitialized())
  661. return -1;
  662. if( pIndex == NULL )
  663. return -1;
  664. base = ((unsigned char*)pIndex) + LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET;
  665. result = (unsigned short*)bsearch((unsigned char *)&key, base, pIndex->StringCount, 4, compare);
  666. if (result != NULL) {
  667. /* index is the second unsigned short */
  668. ++result;
  669. index = *result;
  670. } else {
  671. index = -1;
  672. }
  673. return index;
  674. }
  675. /////////////////////////////////////////////////////////////////////////////
  676. //
  677. // LOCALE_getstring
  678. //
  679. /////////////////////////////////////////////////////////////////////////////
  680. const char* LOCALE_getstring( int StringID )
  681. {
  682. const char* p; /* pointer to string, NULL if string cannot be found */
  683. ASSERT( LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
  684. if( !LOCALE_isinitialized())
  685. return NULL;
  686. /* get string array index from the index if it exists */
  687. if ( lx->pIndex[ lx->BankIndex ] != NULL ) {
  688. StringID = getstringbyindex((unsigned short)StringID, lx->pIndex[lx->BankIndex]);
  689. }
  690. if ((StringID >= 0) && (StringID < (int)(lx->pBank[lx->BankIndex]->StringCount ))) {
  691. unsigned int offset;
  692. p = (const char*)(lx->pBank[lx->BankIndex]);
  693. offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);
  694. p += offset;
  695. } else {
  696. p = NULL;
  697. }
  698. return p;
  699. }
  700. /*
  701. ;
  702. ; ABSTRACT
  703. ;
  704. ; LOCALE_getstr - return selected string from the specified .loc file
  705. ;
  706. ;
  707. ; SUMMARY
  708. ;
  709. ; #include "realfont.h"
  710. ;
  711. ; const char* LOCALE_getstr(stringid)
  712. ;
  713. ; int stringid; // string id to return
  714. ;
  715. ; DESCRIPTION
  716. ;
  717. ; Returns the string identified by stringid from the specified
  718. ; .loc file. Use the string ID specified in the header file created
  719. ; by Locomoto. Note that the string pointer is a const pointer. Do
  720. ; not modify the string or the Locale library may return invalid results.
  721. ;
  722. ; If your strings are Unicode strings, cast the result to a const USTR *.
  723. ;
  724. ; If the .loc file was created with an index stringid can be any
  725. ; valid integer in the range 0..65535. If no index was created
  726. ; with the .loc file stringid will be a zero based array index.
  727. ;
  728. ; String is returned by const for a reason. Bad things will happen
  729. ; if you modify it. You have been warned.
  730. ;
  731. ; SEE ALSO
  732. ;
  733. ; EXAMPLE
  734. ;
  735. ; locale_eg.c
  736. ;
  737. ; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
  738. ; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
  739. ;
  740. ; END ABSTRACT
  741. ;
  742. */
  743. int LOCALElanguageid = 0;
  744. const char* LOCALE_getstr( const void* pLocFile, int StringID )
  745. {
  746. const char* p = NULL; /* pointer to string, NULL if string cannot be found */
  747. HEADER* pHeader;
  748. BANK* pBank;
  749. ASSERT(pLocFile != NULL);
  750. /* Must pass something in */
  751. if( pLocFile == NULL ) {
  752. return p;
  753. }
  754. pHeader = (LOCALEFILE_HEADERCHUNK*)(pLocFile);
  755. ASSERT(pHeader->ChunkID == LOCALEFILE_HEADERCHUNKID);
  756. ASSERT(pHeader->LanguageCount >= 1);
  757. if( pHeader->Flags == 1 ) {
  758. /* file has an index */
  759. INDEX* pIndex = (INDEX*)((unsigned char*)(pLocFile) + pHeader->ChunkSize);
  760. StringID = getstringbyindex((unsigned short)StringID, pIndex);
  761. }
  762. /* get pointer to string bank */
  763. {
  764. int offset = *((int*)(pLocFile) + 4 + LOCALElanguageid);
  765. pBank = (BANK*)((unsigned char*)(pLocFile) + offset);
  766. }
  767. if ((StringID >= 0) && (StringID < (int)(pBank->StringCount))) {
  768. unsigned int offset;
  769. p = (const char*)(pBank);
  770. offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);
  771. p += offset;
  772. } else {
  773. p = NULL;
  774. }
  775. return p;
  776. }