Serious-Engine/Sources/Engine/Base/Translation.cpp

223 lines
5.7 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "Engine/StdH.h"
#include <Engine/Base/CTString.h>
#include <Engine/Base/Translation.h>
#include <Engine/Base/TranslationPair.h>
#include <Engine/Base/Input.h>
#include <Engine/Templates/NameTable_CTranslationPair.h>
#include <Engine/Base/Memory.h>
#include <Engine/Base/Stream.h>
#include <Engine/Base/Console.h>
#include <Engine/Templates/DynamicArray.cpp>
// table of translations
static CNameTable_CTranslationPair _nttpPairs;
static CDynamicArray<CTranslationPair> _atpPairs;
static int _iLine;
#define CHAR_EOF -1
#define CHAR_SRC -2
#define CHAR_DST -3
static int ReadOneChar_t(CTStream &strm)
{
// skip line breaks and count them
unsigned char c;
do {
strm>>c;
if (c=='\n') {
_iLine++;
}
} while (c=='\n' || c=='\r');
// if start of control token
if (c=='\\') {
// read next char
strm>>c;
// decode token
switch (c) {
case '\\': return '\\';
// eol
case 'n': return '\n';
// string end
case '0': return 0;
// source string
case '<': return CHAR_SRC;
// destination string
case '>': return CHAR_DST;
// file end
case '$': return CHAR_EOF;
// other
default:
if (isprint(c)) {
ThrowF_t(TRANS("%d: unknown token '%c'"), _iLine, c);
} else {
ThrowF_t(TRANS("%d: unknown token ascii: 0x%02x"), _iLine, c);
}
}
}
return c;
}
// read one translation string from file
static CTString ReadOneString_t(CTStream &strm)
{
// start with empty string
CTString str;
// read characters
FOREVER{
int i = ReadOneChar_t(strm);
if (i==0) {
return str;
} else {
char c[2];
c[1] = 0;
c[0] = i;
str+=c;
}
}
}
// init translation routines with given translation table
ENGINE_API void InitTranslation(void)
{
// init tables
_atpPairs.Clear();
_nttpPairs.Clear();
_nttpPairs.SetAllocationParameters(100, 5, 5);
}
ENGINE_API void ReadTranslationTable_t(
CDynamicArray<CTranslationPair> &atpPairs, const CTFileName &fnmTable) // throw char *
{
_iLine = 0;
CTFileStream strm;
strm.Open_t(fnmTable);
// read number of pairs
INDEX ctPairs;
CTString strPairs = ReadOneString_t(strm);
strPairs.ScanF("%d", &ctPairs);
// instance that much
CTranslationPair *atp = atpPairs.New(ctPairs);
// for each pair
for(INDEX iPair=0; iPair<ctPairs; iPair++) {
CTranslationPair &tp = atp[iPair];
// read one token
int iToken = ReadOneChar_t(strm);
// otherwise it must be source
if (iToken!=CHAR_SRC) {
if (iToken==CHAR_EOF) {
ThrowF_t(TRANS("error in file <%s>, premature EOF in line #%d!"),
(const char *)fnmTable, _iLine);
} else {
ThrowF_t(TRANS("error in file <%s>, line #%d (pair #%d): expected '<' but found '%c'"),
(const char *)fnmTable, _iLine, iPair, iToken);
}
}
// read source
tp.tp_strSrc = ReadOneString_t(strm);
// next token must be destination
if (ReadOneChar_t(strm)!=CHAR_DST) {
if (iToken==CHAR_EOF) {
ThrowF_t(TRANS("error in file <%s>, premature EOF in line #%d!"),
(const char *)fnmTable, _iLine);
} else {
ThrowF_t(TRANS("error in file <%s>, line #%d (pair #%d): expected '>' but found '%c'"),
(const char *)fnmTable, _iLine, iPair, iToken);
}
}
// read destination
tp.tp_strDst = ReadOneString_t(strm);
};
// last token must be eof
if (ReadOneChar_t(strm)!=CHAR_EOF) {
ThrowF_t(TRANS("error in file <%s>: end of file marker not found in line #%d!"), (const char *)fnmTable, _iLine);
}
}
// finish translation table building
ENGINE_API void FinishTranslationTable(void)
{
INDEX ctPairs = _atpPairs.Count();
// for each pair
_atpPairs.Lock();
for(INDEX iPair=0; iPair<ctPairs; iPair++) {
// add pair to name table
_nttpPairs.Add(&_atpPairs[iPair]);
};
_atpPairs.Unlock();
_pInput->SetKeyNames();
}
// add given translation table
ENGINE_API void AddTranslationTable_t(const CTFileName &fnmTable) // throw char *
{
// just read it to global array
ReadTranslationTable_t(_atpPairs, fnmTable);
}
// add several tables from a directory using wildcards
ENGINE_API void AddTranslationTablesDir_t(const CTFileName &fnmDir, const CTFileName &fnmPattern) // throw char *
{
// list the translation tables matching given pattern
CDynamicStackArray<CTFileName> afnmTables;
MakeDirList(afnmTables, fnmDir, fnmPattern, 0);
for(INDEX i=0; i<afnmTables.Count(); i++) {
ReadTranslationTable_t(_atpPairs, afnmTables[i]);
}
}
// !!! FIXME: clean these out.
// translate a string
ENGINE_API char *Translate(const char *str, INDEX iOffset)
{
return (char*)TranslateConst(str, iOffset);
}
ENGINE_API const char *TranslateConst(const char *str, INDEX iOffset)
{
// skip first bytes
if (strlen(str)>=iOffset) {
str+=iOffset;
} else {
ASSERT(FALSE);
}
// find translation pair
CTranslationPair *ptp = NULL;
if (_atpPairs.Count()>0) {
ptp = _nttpPairs.Find(str);
}
// if not found
if (ptp==NULL) {
// return original string
return str;
// if found
} else {
// return translation
return ptp->tp_strDst;
}
}