locale.cpp 22 KB

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