865 lines
22 KiB
C++
865 lines
22 KiB
C++
![]() |
/*
|
||
|
** Command & Conquer Generals Zero Hour(tm)
|
||
|
** Copyright 2025 Electronic Arts Inc.
|
||
|
**
|
||
|
** This program is free software: you can redistribute it and/or modify
|
||
|
** it under the terms of the GNU General Public License as published by
|
||
|
** the Free Software Foundation, either version 3 of the License, or
|
||
|
** (at your option) any later version.
|
||
|
**
|
||
|
** This program is distributed in the hope that it will be useful,
|
||
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
** GNU General Public License for more details.
|
||
|
**
|
||
|
** You should have received a copy of the GNU General Public License
|
||
|
** along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/* Copyright (C) Electronic Arts Canada Inc. 1998-1999. All rights reserved. */
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <assert.h>
|
||
|
#include "gimex.h" /* for file and memory IO only */
|
||
|
#include "locale.h"
|
||
|
#include "wnd_file.h"
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* File Format Structures */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
#define LOCALEFILE_HEADERCHUNKID 0x48434f4c /* 'LOCH' */
|
||
|
#define LOCALEFILE_INDEXCHUNKID 0x49434f4c /* 'LOCI' */
|
||
|
#define LOCALEFILE_LANGUAGECHUNKID 0x4c434f4c /* 'LOCL' */
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned int ChunkID; /* 'LOCH' LOCALEFILE_HEADERCHUNKID */
|
||
|
unsigned int ChunkSize; /* size of chunk in bytes */
|
||
|
unsigned int Flags; /* 0=no index chunk present,1=index chunk present */
|
||
|
unsigned int LanguageCount; /* number of language chunks in this file */
|
||
|
/* unsigned int LanguageOffset[LanguageCount]; \\ offsets in bytes from start of file to language chunk */
|
||
|
} LOCALEFILE_HEADERCHUNK;
|
||
|
|
||
|
/* offset LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET bytes from the start of the chunk to the language offset table */
|
||
|
#define LOCALEFILE_HEADERCHUNK_LANGUAGE_OFFSET sizeof(LOCALEFILE_HEADERCHUNK)
|
||
|
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned int ChunkID; /* 'LOCI' LOCALEFILE_INDEXCHUNKID */
|
||
|
unsigned int ChunkSize; /* size of chunk in bytes */
|
||
|
unsigned int StringCount; /* number of string ids in this chunk (same value in all language chunks) */
|
||
|
unsigned int pad; /* must be zero */
|
||
|
/* STRINGID StringID[StringCount]; */
|
||
|
/* { */
|
||
|
/* unsigned short ID; \\ id that user gives to look up value */
|
||
|
/* unsigned short Index; \\ index to look up value in language chunks */
|
||
|
/* } */
|
||
|
} LOCALEFILE_INDEXCHUNK;
|
||
|
|
||
|
/* offset LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET bytes from the start of the chunk to the string id table */
|
||
|
#define LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET sizeof(LOCALEFILE_INDEXCHUNK)
|
||
|
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
unsigned int ChunkID; /* 'LOCL' LOCALEFILE_LANGUAGECHUNKID */
|
||
|
unsigned int ChunkSize; /* size of chunk in bytes including this header and all string data */
|
||
|
unsigned int LanguageID; /* language strings are in for this bank */
|
||
|
unsigned int StringCount; /* number of strings in this chunk */
|
||
|
/* unsigned int StringOffset[StringCount]; \\ offsets in bytes from start of chunk to string */
|
||
|
/* const char* Data[StringCount]; \\ StringCount null terminated strings */
|
||
|
} LOCALEFILE_LANGUAGECHUNK;
|
||
|
|
||
|
/* offset LOCALEFILE_LANGUAGECHUNK_STRING_OFFSETbytes from the start of the chunk to the string offset table */
|
||
|
#define LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET sizeof(LOCALEFILE_LANGUAGECHUNK)
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* LOCALE_INSTANCE declaration */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
typedef LOCALEFILE_HEADERCHUNK HEADER;
|
||
|
typedef LOCALEFILE_INDEXCHUNK INDEX;
|
||
|
typedef LOCALEFILE_LANGUAGECHUNK BANK;
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int BankIndex; /* current language bank set (0..BANK_COUNT-1) */
|
||
|
BANK* pBank[LOCALE_BANK_COUNT]; /* array of string banks */
|
||
|
INDEX* pIndex[LOCALE_BANK_COUNT]; /* array of string indices */
|
||
|
} LOCALE_INSTANCE;
|
||
|
|
||
|
static LOCALE_INSTANCE *lx = NULL;
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* initialization/restore */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/* helper function to make assertions for initialization clearer */
|
||
|
int LOCALE_isinitialized( void )
|
||
|
{
|
||
|
if ( lx == NULL ) {
|
||
|
// TRACE("LOCALE API is not initialized - call LOCALE_init before calling LOCALE functions\n");
|
||
|
}
|
||
|
return( lx != NULL );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_init - Init the localization module
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; int LOCALE_init(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Initilizes everything needed to use the locale API. Can only be called
|
||
|
; once until LOCALE_restore is called.
|
||
|
;
|
||
|
; Returns non-zero if everything went ok.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_restore
|
||
|
;
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
int LOCALE_init(void)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
|
||
|
/* ensure locale module is NOT already initialized */
|
||
|
ASSERT(lx == NULL); /* can only call LOCALE_init after a restore or once, cannot double init locale API */
|
||
|
|
||
|
/* allocate instance */
|
||
|
lx = (LOCALE_INSTANCE*)galloc(sizeof(LOCALE_INSTANCE));
|
||
|
if (lx != NULL) {
|
||
|
memset(lx, 0, sizeof(LOCALE_INSTANCE));
|
||
|
ok = 1;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_restore - Free resources used by the locale module
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; void LOCALE_restore(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Restores all resources used by the locale API. Can only be called after
|
||
|
; LOCALE_init, and only once.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_init
|
||
|
;
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
void LOCALE_restore(void)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if( lx != NULL ) {
|
||
|
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
ASSERT(lx != NULL);
|
||
|
|
||
|
/* free any language tables */
|
||
|
for (i = 0; i < LOCALE_BANK_COUNT; i++) {
|
||
|
if (lx->pBank[i]) {
|
||
|
LOCALE_setbank(i);
|
||
|
LOCALE_freetable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* free instance */
|
||
|
gfree(lx);
|
||
|
lx = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* attributes */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_setbank - Set the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; void LOCALE_setbank(BankIndex)
|
||
|
; int BankIndex; Number between 0 and LOCALE_BANK_COUNT - 1
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Sets the current bank to be active. All functions will now use this
|
||
|
; bank for strings. A bank is slot where a string table is loaded.
|
||
|
; More than one bank can have a table loaded but the locale functions
|
||
|
; only work on one bank at a time, the active bank set by this function.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_getbank
|
||
|
;
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
void LOCALE_setbank(int BankIndex)
|
||
|
{
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
lx->BankIndex = BankIndex;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_getbank - Get the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; int LOCALE_getbank(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Returns the bank index of the current bank.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_setbank
|
||
|
;
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
int LOCALE_getbank(void)
|
||
|
{
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
return lx->BankIndex;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_getbanklanguageid - Get the language id for the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; int LOCALE_getbanklanguageid(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Returns the language id of the current bank. This id will match
|
||
|
; the lanugage id in the header file generated by Locomoto
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_loadtable
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
int LOCALE_getbanklanguageid(void)
|
||
|
{
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
ASSERT(lx->pBank[lx->BankIndex]); /* must load a table into bank before calling this function */
|
||
|
return (int)(lx->pBank[lx->BankIndex]->LanguageID);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_getbankstringcount - Get the string count for the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; int LOCALE_getbankstringcount(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Returns the number of strings in the current bank. If zero is
|
||
|
; returned then this bank is empty.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_loadtable
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
int LOCALE_getbankstringcount(void)
|
||
|
{
|
||
|
int StringCount = 0;
|
||
|
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
if (lx->pBank[lx->BankIndex]) {
|
||
|
StringCount = lx->pBank[lx->BankIndex]->StringCount;
|
||
|
}
|
||
|
return StringCount;
|
||
|
}
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* operations */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_loadtable - Load a string table into the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; int LOCALE_loadtable(pathname, languageid)
|
||
|
;
|
||
|
; const char* pathname; // pathname of .loc file to load
|
||
|
; int languageid; // language id to load (from .h file)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Loads the specified language from the string file into the
|
||
|
; current bank. Returns non zero if the operation was succesful.
|
||
|
; The bank must be free before you can call LOCALE_loadtable. To
|
||
|
; free a bank use the LOCALE_freetable function. To determine
|
||
|
; if the bank is free use the LOCALE_getbankstringcount function.
|
||
|
;
|
||
|
; The languageid value is available in the .h file created by
|
||
|
; locomoto.
|
||
|
;
|
||
|
; Returns non-zero if everthing is ok.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_freetable, LOCALE_getbankstringcount
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
static int readheader( GSTREAM* g )
|
||
|
{
|
||
|
int ok = 0;
|
||
|
|
||
|
/* read file header */
|
||
|
LOCALEFILE_HEADERCHUNK header;
|
||
|
int HeaderChunkSize = sizeof(LOCALEFILE_HEADERCHUNK);
|
||
|
|
||
|
// VERIFY(gread(g, &header, HeaderChunkSize) == HeaderChunkSize);
|
||
|
if( gread(g, &header, HeaderChunkSize) != HeaderChunkSize ) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readheader - HeaderChunkSize = %d.", HeaderChunkSize );
|
||
|
Msg( __LINE__, __FILE__, "readheader - header.LanguageCount = %d.", header.LanguageCount );
|
||
|
Msg( __LINE__, __FILE__, "readheader - header.Flags = %d.", header.Flags );
|
||
|
|
||
|
ASSERT( header.ChunkID == LOCALEFILE_HEADERCHUNKID ); /* ensure that this is a valid .loc file */
|
||
|
|
||
|
/* read index chunk if present */
|
||
|
if ( header.Flags == 1 ) {
|
||
|
|
||
|
int IndexChunkSize;
|
||
|
int IndexChunkPos = header.ChunkSize;
|
||
|
|
||
|
/* read index chunk size */
|
||
|
// VERIFY(gseek(g, IndexChunkPos + 4));
|
||
|
if( !gseek( g, IndexChunkPos + 4)) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readheader - seek to = %d.", IndexChunkPos + 4 );
|
||
|
|
||
|
// VERIFY(gread(g, &IndexChunkSize, 4) == 4);
|
||
|
if( gread( g, &IndexChunkSize, 4) != 4 ) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readheader - IndexChunkSize = %d.", IndexChunkSize );
|
||
|
|
||
|
/* alloc and read index chunk */
|
||
|
lx->pIndex[lx->BankIndex] = (LOCALEFILE_INDEXCHUNK *)galloc((long)IndexChunkSize );
|
||
|
if (lx->pIndex[lx->BankIndex]) {
|
||
|
|
||
|
// VERIFY(gseek(g, IndexChunkPos));
|
||
|
gseek( g, IndexChunkPos );
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readheader - seek to = %d.", IndexChunkPos );
|
||
|
|
||
|
// VERIFY(gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize) == IndexChunkSize);
|
||
|
if ( gread(g, lx->pIndex[lx->BankIndex], IndexChunkSize ) != IndexChunkSize ) {
|
||
|
return ok;
|
||
|
}
|
||
|
Msg( __LINE__, __FILE__, "readheader - IndexChunkSize = %d.", IndexChunkSize );
|
||
|
|
||
|
ASSERT( lx->pIndex[lx->BankIndex]->ChunkID == LOCALEFILE_INDEXCHUNKID );
|
||
|
|
||
|
ok = 1;
|
||
|
}
|
||
|
}
|
||
|
Msg( __LINE__, __FILE__, "readheader - exiting." );
|
||
|
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
static int readstrings( GSTREAM* g, int LanguageID )
|
||
|
{
|
||
|
Msg( __LINE__, __FILE__, "readstrings:: g ok? %d.", ((g!= NULL)?1:0));
|
||
|
|
||
|
int ok = 0;
|
||
|
|
||
|
int LanguageChunkOffsetPos = 16 + LanguageID*4;
|
||
|
int LanguageChunkPos = 0;
|
||
|
int LanguageChunkSize = -1;
|
||
|
|
||
|
/* read offset to language chunk */
|
||
|
// VERIFY(gseek(g, (int)LanguageChunkOffsetPos));
|
||
|
// VERIFY(gread(g, &LanguageChunkPos, 4) == 4);
|
||
|
if( !gseek( g, (int)LanguageChunkOffsetPos )) {
|
||
|
return ok;
|
||
|
}
|
||
|
if( gread( g, &LanguageChunkPos, 4 ) != 4 ) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
/* read language chunk size */
|
||
|
// VERIFY(gseek(g, LanguageChunkPos + 4));
|
||
|
// VERIFY(gread(g, &LanguageChunkSize, 4) == 4);
|
||
|
if( !gseek( g, LanguageChunkPos + 4 )) {
|
||
|
return ok;
|
||
|
}
|
||
|
if( gread( g, &LanguageChunkSize, 4 ) != 4 ) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readstrings::LanguageChunkOffsetPos = %d.", LanguageChunkOffsetPos );
|
||
|
Msg( __LINE__, __FILE__, "readstrings::LanguageChunkPos = %d.", LanguageChunkPos );
|
||
|
Msg( __LINE__, __FILE__, "readstrings::LanguageChunkSize = %d.", LanguageChunkSize );
|
||
|
|
||
|
/* alloc and read language chunk */
|
||
|
lx->pBank[lx->BankIndex] = (LOCALEFILE_LANGUAGECHUNK *)galloc((long)LanguageChunkSize);
|
||
|
if (lx->pBank[lx->BankIndex]) {
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "readstrings:: A." );
|
||
|
|
||
|
// VERIFY(gseek(g, LanguageChunkPos));
|
||
|
// VERIFY(gread(g, lx->pBank[lx->BankIndex], LanguageChunkSize) == LanguageChunkSize);
|
||
|
if( !gseek( g, LanguageChunkPos )) {
|
||
|
return ok;
|
||
|
}
|
||
|
if( gread( g, lx->pBank[lx->BankIndex], LanguageChunkSize ) != LanguageChunkSize ) {
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
ASSERT(lx->pBank[lx->BankIndex]->ChunkID == LOCALEFILE_LANGUAGECHUNKID);
|
||
|
ok = 1;
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
int LOCALE_loadtable(const char* PathName, int LanguageID)
|
||
|
{
|
||
|
int ok = 0;
|
||
|
GSTREAM* g;
|
||
|
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
ASSERT(lx->pBank[lx->BankIndex] == NULL); /* bank must be empty before loading a new table */
|
||
|
ASSERT(lx->pIndex[lx->BankIndex] == NULL); /* bank must be empty before loading a new table */
|
||
|
|
||
|
g = gopen( PathName );
|
||
|
if( g != NULL ) {
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "LOCALE_loadtable-- file opened." );
|
||
|
|
||
|
if( readheader(g)) {
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "LOCALE_loadtable-- readstrings." );
|
||
|
|
||
|
ok = readstrings( g, LanguageID );
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "LOCALE_loadtable-- ok = %d ).", ok );
|
||
|
}
|
||
|
gclose(g);
|
||
|
}
|
||
|
return ok;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_purgetable - OBSOLETE
|
||
|
;
|
||
|
; Make all references to LOCALE_freetable
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_freetable - Free the string table in the current bank
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; void LOCALE_freetable(void)
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Frees the table loaded in the current bank. There must be a
|
||
|
; table loaded in the current bank. Use LOCALE_getbankstringcount
|
||
|
; to determine if the bank is free or not.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_loadtable, LOCALE_getbankstringcount
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
void LOCALE_freetable(void)
|
||
|
{
|
||
|
if( lx != NULL ) {
|
||
|
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
ASSERT(lx->pBank[lx->BankIndex]); /* table must be loaded before calling this function */
|
||
|
|
||
|
/* free string bank */
|
||
|
gfree(lx->pBank[lx->BankIndex]);
|
||
|
lx->pBank[lx->BankIndex] = NULL;
|
||
|
|
||
|
/* if the bank has an index loaded, free that as well */
|
||
|
if (lx->pIndex[lx->BankIndex]) {
|
||
|
gfree(lx->pIndex[lx->BankIndex]);
|
||
|
lx->pIndex[lx->BankIndex] = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_getstring - Return the specified string from the current bank
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; const char* LOCALE_getstring( StringID )
|
||
|
; int StringID; ID of string to return
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Returns the string specified from the current bank. There must
|
||
|
; be a string table loaded into the current bank. Use the String
|
||
|
; ID specified in the header file created by Locomoto. Note that
|
||
|
; the string pointer is a const pointer. Do not modify the string
|
||
|
; or the Locale library may return invalid results.
|
||
|
;
|
||
|
; If the .loc file was created with an index StringID can be any
|
||
|
; valid integer in the range 0..65535. If no index was created
|
||
|
; with the .loc file StringID will be a zero based array index.
|
||
|
;
|
||
|
; String is returned by const for a reason. Bad things will happen
|
||
|
; if you modify it. You have been warned.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; LOCALE_loadtable, LOCALE_getbankstringcount
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h> // for bsearch function
|
||
|
|
||
|
static int compare ( const void* arg1, const void* arg2 )
|
||
|
{
|
||
|
const unsigned short* s1 = (const unsigned short*)(arg1);
|
||
|
const unsigned short* s2 = (const unsigned short*)(arg2);
|
||
|
return (*s1) - (*s2);
|
||
|
}
|
||
|
|
||
|
static int getstringbyindex( unsigned short key, const INDEX* pIndex )
|
||
|
{
|
||
|
int index = 0;
|
||
|
unsigned short* result;
|
||
|
unsigned char* base; /* pointer to base of string id table */
|
||
|
|
||
|
ASSERT(LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
ASSERT(pIndex != NULL); /* index not loaded - .loc file must have index created (use -i option) */
|
||
|
|
||
|
base = ((unsigned char*)pIndex) + LOCALEFILE_INDEXCHUNK_STRINGID_OFFSET;
|
||
|
result = (unsigned short*)bsearch((unsigned char *)&key, base, pIndex->StringCount, 4, compare);
|
||
|
|
||
|
if (result != NULL) {
|
||
|
/* index is the second unsigned short */
|
||
|
++result;
|
||
|
index = *result;
|
||
|
} else {
|
||
|
index = -1;
|
||
|
}
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
const char* LOCALE_getstring( int StringID )
|
||
|
{
|
||
|
const char* p; /* pointer to string, NULL if string cannot be found */
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring::( %d ).", StringID );
|
||
|
|
||
|
ASSERT( LOCALE_isinitialized()); /* must call LOCALE_init before calling this function */
|
||
|
|
||
|
/* get string array index from the index if it exists */
|
||
|
if ( lx->pIndex[ lx->BankIndex ] != NULL ) {
|
||
|
StringID = getstringbyindex((unsigned short)StringID, lx->pIndex[lx->BankIndex]);
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring::( %d ).", StringID );
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring::( lx->BankIndex = %d ).", lx->BankIndex );
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring::( lx->pBank[lx->BankIndex]->StringCount = %d ).", lx->pBank[lx->BankIndex]->StringCount );
|
||
|
|
||
|
if ((StringID >= 0) && (StringID < (int)(lx->pBank[lx->BankIndex]->StringCount ))) {
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring:: A" );
|
||
|
|
||
|
unsigned int offset;
|
||
|
|
||
|
p = (const char*)(lx->pBank[lx->BankIndex]);
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring:: B" );
|
||
|
|
||
|
offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring:: C" );
|
||
|
|
||
|
p += offset;
|
||
|
|
||
|
Msg( __LINE__, __FILE__, "Locale_getstring:: D" );
|
||
|
|
||
|
|
||
|
} else {
|
||
|
p = NULL;
|
||
|
}
|
||
|
|
||
|
Msg( __LINE__, __FILE__, L"%s", 1252, (wchar_t *)p );
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
;
|
||
|
; ABSTRACT
|
||
|
;
|
||
|
; LOCALE_getstr - return selected string from the specified .loc file
|
||
|
;
|
||
|
;
|
||
|
; SUMMARY
|
||
|
;
|
||
|
; #include "realfont.h"
|
||
|
;
|
||
|
; const char* LOCALE_getstr(stringid)
|
||
|
;
|
||
|
; int stringid; // string id to return
|
||
|
;
|
||
|
; DESCRIPTION
|
||
|
;
|
||
|
; Returns the string identified by stringid from the specified
|
||
|
; .loc file. Use the string ID specified in the header file created
|
||
|
; by Locomoto. Note that the string pointer is a const pointer. Do
|
||
|
; not modify the string or the Locale library may return invalid results.
|
||
|
;
|
||
|
; If your strings are Unicode strings, cast the result to a const USTR *.
|
||
|
;
|
||
|
; If the .loc file was created with an index stringid can be any
|
||
|
; valid integer in the range 0..65535. If no index was created
|
||
|
; with the .loc file stringid will be a zero based array index.
|
||
|
;
|
||
|
; String is returned by const for a reason. Bad things will happen
|
||
|
; if you modify it. You have been warned.
|
||
|
;
|
||
|
; SEE ALSO
|
||
|
;
|
||
|
; EXAMPLE
|
||
|
;
|
||
|
; locale_eg.c
|
||
|
;
|
||
|
; <HTML A HREF="locale_eg.c">Download the source<HTML /A>
|
||
|
; <HTML A HREF="locale_eg.csv">locale_eg.csv<HTML /A> (example data)
|
||
|
;
|
||
|
; END ABSTRACT
|
||
|
;
|
||
|
*/
|
||
|
|
||
|
int LOCALElanguageid = 0;
|
||
|
|
||
|
const char* LOCALE_getstr( const void* pLocFile, int StringID )
|
||
|
{
|
||
|
const char* p; /* pointer to string, NULL if string cannot be found */
|
||
|
|
||
|
HEADER* pHeader;
|
||
|
BANK* pBank;
|
||
|
|
||
|
ASSERT(pLocFile != NULL);
|
||
|
|
||
|
pHeader = (LOCALEFILE_HEADERCHUNK*)(pLocFile);
|
||
|
ASSERT(pHeader->ChunkID == LOCALEFILE_HEADERCHUNKID);
|
||
|
ASSERT(pHeader->LanguageCount >= 1);
|
||
|
|
||
|
if( pHeader->Flags == 1 ) {
|
||
|
|
||
|
/* file has an index */
|
||
|
INDEX* pIndex = (INDEX*)((unsigned char*)(pLocFile) + pHeader->ChunkSize);
|
||
|
StringID = getstringbyindex((unsigned short)StringID, pIndex);
|
||
|
}
|
||
|
|
||
|
/* get pointer to string bank */
|
||
|
{
|
||
|
int offset = *((int*)(pLocFile) + 4 + LOCALElanguageid);
|
||
|
pBank = (BANK*)((unsigned char*)(pLocFile) + offset);
|
||
|
}
|
||
|
|
||
|
if ((StringID >= 0) && (StringID < (int)(pBank->StringCount))) {
|
||
|
|
||
|
unsigned int offset;
|
||
|
|
||
|
p = (const char*)(pBank);
|
||
|
offset = *(unsigned int*)(p + LOCALEFILE_LANGUAGECHUNK_STRING_OFFSET + StringID*4);
|
||
|
p += offset;
|
||
|
|
||
|
} else {
|
||
|
p = NULL;
|
||
|
}
|
||
|
|
||
|
return p;
|
||
|
}
|
||
|
|