2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code 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 .
Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
# include "precompiled.h"
// This is the default language dict that the entire system uses, but you can instantiate your own idLangDict classes to manipulate a language dictionary in a tool
idLangDict idLocalization : : languageDict ;
idCVar lang_maskLocalizedStrings ( " lang_maskLocalizedStrings " , " 0 " , CVAR_BOOL , " Masks all localized strings to help debugging. When set will replace strings with an equal length of W's and ending in an X. Note: The masking occurs at string table load time. " ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLocalization : : ClearDictionary
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLocalization : : ClearDictionary ( )
{
2012-11-26 18:58:24 +00:00
languageDict . Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLocalization : : LoadDictionary
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLocalization : : LoadDictionary ( const byte * data , int dataLen , const char * fileName )
{
2012-11-26 18:58:24 +00:00
return languageDict . Load ( data , dataLen , fileName ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idLocalization : : GetString
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLocalization : : GetString ( const char * inString )
{
2012-11-26 18:58:24 +00:00
return languageDict . GetString ( inString ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
2012-11-28 15:47:07 +00:00
idLocalization : : FindString
2012-11-26 18:58:24 +00:00
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLocalization : : FindString ( const char * inString )
{
2012-11-26 18:58:24 +00:00
return languageDict . FindString ( inString ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLocalization : : VerifyUTF8
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
utf8Encoding_t idLocalization : : VerifyUTF8 ( const uint8 * buffer , const int bufferLen , const char * name )
{
2012-11-26 18:58:24 +00:00
utf8Encoding_t encoding ;
idStr : : IsValidUTF8 ( buffer , bufferLen , encoding ) ;
2012-11-28 15:47:07 +00:00
if ( encoding = = UTF8_INVALID )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " Language file %s is not valid UTF-8 or plain ASCII. " , name ) ;
2012-11-28 15:47:07 +00:00
}
else if ( encoding = = UTF8_INVALID_BOM )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " Language file %s is marked as UTF-8 but has invalid encoding. " , name ) ;
2012-11-28 15:47:07 +00:00
}
else if ( encoding = = UTF8_ENCODED_NO_BOM )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " Language file %s has no byte order marker. Fix this or roll back to a version that has the marker. " , name ) ;
2012-11-28 15:47:07 +00:00
}
else if ( encoding ! = UTF8_ENCODED_BOM & & encoding ! = UTF8_PURE_ASCII )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " Language file %s has unknown utf8Encoding_t. " , name ) ;
}
return encoding ;
}
2012-11-28 15:47:07 +00:00
// string entries can refer to other string entries,
2012-11-26 18:58:24 +00:00
// recursing up to this many times before we decided someone did something stupid
2012-11-28 15:47:07 +00:00
const char * idLangDict : : KEY_PREFIX = " #str_ " ; // all keys should be prefixed with this for redirection to work
2012-11-26 18:58:24 +00:00
const int idLangDict : : KEY_PREFIX_LEN = idStr : : Length ( KEY_PREFIX ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : idLangDict
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLangDict : : idLangDict ( ) : keyIndex ( 4096 , 4096 )
{
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : ~ idLangDict
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idLangDict : : ~ idLangDict ( )
{
2012-11-26 18:58:24 +00:00
Clear ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : Clear
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLangDict : : Clear ( )
{
2012-11-26 18:58:24 +00:00
//mem.PushHeap();
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < keyVals . Num ( ) ; i + + )
{
if ( keyVals [ i ] . value = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
blockAlloc . Free ( keyVals [ i ] . value ) ;
keyVals [ i ] . value = NULL ;
}
//mem.PopHeap();
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : Load
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : Load ( const byte * buffer , const int bufferLen , const char * name )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( buffer = = NULL | | bufferLen < = 0 )
{
2012-11-26 18:58:24 +00:00
// let whoever called us deal with the failure (so sys_lang can be reset)
return false ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " Reading %s " , name ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool utf8 = false ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// in all but retail builds, ensure that the byte-order mark is NOT MISSING so that
// we can avoid debugging UTF-8 code
# ifndef ID_RETAIL
utf8Encoding_t encoding = idLocalization : : VerifyUTF8 ( buffer , bufferLen , name ) ;
2012-11-28 15:47:07 +00:00
if ( encoding = = UTF8_ENCODED_BOM )
{
2012-11-26 18:58:24 +00:00
utf8 = true ;
2012-11-28 15:47:07 +00:00
}
else if ( encoding = = UTF8_PURE_ASCII )
{
2012-11-26 18:58:24 +00:00
utf8 = false ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
assert ( false ) ; // this should have been handled in VerifyUTF8 with a FatalError
return false ;
}
# else
// in release we just check the BOM so we're not scanning the lang file twice on startup
2012-11-28 15:47:07 +00:00
if ( bufferLen > 3 & & buffer [ 0 ] = = 0xEF & & buffer [ 1 ] = = 0xBB & & buffer [ 2 ] = = 0xBF )
{
2012-11-26 18:58:24 +00:00
utf8 = true ;
}
# endif
2012-11-28 15:47:07 +00:00
if ( utf8 )
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " as UTF-8 \n " ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " as ASCII \n " ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idStr tempKey ;
idStr tempVal ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int line = 0 ;
int numStrings = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int i = 0 ;
2012-11-28 15:47:07 +00:00
while ( i < bufferLen )
{
2012-11-26 18:58:24 +00:00
uint32 c = buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( c = = ' / ' ) // comment, read until new line
{
while ( i < bufferLen )
{
2012-11-26 18:58:24 +00:00
c = buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( c = = ' \n ' )
{
2012-11-26 18:58:24 +00:00
line + + ;
break ;
}
}
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' } ' )
{
2012-11-26 18:58:24 +00:00
break ;
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' \n ' )
{
2012-11-26 18:58:24 +00:00
line + + ;
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' \" ' )
{
2012-11-26 18:58:24 +00:00
int keyStart = i ;
int keyEnd = - 1 ;
2012-11-28 15:47:07 +00:00
while ( i < bufferLen )
{
2012-11-26 18:58:24 +00:00
c = buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( c = = ' \" ' )
{
2012-11-26 18:58:24 +00:00
keyEnd = i - 1 ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( keyEnd < keyStart )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " %s File ended while reading key at line %d " , name , line ) ;
}
2012-11-28 15:47:07 +00:00
tempKey . CopyRange ( ( char * ) buffer , keyStart , keyEnd ) ;
2012-11-26 18:58:24 +00:00
int valStart = - 1 ;
2012-11-28 15:47:07 +00:00
while ( i < bufferLen )
{
2012-11-26 18:58:24 +00:00
c = buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( c = = ' \" ' )
{
2012-11-26 18:58:24 +00:00
valStart = i ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( valStart < 0 )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " %s File ended while reading value at line %d " , name , line ) ;
}
int valEnd = - 1 ;
tempVal . CapLength ( 0 ) ;
2012-11-28 15:47:07 +00:00
while ( i < bufferLen )
{
2012-11-26 18:58:24 +00:00
c = utf8 ? idStr : : UTF8Char ( buffer , i ) : buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( ! utf8 & & c > = 0x80 )
{
2012-11-26 18:58:24 +00:00
// this is a serious error and we must check this to avoid accidentally shipping a file where someone squased UTF-8 encodings
idLib : : FatalError ( " Language file %s is supposed to be plain ASCII, but has byte values > 127! " , name ) ;
}
2012-11-28 15:47:07 +00:00
if ( c = = ' \" ' )
{
2012-11-26 18:58:24 +00:00
valEnd = i - 1 ;
continue ;
}
2012-11-28 15:47:07 +00:00
if ( c = = ' \n ' )
{
2012-11-26 18:58:24 +00:00
line + + ;
break ;
}
2012-11-28 15:47:07 +00:00
if ( c = = ' \r ' )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( c = = ' \\ ' )
{
2012-11-26 18:58:24 +00:00
c = utf8 ? idStr : : UTF8Char ( buffer , i ) : buffer [ i + + ] ;
2012-11-28 15:47:07 +00:00
if ( c = = ' n ' )
{
2012-11-26 18:58:24 +00:00
c = ' \n ' ;
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' t ' )
{
2012-11-26 18:58:24 +00:00
c = ' \t ' ;
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' \" ' )
{
2012-11-26 18:58:24 +00:00
c = ' \" ' ;
2012-11-28 15:47:07 +00:00
}
else if ( c = = ' \\ ' )
{
2012-11-26 18:58:24 +00:00
c = ' \\ ' ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " Unknown escape sequence %x at line %d " , c , line ) ;
}
}
tempVal . AppendUTF8Char ( c ) ;
}
2012-11-28 15:47:07 +00:00
if ( valEnd < valStart )
{
2012-11-26 18:58:24 +00:00
idLib : : FatalError ( " %s File ended while reading value at line %d " , name , line ) ;
}
2012-11-28 15:47:07 +00:00
if ( lang_maskLocalizedStrings . GetBool ( ) & & tempVal . Length ( ) > 0 & & tempKey . Find ( " #font_ " ) = = - 1 )
{
2012-11-26 18:58:24 +00:00
int len = tempVal . Length ( ) ;
2012-11-28 15:47:07 +00:00
if ( len > 0 )
{
2012-11-26 18:58:24 +00:00
tempVal . Fill ( ' W ' , len - 1 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
tempVal . Empty ( ) ;
}
tempVal . Append ( ' X ' ) ;
}
AddKeyVal ( tempKey , tempVal ) ;
numStrings + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " %i strings read \n " , numStrings ) ;
// get rid of any waste due to geometric list growth
//mem.PushHeap();
keyVals . Condense ( ) ;
//mem.PopHeap();
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : Save
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : Save ( const char * fileName )
{
idFile * outFile = fileSystem - > OpenFileWrite ( fileName ) ;
if ( outFile = = NULL )
{
2012-11-26 18:58:24 +00:00
idLib : : Warning ( " Error saving: %s " , fileName ) ;
return false ;
}
byte bof [ 3 ] = { 0xEF , 0xBB , 0xBF } ;
outFile - > Write ( bof , 3 ) ;
outFile - > WriteFloatString ( " // string table \n // \n \n { \n " ) ;
2012-11-28 15:47:07 +00:00
for ( int j = 0 ; j < keyVals . Num ( ) ; j + + )
{
const idLangKeyValue & kvp = keyVals [ j ] ;
if ( kvp . value = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
outFile - > WriteFloatString ( " \t \" %s \" \t \" " , kvp . key ) ;
2012-11-28 15:47:07 +00:00
for ( int k = 0 ; kvp . value [ k ] ! = 0 ; k + + )
{
2012-11-26 18:58:24 +00:00
char ch = kvp . value [ k ] ;
2012-11-28 15:47:07 +00:00
if ( ch = = ' \t ' )
{
2012-11-26 18:58:24 +00:00
outFile - > Write ( " \\ t " , 2 ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ch = = ' \n ' | | ch = = ' \r ' )
{
2012-11-26 18:58:24 +00:00
outFile - > Write ( " \\ n " , 2 ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ch = = ' " ' )
{
2012-11-26 18:58:24 +00:00
outFile - > Write ( " \\ \" " , 2 ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ch = = ' \\ ' )
{
2012-11-26 18:58:24 +00:00
outFile - > Write ( " \\ \\ " , 2 ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
outFile - > Write ( & ch , 1 ) ;
}
}
outFile - > WriteFloatString ( " \" \n " ) ;
}
outFile - > WriteFloatString ( " \n } \n " ) ;
delete outFile ;
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : GetString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLangDict : : GetString ( const char * str ) const
{
const char * localized = FindString ( str ) ;
if ( localized = = NULL )
{
2012-11-26 18:58:24 +00:00
return str ;
}
return localized ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : FindStringIndex
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLangDict : : FindStringIndex ( const char * str ) const
{
if ( str = = NULL )
{
2012-11-26 18:58:24 +00:00
return - 1 ;
}
int hash = idStr : : IHash ( str ) ;
2012-11-28 15:47:07 +00:00
for ( int i = keyIndex . GetFirst ( hash ) ; i > = 0 ; i = keyIndex . GetNext ( i ) )
{
if ( idStr : : Icmp ( str , keyVals [ i ] . key ) = = 0 )
{
2012-11-26 18:58:24 +00:00
return i ;
}
}
return - 1 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : FindString_r
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLangDict : : FindString_r ( const char * str , int & depth ) const
{
2012-11-26 18:58:24 +00:00
depth + + ;
2012-11-28 15:47:07 +00:00
if ( depth > MAX_REDIRECTION_DEPTH )
{
2012-11-26 18:58:24 +00:00
// This isn't an error because we assume the error will be obvious somewhere in a GUI or something,
// and the whole point of tracking the depth is to avoid a crash.
idLib : : Warning ( " String '%s', indirection depth > %d " , str , MAX_REDIRECTION_DEPTH ) ;
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( str = = NULL | | str [ 0 ] = = ' \0 ' )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int index = FindStringIndex ( str ) ;
2012-11-28 15:47:07 +00:00
if ( index < 0 )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
const char * value = keyVals [ index ] . value ;
if ( value = = NULL )
{
2012-11-26 18:58:24 +00:00
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( IsStringId ( value ) )
{
2012-11-26 18:58:24 +00:00
// this string is re-directed to another entry
return FindString_r ( value , depth ) ;
}
return value ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : FindString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLangDict : : FindString ( const char * str ) const
{
2012-11-26 18:58:24 +00:00
int depth = 0 ;
return FindString_r ( str , depth ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : DeleteString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : DeleteString ( const char * key )
{
2012-11-26 18:58:24 +00:00
return DeleteString ( FindStringIndex ( key ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : DeleteString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : DeleteString ( const int idx )
{
if ( idx < 0 | | idx > = keyVals . Num ( ) )
{
2012-11-26 18:58:24 +00:00
return false ;
}
//mem.PushHeap();
blockAlloc . Free ( keyVals [ idx ] . value ) ;
keyVals [ idx ] . value = NULL ;
//mem.PopHeap();
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : RenameStringKey
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : RenameStringKey ( const char * oldKey , const char * newKey )
{
2012-11-26 18:58:24 +00:00
int index = FindStringIndex ( oldKey ) ;
2012-11-28 15:47:07 +00:00
if ( index < 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
//mem.PushHeap();
blockAlloc . Free ( keyVals [ index ] . key ) ;
int newKeyLen = idStr : : Length ( newKey ) ;
keyVals [ index ] . key = blockAlloc . Alloc ( newKeyLen + 1 ) ;
idStr : : Copynz ( keyVals [ index ] . key , newKey , newKeyLen + 1 ) ;
int oldHash = idStr : : IHash ( oldKey ) ;
int newHash = idStr : : IHash ( newKey ) ;
2012-11-28 15:47:07 +00:00
if ( oldHash ! = newHash )
{
2012-11-26 18:58:24 +00:00
keyIndex . Remove ( oldHash , index ) ;
keyIndex . Add ( newHash , index ) ;
}
//mem.PopHeap();
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : SetString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : SetString ( const char * key , const char * val )
{
2012-11-26 18:58:24 +00:00
int index = FindStringIndex ( key ) ;
2012-11-28 15:47:07 +00:00
if ( index < 0 )
{
2012-11-26 18:58:24 +00:00
return false ;
}
//mem.PushHeap();
2012-11-28 15:47:07 +00:00
if ( keyVals [ index ] . value ! = NULL )
{
2012-11-26 18:58:24 +00:00
blockAlloc . Free ( keyVals [ index ] . value ) ;
}
int valLen = idStr : : Length ( val ) ;
keyVals [ index ] . value = blockAlloc . Alloc ( valLen + 1 ) ;
idStr : : Copynz ( keyVals [ index ] . value , val , valLen + 1 ) ;
//mem.PopHeap();
return true ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : AddKeyVal
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idLangDict : : AddKeyVal ( const char * key , const char * val )
{
if ( SetString ( key , val ) )
{
2012-11-26 18:58:24 +00:00
return ;
}
//mem.PushHeap();
int keyLen = idStr : : Length ( key ) ;
2012-11-28 15:47:07 +00:00
char * k = blockAlloc . Alloc ( keyLen + 1 ) ;
2012-11-26 18:58:24 +00:00
idStr : : Copynz ( k , key , keyLen + 1 ) ;
2012-11-28 15:47:07 +00:00
char * v = NULL ;
if ( val ! = NULL )
{
2012-11-26 18:58:24 +00:00
int valLen = idStr : : Length ( val ) ;
v = blockAlloc . Alloc ( valLen + 1 ) ;
idStr : : Copynz ( v , val , valLen + 1 ) ;
}
int index = keyVals . Append ( idLangKeyValue ( k , v ) ) ;
int hash = idStr : : IHash ( key ) ;
keyIndex . Add ( hash , index ) ;
//mem.PopHeap();
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : AddString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLangDict : : AddString ( const char * val )
{
2012-11-26 18:58:24 +00:00
int i = Sys_Milliseconds ( ) ;
idStr key ;
sprintf ( key , " #str_%06d " , ( i + + % 1000000 ) ) ;
2012-11-28 15:47:07 +00:00
while ( FindStringIndex ( key ) > 0 )
{
2012-11-26 18:58:24 +00:00
sprintf ( key , " #str_%06d " , ( i + + % 1000000 ) ) ;
}
AddKeyVal ( key , val ) ;
int index = FindStringIndex ( key ) ;
return keyVals [ index ] . key ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : GetNumKeyVals
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idLangDict : : GetNumKeyVals ( ) const
{
2012-11-26 18:58:24 +00:00
return keyVals . Num ( ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : GetKeyVal
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const idLangKeyValue * idLangDict : : GetKeyVal ( int i ) const
{
2012-11-26 18:58:24 +00:00
return & keyVals [ i ] ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : IsStringId
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool idLangDict : : IsStringId ( const char * str )
{
2012-11-26 18:58:24 +00:00
return idStr : : Icmpn ( str , KEY_PREFIX , KEY_PREFIX_LEN ) = = 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idLangDict : : GetLocalizedString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idLangDict : : GetLocalizedString ( const idStrId & strId ) const
{
if ( strId . GetIndex ( ) > = 0 & & strId . GetIndex ( ) < keyVals . Num ( ) )
{
if ( keyVals [ strId . GetIndex ( ) ] . value = = NULL )
{
2012-11-26 18:58:24 +00:00
return keyVals [ strId . GetIndex ( ) ] . key ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
return keyVals [ strId . GetIndex ( ) ] . value ;
}
}
return " " ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
idStrId
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idStrId : : Set
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idStrId : : Set ( const char * key )
{
if ( key = = NULL | | key [ 0 ] = = 0 )
{
2012-11-26 18:58:24 +00:00
index = - 1 ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
index = idLocalization : : languageDict . FindStringIndex ( key ) ;
2012-11-28 15:47:07 +00:00
if ( index < 0 )
{
// don't allow setting of string ID's to an unknown ID... this should only be allowed from
// the string table tool because additions from anywhere else are not guaranteed to be
2012-11-26 18:58:24 +00:00
// saved to the .lang file.
idLib : : Warning ( " Attempted to set unknown string ID '%s' " , key ) ;
}
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idStrId : : GetKey
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idStrId : : GetKey ( ) const
{
if ( index > = 0 & & index < idLocalization : : languageDict . keyVals . Num ( ) )
{
2012-11-26 18:58:24 +00:00
return idLocalization : : languageDict . keyVals [ index ] . key ;
}
return " " ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
idStrId : : GetLocalizedString
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
const char * idStrId : : GetLocalizedString ( ) const
{
2012-11-26 18:58:24 +00:00
return idLocalization : : languageDict . GetLocalizedString ( * this ) ;
}