| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406 |
- /*
- ** Command & Conquer Generals(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/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- //----------------------------------------------------------------------------
- //
- // Westwood Studios Pacific.
- //
- // Confidential Information
- // Copyright(C) 2001 - All Rights Reserved
- //
- //----------------------------------------------------------------------------
- //
- // Project: RTS3
- //
- // File name: GameText.cpp
- //
- // Created: 11/07/01
- //
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Includes
- //----------------------------------------------------------------------------
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "GameClient/GameText.h"
- #include "Common/Language.h"
- #include "Common/Registry.h"
- #include "GameClient/LanguageFilter.h"
- #include "Common/Debug.h"
- #include "Common/UnicodeString.h"
- #include "Common/AsciiString.h"
- #include "Common/GlobalData.h"
- #include "Common/File.h"
- #include "Common/FileSystem.h"
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- //----------------------------------------------------------------------------
- // Externals
- //----------------------------------------------------------------------------
- #if defined(_DEBUG) || defined(_INTERNAL)
- Bool g_useStringFile = TRUE;
- #endif
- //----------------------------------------------------------------------------
- // Defines
- //----------------------------------------------------------------------------
- #define CSF_ID ( ('C'<<24) | ('S'<<16) | ('F'<<8) | (' ') )
- #define CSF_LABEL ( ('L'<<24) | ('B'<<16) | ('L'<<8) | (' ') )
- #define CSF_STRING ( ('S'<<24) | ('T'<<16) | ('R'<<8) | (' ') )
- #define CSF_STRINGWITHWAVE ( ('S'<<24) | ('T'<<16) | ('R'<<8) | ('W') )
- #define CSF_VERSION 3
- #define STRING_FILE 0
- #define CSF_FILE 1
- #define MAX_UITEXT_LENGTH (10*1024)
- //----------------------------------------------------------------------------
- // Private Types
- //----------------------------------------------------------------------------
- //===============================
- // StringInfo
- //===============================
- struct StringInfo
- {
- AsciiString label;
- UnicodeString text;
- AsciiString speech;
- };
- struct StringLookUp
- {
- AsciiString *label;
- StringInfo *info;
- };
- //===============================
- // CSFHeader
- //===============================
- struct CSFHeader
- {
- Int id;
- Int version;
- Int num_labels;
- Int num_strings;
- Int skip;
- Int langid;
- };
- //===============================
- // struct NoString
- //===============================
- struct NoString
- {
- struct NoString *next;
- UnicodeString text;
- };
- //===============================
- // GameTextManager
- //===============================
- class GameTextManager : public GameTextInterface
- {
- public:
- GameTextManager();
- virtual ~GameTextManager();
- virtual void init( void ); ///< Initlaizes the text system
- virtual void deinit( void ); ///< De-initlaizes the text system
- virtual void update( void ) {}; ///< update text manager
- virtual void reset( void ); ///< Resets the text system
- virtual UnicodeString fetch( const Char *label, Bool *exists = NULL ); ///< Returns the associated labeled unicode text
- virtual UnicodeString fetch( AsciiString label, Bool *exists = NULL ); ///< Returns the associated labeled unicode text
- virtual AsciiStringVec& getStringsWithLabelPrefix(AsciiString label);
- virtual void initMapStringFile( const AsciiString& filename );
- protected:
- Int m_textCount;
- Int m_maxLabelLen;
- Char m_buffer[MAX_UITEXT_LENGTH];
- Char m_buffer2[MAX_UITEXT_LENGTH];
- Char m_buffer3[MAX_UITEXT_LENGTH];
- WideChar m_tbuffer[MAX_UITEXT_LENGTH*2];
-
- StringInfo *m_stringInfo;
- StringLookUp *m_stringLUT;
- Bool m_initialized;
- #if defined(_DEBUG) || defined(_INTERNAL)
- Bool m_jabberWockie;
- Bool m_munkee;
- #endif
- NoString *m_noStringList;
- Int m_useStringFile;
- LanguageID m_language;
- UnicodeString m_failed;
- StringInfo *m_mapStringInfo;
- StringLookUp *m_mapStringLUT;
- Int m_mapTextCount;
- /// m_asciiStringVec will be altered every time that getStringsWithLabelPrefix is called,
- /// so don't simply store a pointer to it.
- AsciiStringVec m_asciiStringVec;
- void stripSpaces ( WideChar *string );
- void removeLeadingAndTrailing ( Char *m_buffer );
- void readToEndOfQuote( File *file, Char *in, Char *out, Char *wavefile, Int maxBufLen );
- void reverseWord ( Char *file, Char *lp );
- void translateCopy( WideChar *outbuf, Char *inbuf );
- Bool getStringCount( const Char *filename, Int& textCount );
- Bool getCSFInfo ( const Char *filename );
- Bool parseCSF( const Char *filename );
- Bool parseStringFile( const char *filename );
- Bool parseMapStringFile( const char *filename );
- Bool readLine( char *buffer, Int max, File *file );
- Char readChar( File *file );
- };
- static int _cdecl compareLUT ( const void *, const void*);
- //----------------------------------------------------------------------------
- // Private Data
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Public Data
- //----------------------------------------------------------------------------
- GameTextInterface *TheGameText = NULL;
- //----------------------------------------------------------------------------
- // Private Prototypes
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Private Functions
- //----------------------------------------------------------------------------
- //----------------------------------------------------------------------------
- // Public Functions
- //----------------------------------------------------------------------------
- //============================================================================
- // CreateGameTextInterface
- //============================================================================
- GameTextInterface* CreateGameTextInterface( void )
- {
- return NEW GameTextManager;
- }
- //============================================================================
- // GameTextManager::GameTextManager
- //============================================================================
- GameTextManager::GameTextManager()
- : m_textCount(0),
- m_maxLabelLen(0),
- m_stringInfo(NULL),
- m_stringLUT(NULL),
- m_initialized(FALSE),
- m_noStringList(NULL),
- #if defined(_DEBUG) || defined(_INTERNAL)
- m_jabberWockie(FALSE),
- m_munkee(FALSE),
- m_useStringFile(g_useStringFile),
- #else
- m_useStringFile(TRUE),
- #endif
- m_mapStringInfo(NULL),
- m_mapStringLUT(NULL),
- m_failed(L"***FATAL*** String Manager failed to initilaize properly")
- {
- // Added By Sadullah Nader
- // Initializations missing and needed
- for(Int i=0; i < MAX_UITEXT_LENGTH; i++)
- {
- m_buffer[i] = 0;
- m_buffer2[i] = 0;
- m_buffer3[i] = 0;
- }
- //
- }
- //============================================================================
- // GameTextManager::~GameTextManager
- //============================================================================
- GameTextManager::~GameTextManager()
- {
- deinit();
- }
- //============================================================================
- // GameTextManager::init
- //============================================================================
- extern const Char *g_strFile;
- extern const Char *g_csfFile;
- void GameTextManager::init( void )
- {
- AsciiString csfFile;
- csfFile.format(g_csfFile, GetRegistryLanguage().str());
- Int format;
- if ( m_initialized )
- {
- return;
- }
- m_initialized = TRUE;
- m_maxLabelLen = 0;
- #if defined(_DEBUG) || defined(_INTERNAL)
- if(TheGlobalData)
- {
- m_jabberWockie = TheGlobalData->m_jabberOn;
- m_munkee = TheGlobalData->m_munkeeOn;
- }
- #endif
- if ( m_useStringFile && getStringCount( g_strFile, m_textCount ) )
- {
- format = STRING_FILE;
- }
- else if ( getCSFInfo ( csfFile.str() ) )
- {
- format = CSF_FILE;
- }
- else
- {
- return;
- }
- if( (m_textCount == 0) )
- {
- return;
- }
- //Allocate StringInfo Array
- m_stringInfo = NEW StringInfo[m_textCount];
- if( m_stringInfo == NULL )
- {
- deinit();
- return;
- }
- if ( format == STRING_FILE )
- {
- if( parseStringFile( g_strFile ) == FALSE )
- {
- deinit();
- return;
- }
- }
- else
- {
- if ( !parseCSF ( csfFile.str() ) )
- {
- deinit();
- return;
- }
- }
- m_stringLUT = NEW StringLookUp[m_textCount];
- StringLookUp *lut = m_stringLUT;
- StringInfo *info = m_stringInfo;
- for ( Int i = 0; i < m_textCount; i++ )
- {
- lut->info = info;
- lut->label = &info->label;
- lut++;
- info++;
- }
- qsort( m_stringLUT, m_textCount, sizeof(StringLookUp), compareLUT );
- UnicodeString ourName = fetch("GUI:Command&ConquerGenerals");
- extern HWND ApplicationHWnd; ///< our application window handle
- if (ApplicationHWnd) {
- ::SetWindowTextW(ApplicationHWnd, ourName.str());
- }
- }
- //============================================================================
- // GameTextManager::deinit
- //============================================================================
- void GameTextManager::deinit( void )
- {
- if( m_stringInfo != NULL )
- {
- delete [] m_stringInfo;
- m_stringInfo = NULL;
- }
- if( m_stringLUT != NULL )
- {
- delete [] m_stringLUT;
- m_stringLUT = NULL;
- }
- m_textCount = 0;
- NoString *noString = m_noStringList;
- DEBUG_LOG(("\n*** Missing strings ***\n"));
- while ( noString )
- {
- DEBUG_LOG(("*** %ls ***\n", noString->text.str()));
- NoString *next = noString->next;
- delete noString;
- noString = next;
- }
- DEBUG_LOG(("*** End missing strings ***\n\n"));
- m_noStringList = NULL;
- m_initialized = FALSE;
- }
- //============================================================================
- // GameTextManager::reset
- //============================================================================
- void GameTextManager::reset( void )
- {
- if( m_mapStringInfo != NULL )
- {
- delete [] m_mapStringInfo;
- m_mapStringInfo = NULL;
- }
- if( m_mapStringLUT != NULL )
- {
- delete [] m_mapStringLUT;
- m_mapStringLUT = NULL;
- }
- }
- //============================================================================
- // GameTextManager::stripSpaces
- //============================================================================
- void GameTextManager::stripSpaces ( WideChar *string )
- {
- WideChar *str, *ptr;
- WideChar ch, last = 0;
- Int skipall = TRUE;
- str = ptr = string;
- while ( (ch = *ptr++) != 0 )
- {
- if ( ch == ' ' )
- {
- if ( last == ' ' || skipall )
- {
- continue;
- }
- }
- if ( ch == '\n' || ch == '\t' )
- {
- // remove last space
- if ( last == ' ' )
- {
- str--;
- }
- skipall = TRUE; // skip all spaces
- last = *str++ = ch;
- continue;
- }
- last = *str++ = ch;
- skipall = FALSE;
- }
- if ( last == ' ' )
- {
- str--;
- }
- *str = 0;
- }
- //============================================================================
- // GameTextManager::removeLeadingAndTrailing
- //============================================================================
- void GameTextManager::removeLeadingAndTrailing ( Char *buffer )
- {
- Char *first, *ptr;
- Char ch;
- ptr = first = buffer;
- while ( (ch = *first) != 0 && iswspace ( ch ))
- {
- first++;
- }
- while ( (*ptr++ = *first++) != 0 );
- ptr -= 2;;
- while ( (ptr > buffer) && (ch = *ptr) != 0 && iswspace ( ch ) )
- {
- ptr--;
- }
- ptr++;
- *ptr = 0;
- }
- //============================================================================
- // GameTextManager::readToEndOfQuote
- //============================================================================
- void GameTextManager::readToEndOfQuote( File *file, Char *in, Char *out, Char *wavefile, Int maxBufLen )
- {
- Int slash = FALSE;
- Int state = 0;
- Int line_start = FALSE;
- Char ch;
- Int ccount = 0;
- Int len = 0;
- Int done = FALSE;
- while ( maxBufLen )
- {
- // get next Char
- if ( in )
- {
- if ( (ch = *in++) == 0 )
- {
- in = NULL; // have exhausted the input m_buffer
- ch = readChar ( file );
- }
- }
- else
- {
- ch = readChar ( file );
- }
- if ( ch == EOF )
- {
- return ;
- }
- if ( ch == '\n' )
- {
- line_start = TRUE;
- slash = FALSE;
- ccount = 0;
- ch = ' ';
- }
- else if ( ch == '\\' && !slash)
- {
- slash = TRUE;
- }
- else if ( ch == '\\' && slash)
- {
- slash = FALSE;
- }
- else if ( ch == '"' && !slash )
- {
- break; // done
- }
- else
- {
- slash = FALSE;
- }
- if ( iswspace ( ch ))
- {
- ch = ' ';
- }
- *out++ = ch;
- maxBufLen--;
- }
- *out = 0;
- while ( !done )
- {
- // get next Char
- if ( in )
- {
- if ( (ch = *in++) == 0 )
- {
- in = NULL; // have exhausted the input m_buffer
- ch = readChar ( file );
- }
- }
- else
- {
- ch = readChar ( file );
- }
- if ( ch == '\n' || ch == EOF )
- {
- break;
- }
- switch ( state )
- {
- case 0:
- if ( iswspace ( ch ) || ch == '=' )
- {
- break;
- }
- state = 1;
- case 1:
- if ( ( ch >= 'a' && ch <= 'z') || ( ch >= 'A' && ch <='Z') || (ch >= '0' && ch <= '9') || ch == '_' )
- {
- *wavefile++ = ch;
- len++;
- break;
- }
- state = 2;
- case 2:
- break;
- }
- }
- *wavefile = 0;
- if ( len )
- {
- if ( ( ch = *(wavefile-1)) >= '0' && ch <= '9' )
- {
- *wavefile++ = 'e';
- *wavefile = 0;
- }
- }
- }
- //============================================================================
- // GameTextManager::reverseWord
- //============================================================================
- void GameTextManager::reverseWord ( Char *file, Char *lp )
- {
- Int first = TRUE;
- Char f, l;
- Int ok = TRUE ;
- while ( ok )
- {
- if ( file >= lp )
- {
- return;
- }
- f = *file;
- l = *lp;
- if ( first )
- {
- if ( f >= 'A' && f <= 'Z' )
- {
- if ( l >= 'a' && l <= 'z' )
- {
- f = (f - 'A') + 'a';
- l = (l - 'a') + 'A';
- }
- }
- first = FALSE;
- }
- *lp-- = f;
- *file++ = l;
- }
- }
- //============================================================================
- // GameTextManager::translateCopy
- //============================================================================
- void GameTextManager::translateCopy( WideChar *outbuf, Char *inbuf )
- {
- Int slash = FALSE;
- #if defined(_DEBUG) || defined(_INTERNAL)
- if ( m_jabberWockie )
- {
- static Char buffer[MAX_UITEXT_LENGTH*2];
- Char *firstLetter = NULL, *lastLetter;
- Char *b = buffer;
- Int formatWord = FALSE;
- Char ch;
- while ( (ch = *inbuf++) != 0 )
- {
- if ( ! (( ch >= 'a' && ch <= 'z') || ( ch >= 'A' && ch <= 'Z' )))
- {
- if ( firstLetter )
- {
- if ( !formatWord )
- {
- lastLetter = b-1;
- reverseWord ( firstLetter, lastLetter );
- }
- firstLetter = NULL;
- formatWord = FALSE;
- }
- *b++ = ch;
- if ( ch == '\\' )
- {
- *b++ = *inbuf++;
- }
- if ( ch == '%' )
- {
- while ( (ch = *inbuf++) != 0 && !( (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')))
- {
- *b++ = ch;
- }
- *b++ = ch;
- }
- }
- else
- {
- if ( !firstLetter )
- {
- firstLetter = b;
- }
- *b++ = ch;
- }
- }
- if ( firstLetter )
- {
- lastLetter = b-1;
- reverseWord ( firstLetter, lastLetter );
- }
- *b++ = 0;
- inbuf = buffer;
- }
- else if( m_munkee )
- {
- wcscpy(outbuf, L"Munkee");
- return;
- }
- #endif
- while( *inbuf != '\0' )
- {
- if( slash == TRUE )
- {
- slash = FALSE;
- switch( *inbuf )
- {
- // in case end of string is reached
- // should never happen!!!
- case '\0':
- return;
- case '\\':
- *outbuf++ = '\\';
- break;
- case '\'':
- *outbuf++ = '\'';
- break;
- case '\"':
- *outbuf++ = '\"';
- break;
- case '\?':
- *outbuf++ = '\?';
- break;
- case 't':
- *outbuf++ = '\t';
- break;
- case 'n':
- *outbuf++ = '\n';
- break;
- default:
- *outbuf++ = *inbuf & 0x00FF;
- break;
- }
- }
- else if( *inbuf != '\\' )
- {
- *outbuf++ = *inbuf & 0x00FF;
- }
- else
- slash = TRUE;
- inbuf++;
- }
- *outbuf= 0;
- }
- //============================================================================
- // GameTextManager::getStringCount
- //============================================================================
- Bool GameTextManager::getStringCount( const char *filename, Int& textCount )
- {
- Int ok = TRUE;
- textCount = 0;
- File *file;
- file = TheFileSystem->openFile(filename, File::READ | File::TEXT);
- DEBUG_LOG(("Looking in %s for string file\n", filename));
-
- if ( file == NULL )
- {
- return FALSE;
- }
- while(ok)
- {
- if( !readLine( m_buffer, sizeof( m_buffer) -1, file ) )
- break;
- removeLeadingAndTrailing ( m_buffer );
- if( m_buffer[0] == '"' )
- {
- Int len = strlen(m_buffer);
- m_buffer[ len ] = '\n';
- m_buffer[ len+1] = 0;
- readToEndOfQuote( file, &m_buffer[1], m_buffer2, m_buffer3, MAX_UITEXT_LENGTH );
- }
- else if( !stricmp( m_buffer, "END") )
- {
- textCount++;
- }
- }
- textCount += 500;
- file->close();
- file = NULL;
- return TRUE;
- }
- //============================================================================
- // GameTextManager::getCSFInfo
- //============================================================================
- Bool GameTextManager::getCSFInfo ( const Char *filename )
- {
- CSFHeader header;
- Int ok = FALSE;
- File *file = TheFileSystem->openFile(filename, File::READ | File::BINARY);
- DEBUG_LOG(("Looking in %s for compiled string file\n", filename));
- if ( file != NULL )
- {
- if ( file->read( &header, sizeof ( header )) == sizeof ( header ) )
- {
- if ( header.id == CSF_ID )
- {
- m_textCount = header.num_labels;
- if ( header.version >= 2 )
- {
- m_language = (LanguageID) header.langid;
- }
- else
- {
- m_language = LANGUAGE_ID_US;
- }
- ok = TRUE;
- }
- }
- file->close();
- file = NULL;
- }
- return ok;
- }
- //============================================================================
- // GameTextManager::parseCSF
- //============================================================================
- Bool GameTextManager::parseCSF( const Char *filename )
- {
- File *file;
- Int id;
- Int len;
- Int listCount = 0;
- Bool ok = FALSE;
- CSFHeader header;
- file = TheFileSystem->openFile(filename, File::READ | File::BINARY);
- if ( file == NULL )
- {
- return FALSE;
- }
- if ( file->read ( &header, sizeof ( CSFHeader)) != sizeof ( CSFHeader) )
- {
- return FALSE;
- }
- while( file->read ( &id, sizeof (id)) == sizeof ( id) )
- {
- Int num;
- Int num_strings;
- if ( id != CSF_LABEL )
- {
- goto quit;
- }
- file->read ( &num_strings, sizeof ( Int ));
- file->read ( &len, sizeof ( Int ) );
- if ( len )
- {
- file->read ( m_buffer, len );
- }
- m_buffer[len] = 0;
- m_stringInfo[listCount].label = m_buffer;
- if ( len > m_maxLabelLen )
- {
- m_maxLabelLen = len;
- }
- num = 0;
- while ( num < num_strings )
- {
- file->read ( &id, sizeof ( Int ) );
- if ( id != CSF_STRING && id != CSF_STRINGWITHWAVE )
- {
- goto quit;
- }
- file->read ( &len, sizeof ( Int ) );
- if ( len )
- {
- file->read ( m_tbuffer, len*sizeof(WideChar) );
- }
- if ( num == 0 )
- {
- // only use the first string found
- m_tbuffer[len] = 0;
-
- {
- WideChar *ptr;
-
- ptr = m_tbuffer;
-
- while ( *ptr )
- {
- *ptr = ~*ptr;
- ptr++;
- }
- }
-
- stripSpaces ( m_tbuffer );
- m_stringInfo[listCount].text = m_tbuffer;
- }
- if ( id == CSF_STRINGWITHWAVE )
- {
- file->read ( &len, sizeof ( Int ) );
- if ( len )
- {
- file->read ( m_buffer, len );
- }
- m_buffer[len] = 0;
- if ( num == 0 && len )
- {
- // only use the first string found
- m_stringInfo[listCount].speech = m_buffer;
- }
- }
- num++;
- }
- listCount++;
- }
- ok = TRUE;
- quit:
- file->close();
- file = NULL;
- return ok;
- }
- //============================================================================
- // GameTextManager::parseStringFile
- //============================================================================
- Bool GameTextManager::parseStringFile( const char *filename )
- {
- Int listCount = 0;
- Int ok = TRUE;
- File *file = TheFileSystem->openFile(filename, File::READ | File::TEXT);
-
- if ( file == NULL )
- {
- return FALSE;
- }
- while( ok )
- {
- Int len;
- if( !readLine( m_buffer, MAX_UITEXT_LENGTH, file ))
- {
- break;
- }
- removeLeadingAndTrailing ( m_buffer );
- if( ( *(unsigned short *)m_buffer == 0x2F2F) || !m_buffer[0]) // 0x2F2F is Hex for //
- continue;
- // make sure label is unique
- for ( Int i = 0; i < listCount; i++ )
- {
- if ( !stricmp ( m_stringInfo[i].label.str(), m_buffer ))
- {
- DEBUG_ASSERTCRASH ( FALSE, ("String label '%s' multiply defined!", m_buffer ));
- }
- }
- m_stringInfo[listCount].label = m_buffer;
- len = strlen ( m_buffer );
- if ( len > m_maxLabelLen )
- {
- m_maxLabelLen = len;
- }
- Bool readString = FALSE;
- while( ok )
- {
- if (!readLine ( m_buffer, sizeof(m_buffer)-1, file ))
- {
- DEBUG_ASSERTCRASH (FALSE, ("Unexpected end of string file"));
- ok = FALSE;
- goto quit;
- }
- removeLeadingAndTrailing ( m_buffer );
- if( m_buffer[0] == '"' )
- {
- len = strlen(m_buffer);
- m_buffer[ len ] = '\n';
- m_buffer[ len+1] = 0;
- readToEndOfQuote( file, &m_buffer[1], m_buffer2, m_buffer3, MAX_UITEXT_LENGTH );
- if ( readString )
- {
- // only one string per label allows
- DEBUG_ASSERTCRASH ( FALSE, ("String label '%s' has more than one string defined!", m_stringInfo[listCount].label.str()));
- }
- else
- {
- // Copy string into new home
- translateCopy( m_tbuffer, m_buffer2 );
- stripSpaces ( m_tbuffer );
-
- m_stringInfo[listCount].text = m_tbuffer ;
- m_stringInfo[listCount].speech = m_buffer3;
- readString = TRUE;
- }
- }
- else if ( !stricmp ( m_buffer, "END" ))
- {
- break;
- }
- }
- listCount++;
- }
- quit:
- file->close();
- file = NULL;
- return ok;
- }
- //============================================================================
- // GameTextManager::initMapStringFile
- //============================================================================
- void GameTextManager::initMapStringFile( const AsciiString& filename )
- {
- m_mapTextCount = 0;
- getStringCount( filename.str(), m_mapTextCount );
- m_mapStringInfo = NEW StringInfo[m_mapTextCount];
- parseMapStringFile( filename.str() );
- m_mapStringLUT = NEW StringLookUp[m_mapTextCount];
- StringLookUp *lut = m_mapStringLUT;
- StringInfo *info = m_mapStringInfo;
- for ( Int i = 0; i < m_mapTextCount; i++ )
- {
- lut->info = info;
- lut->label = &info->label;
- lut++;
- info++;
- }
- qsort( m_mapStringLUT, m_mapTextCount, sizeof(StringLookUp), compareLUT );
- }
- //============================================================================
- // GameTextManager::parseMapStringFile
- //============================================================================
- Bool GameTextManager::parseMapStringFile( const char *filename )
- {
- Int listCount = 0;
- Int ok = TRUE;
- File *file;
- file = TheFileSystem->openFile(filename, File::READ | File::TEXT);
- if ( file == NULL )
- {
- return FALSE;
- }
- while( ok )
- {
- Int len;
- if( !readLine( m_buffer, MAX_UITEXT_LENGTH, file ))
- {
- break;
- }
- removeLeadingAndTrailing ( m_buffer );
- if( ( *(unsigned short *)m_buffer == 0x2F2F) || !m_buffer[0]) // 0x2F2F is Hex for //
- continue;
- // make sure label is unique
- for ( Int i = 0; i < listCount; i++ )
- {
- if ( !stricmp ( m_mapStringInfo[i].label.str(), m_buffer ))
- {
- DEBUG_ASSERTCRASH ( FALSE, ("String label '%s' multiply defined!", m_buffer ));
- }
- }
- m_mapStringInfo[listCount].label = m_buffer;
- len = strlen ( m_buffer );
- if ( len > m_maxLabelLen )
- {
- m_maxLabelLen = len;
- }
- Bool readString = FALSE;
- while( ok )
- {
- if (!readLine ( m_buffer, sizeof(m_buffer)-1, file ))
- {
- DEBUG_ASSERTCRASH (FALSE, ("Unexpected end of string file"));
- ok = FALSE;
- goto quit;
- }
- removeLeadingAndTrailing ( m_buffer );
- if( m_buffer[0] == '"' )
- {
- len = strlen(m_buffer);
- m_buffer[ len ] = '\n';
- m_buffer[ len+1] = 0;
- readToEndOfQuote( file, &m_buffer[1], m_buffer2, m_buffer3, MAX_UITEXT_LENGTH );
- if ( readString )
- {
- // only one string per label allowed
- DEBUG_ASSERTCRASH ( FALSE, ("String label '%s' has more than one string defined!", m_stringInfo[listCount].label.str()));
- }
- else
- {
- // Copy string into new home
- translateCopy( m_tbuffer, m_buffer2 );
- stripSpaces ( m_tbuffer );
- UnicodeString text = UnicodeString(m_tbuffer);
- if (TheLanguageFilter)
- TheLanguageFilter->filterLine(text);
-
- m_mapStringInfo[listCount].text = text;
- m_mapStringInfo[listCount].speech = m_buffer3;
- readString = TRUE;
- }
- }
- else if ( !stricmp ( m_buffer, "END" ))
- {
- break;
- }
- }
- listCount++;
- }
- quit:
- file->close();
- file = NULL;
- return ok;
- }
- //============================================================================
- // *GameTextManager::fetch
- //============================================================================
- UnicodeString GameTextManager::fetch( const Char *label, Bool *exists )
- {
- DEBUG_ASSERTCRASH ( m_initialized, ("String Manager has not been m_initialized") );
- if( m_stringInfo == NULL )
- {
- if( exists )
- *exists = FALSE;
- return m_failed;
- }
- StringLookUp *lookUp;
- StringLookUp key;
- AsciiString lb;
- lb = label;
- key.info = NULL;
- key.label = &lb;
- lookUp = (StringLookUp *) bsearch( &key, (void*) m_stringLUT, m_textCount, sizeof(StringLookUp), compareLUT );
- if ( lookUp == NULL && m_mapStringLUT && m_mapTextCount )
- {
- lookUp = (StringLookUp *) bsearch( &key, (void*) m_mapStringLUT, m_mapTextCount, sizeof(StringLookUp), compareLUT );
- }
- if( lookUp == NULL )
- {
- // string not found
- if( exists )
- *exists = FALSE;
- // See if we already have the missing string
- UnicodeString missingString;
- missingString.format(L"MISSING: '%hs'", label);
- NoString *noString = m_noStringList;
- while ( noString )
- {
- if (noString->text == missingString)
- return missingString;
- noString = noString->next;
- }
- //DEBUG_LOG(("*** MISSING:'%s' ***\n", label));
- // Remember file could have been altered at this point.
- noString = NEW NoString;
- noString->text = missingString;
- noString->next = m_noStringList;
- m_noStringList = noString;
- return noString->text;
- }
- if( exists )
- *exists = TRUE;
- return lookUp->info->text;
- }
- //============================================================================
- // *GameTextManager::fetch
- //============================================================================
- UnicodeString GameTextManager::fetch( AsciiString label, Bool *exists )
- {
- return fetch(label.str(), exists);
- }
- //============================================================================
- // GameTextManager::getStringsWithLabelPrefix
- //============================================================================
- AsciiStringVec& GameTextManager::getStringsWithLabelPrefix(AsciiString label)
- {
- m_asciiStringVec.clear();
- if (m_stringLUT) {
- for (int i = 0; i < m_textCount; ++i) {
- if (strstr(m_stringLUT[i].label->str(), label.str()) == m_stringLUT[i].label->str()) {
- m_asciiStringVec.push_back(*m_stringLUT[i].label);
- }
- }
- }
- if (m_mapStringLUT) {
- for (int i = 0; i < m_mapTextCount; ++i) {
- if (strstr(m_mapStringLUT[i].label->str(), label.str()) == m_mapStringLUT[i].label->str()) {
- m_asciiStringVec.push_back(*m_mapStringLUT[i].label);
- }
- }
- }
- return m_asciiStringVec;
- }
- //============================================================================
- // GameTextManager::readLine
- //============================================================================
- Bool GameTextManager::readLine( char *buffer, Int max, File *file )
- {
- Int ok = FALSE;
- while ( max && file->read( buffer, 1 ) == 1 )
- {
- ok = TRUE;
- if ( *buffer == '\n' )
- {
- break;
- }
- buffer++;
- max--;
- }
- *buffer = 0;
- return ok;
- }
- //============================================================================
- // GameTextManager::readChar
- //============================================================================
- Char GameTextManager::readChar( File *file )
- {
- Char ch;
- if ( file->read( &ch, 1 ) == 1 )
- {
- return ch;
- }
- return 0;
- }
- //============================================================================
- // GameTextManager::compareLUT
- //============================================================================
- static int __cdecl compareLUT ( const void *i1, const void*i2)
- {
- StringLookUp *lut1 = (StringLookUp*) i1;
- StringLookUp *lut2 = (StringLookUp*) i2;
- return stricmp( lut1->label->str(), lut2->label->str());
- }
|