////////////////////////////////////////////////////////////////////// // // Crytek Source code // Copyright (c) Crytek 2001-2004 // // StringTableMgr.cpp: implementation of the CStringTableMgr class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "StringTableMgr.h" #include "ScriptObjectLanguage.h" #include "IXMLDOM.h" #include #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// CStringTableMgr::CStringTableMgr() { m_pSystem=NULL; m_pLanguageStriptObject=NULL; } ////////////////////////////////////////////////////////////////////// CStringTableMgr::~CStringTableMgr() { } ////////////////////////////////////////////////////////////////////// bool CStringTableMgr::Load(ISystem *pSystem,CScriptObjectLanguage &oLang, string sLanguage) { m_pSystem=pSystem; m_sLanguage=sLanguage; m_pLanguageStriptObject=&oLang; m_vStrings.clear(); //------------------------------------------------------------------------------------------------- // input localization //------------------------------------------------------------------------------------------------- // keyboard for (int i = 0; i <= 0x80; i++) { AddControl(i); } // mouse for (int i = 1; i <= 0x0f; i++) { AddControl(i*0x10000); } return (true); } void CStringTableMgr::AddControl(int nKey) { IInput *pInput = m_pSystem->GetIInput(); if (!pInput) { return; } wchar_t szwKeyName[256] = {0}; char szKey[256] = {0}; if (!IS_MOUSE_KEY(nKey)) { if (pInput->GetOSKeyName(nKey, szwKeyName, 255)) { sprintf(szKey, "control%d", nKey); int nID = (int)m_vStrings.size(); m_keysMap[szKey] = nID; m_vStrings.push_back(szwKeyName); m_pLanguageStriptObject->AddString(szKey,nID); sprintf(szKey, "%S", szwKeyName); m_vEnglishStrings.push_back(szKey); } } } ////////////////////////////////////////////////////////////////////// // Retrieve a string by ID from the string-table. const wstring & CStringTableMgr::EnumString(int nID) const { static wstring unknown (L"???"); if( nID<0 || nID>=int(m_vStrings.size()) ) return (unknown);// string doesnt exist, return "???" return (m_vStrings[nID]); } ////////////////////////////////////////////////////////////////////// // Loads a string-table from a Excel XML Spreadsheet file. bool CStringTableMgr::LoadExcelXmlSpreadsheet( const string &sFileName ) { //string sPath="LANGUAGES/"+m_sLanguage+string("/")+sFileName; string sPath="LANGUAGES/"+sFileName; //check if this table has already been loaded FileNamesMapItor nit = m_mapLoadedTables.find(sPath); if (nit!=m_mapLoadedTables.end()) return (true); XDOM::IXMLDOMDocumentPtr pDoc=m_pSystem->CreateXMLDocument(); // load xml-file if (!pDoc->load(sPath.c_str())) return (false); m_mapLoadedTables[sFileName] = NULL; XDOM::IXMLDOMNodeListPtr pNodeList; XDOM::IXMLDOMNodePtr pString; XDOM::IXMLDOMNodePtr pEnum; XDOM::IXMLDOMNodePtr pValue; XDOM::IXMLDOMNodeListPtr pWorksheetList = pDoc->getElementsByTagName("Worksheet"); pWorksheetList->reset(); XDOM::IXMLDOMNodePtr pWorksheetNode = pWorksheetList->nextNode(); if (!pWorksheetNode) return false; XDOM::IXMLDOMNodeListPtr pTableList = pWorksheetNode->getElementsByTagName("Table"); pTableList->reset(); XDOM::IXMLDOMNodePtr pTableNode = pTableList->nextNode(); if (!pTableNode) return false; XDOM::IXMLDOMNodeListPtr pRowsList = pTableNode->getElementsByTagName("Row"); XDOM::IXMLDOMNodePtr pRowNode; XDOM::IXMLDOMNodePtr pCellNode; int nRow = 0; pRowsList->reset(); // get all strings in table while (pRowNode = pRowsList->nextNode()) { XDOM::IXMLDOMNodeListPtr pCellList = pRowNode->getElementsByTagName("Cell"); nRow++; if (nRow == 1) // Skip first row, it only have description. continue; const char* sKeyString = ""; const char* sEnglishString = ""; const char* sLanguageString = ""; int nCell = 0; pCellList->reset(); while (pCellNode = pCellList->nextNode()) { XDOM::IXMLDOMNodeListPtr pDataList = pCellNode->getElementsByTagName("Data"); #if !defined(LINUX64) if (pDataList==NULL) #else if (pDataList==0) #endif continue; pDataList->reset(); XDOM::IXMLDOMNodePtr pDataNode = pDataList->nextNode(); if (!pDataNode) continue; //CellNode->getTex switch (nCell) { // First cell is message key. case 0: sKeyString = pDataNode->getText(); break; // Second cell is english message. case 1: sEnglishString = pDataNode->getText(); break; // Third cell is local language. case 2: sLanguageString = pDataNode->getText(); break; }; nCell++; } const char *sUTF_8_Str = sLanguageString; if (strlen(sUTF_8_Str) == 0) { sUTF_8_Str = sEnglishString; } int nUTF_8_Len = strlen(sUTF_8_Str); int nUnicodeLen = nUTF_8_Len + 16; // + 16 just for safety. wchar_t *sUnicodeStr = new wchar_t[ nUnicodeLen*sizeof(wchar_t) + 16 ]; // Use UTF-8 multibyte unicode decoding to convert to wide string. // This is potentially not porrtable, for different platforms, alternative function must be used. #if defined(LINUX) mbstowcs( sUnicodeStr, sUTF_8_Str, nUTF_8_Len ); sUnicodeStr[ nUTF_8_Len ] = 0; #else MultiByteToWideChar( CP_UTF8,0,sUTF_8_Str,-1,sUnicodeStr,nUnicodeLen ); #endif wstring unicodeStr = sUnicodeStr; wstring::size_type nPos; while ((nPos = unicodeStr.find(L"\\n",0,2))!=wstring::npos) { unicodeStr.replace(nPos,2,L"\n"); } SAFE_DELETE_ARRAY(sUnicodeStr); if (m_keysMap.find(sKeyString) != m_keysMap.end()) { //m_pSystem->GetILog()->Log("\003$6Localized String '%s' Already Loaded!", sKeyString); } else { int nID = (int)m_vStrings.size(); char szLowerCaseKey[1024]; strcpy(szLowerCaseKey,sKeyString); strlwr(szLowerCaseKey); m_vStrings.push_back( unicodeStr ); m_vEnglishStrings.push_back( sEnglishString ); m_keysMap[szLowerCaseKey] = nID; m_pLanguageStriptObject->AddString( sKeyString,nID ); } } return (true); } ////////////////////////////////////////////////////////////////////////// // Loads a string-table from a XML-file. bool CStringTableMgr::LoadStringTable(string sFileName) { return LoadExcelXmlSpreadsheet( sFileName ); /* string sPath = "LANGUAGES/" + m_sLanguage + "/" + sFileName; //check if this table has already been loaded FileNamesMapItor nit = m_mapLoadedTables.find(sPath); if (nit!=m_mapLoadedTables.end()) return (true); XDOM::IXMLDOMDocumentPtr pDoc=m_pSystem->CreateXMLDocument(); // load xml-file if (!pDoc->load(sPath.c_str())) return (false); m_mapLoadedTables[sFileName] = NULL; XDOM::IXMLDOMNodeListPtr pNodeList; XDOM::IXMLDOMNodePtr pString; XDOM::IXMLDOMNodePtr pEnum; XDOM::IXMLDOMNodePtr pValue; pNodeList=pDoc->getElementsByTagName("string"); if(!pNodeList) return true; pNodeList->reset(); // get all strings in table while (pString=pNodeList->nextNode()) { pEnum=pString->getAttribute("enum"); pValue=pString->getAttribute("value"); if((pEnum!=NULL) && (pValue!=NULL)) { wstring::size_type nPos; int nID=m_vStrings.size(); //wstring str=pValue->getText(); wstring str=pValue->getTextW(); while ((nPos=str.find(L"\\n",0,2))!=wstring::npos) { str.replace(nPos,2,L"\n"); } m_vStrings.push_back(str); string keyString=pEnum->getText(); m_pLanguageStriptObject->AddString(pEnum->getText(),nID); } } return (true); */ } ////////////////////////////////////////////////////////////////////////// bool CStringTableMgr::LookupString( const char *sKey,wstring &sLocalizedString ) { assert(sKey); // Label sign. if (sKey[0] == '@') { char szLowKey[512]; strcpy(szLowKey,sKey); strlwr(szLowKey); int nId = stl::find_in_map( m_keysMap,szLowKey,-1 ); if (nId >= 0) { sLocalizedString = m_vStrings[nId]; return true; } else { nId = stl::find_in_map( m_keysMap,szLowKey+1,-1 ); if (nId >= 0) { sLocalizedString = m_vStrings[nId]; return true; } else { //GameWarning( "Localized string for Label <%s> not found",sKey ); AppendToUnicodeString(sKey, sLocalizedString); return false; } } } else { //GameWarning( "Not a valid localized string Label <%s>, must start with @ symbol",sKey ); } AppendToUnicodeString(sKey, sLocalizedString); return false; } ////////////////////////////////////////////////////////////////////////// bool CStringTableMgr::LookupEnglishString( const char *sKey, string &sLocalizedString ) { assert(sKey); // Label sign. if (sKey[0] == '@') { char szLowKey[512]; strcpy(szLowKey,sKey); strlwr(szLowKey); int nId = stl::find_in_map( m_keysMap,szLowKey,-1 ); if (nId >= 0) { sLocalizedString = m_vEnglishStrings[nId]; return true; } else { nId = stl::find_in_map( m_keysMap,szLowKey+1,-1 ); if (nId >= 0) { sLocalizedString = m_vEnglishStrings[nId]; return true; } else { //GameWarning( "Localized string for Label <%s> not found",sKey ); AppendToAsciiString(sKey, sLocalizedString); return false; } } } else { //GameWarning( "Not a valid localized string Label <%s>, must start with @ symbol",sKey ); } AppendToAsciiString(sKey, sLocalizedString); return false; } ////////////////////////////////////////////////////////////////////////// void CStringTableMgr::Localize(const string &sString, wstring &sLocalizedString, bool bEnglish ) { // scan the string bool done = false; int len = sString.length(); int curpos = 0; while (!done) { int pos = sString.find_first_of("@", curpos); if (pos == string::npos) { // did not find anymore, so we are done done = true; pos = len; } // found an occurence // we have skipped a few characters, so copy them over if (pos > curpos) { // skip AppendToUnicodeString(sString.substr(curpos, pos - curpos), sLocalizedString); curpos = pos; } if (curpos == pos) { // find the end of the label int endpos = sString.find_first_of(" ", curpos); if (endpos == string::npos) { // have reached the end done = true; endpos = len; } if (endpos > curpos) { // localize token if (bEnglish) { string sLocalizedToken; LookupEnglishString(sString.substr(curpos, endpos - curpos).c_str(), sLocalizedToken); AppendToUnicodeString(sLocalizedToken, sLocalizedString); } else { wstring sLocalizedToken; LookupString(sString.substr(curpos, endpos - curpos).c_str(), sLocalizedToken); // append sLocalizedString+=sLocalizedToken; } curpos = endpos; } } } } ////////////////////////////////////////////////////////////////////////// bool CStringTableMgr::GetSubtitleLabel(const char *_szFilename,char *szLabel) { if (!_szFilename || !szLabel) return (false); char szFilename[512]; strcpy(szFilename,_szFilename); strlwr(szFilename); ptrdiff_t len = strlen(szFilename)-1; if (len<=1) return (false); char szFilenameCopy[512]; strcpy(szFilenameCopy,szFilename); char *szIn=&szFilenameCopy[len]; // remove path while ((len>0) && (*szIn) && (*szIn!='/') && (*szIn!='\\')) { szIn--; len--; } szIn++; len = strlen(szIn)-1; if (len<=1) return (false); // strip extension while (szIn[len]) { if (szIn[len]=='.') { break; } len--; if (!len) { return (false); } } char szTemp[256]; strncpy(szTemp, szIn, len); szTemp[len] = 0; int nId = stl::find_in_map( m_keysMap,szTemp,-1 ); if (nId>=0) { // changed this, was copying szIn (original filename) into szLabel sprintf(szLabel,"@%s",szTemp); return (true); } return (false); } ////////////////////////////////////////////////////////////////////////// void CStringTableMgr::AppendToUnicodeString(const string& sSource, wstring &sDest) { std::vector swTemp; swTemp.resize(sSource.size()+1); #if defined(LINUX) swprintf (&swTemp[0], swTemp.size(), L"%S", sSource.c_str()); #else swprintf (&swTemp[0], L"%S", sSource.c_str()); #endif wstring tmp(&swTemp[0]); sDest += tmp; } ////////////////////////////////////////////////////////////////////////// void CStringTableMgr::AppendToAsciiString(const string& sSource, string &sDest) { std::vector sTemp; sTemp.resize(sSource.size()+1); sprintf (&sTemp[0], "%S", sSource.c_str()); string tmp(&sTemp[0]); sDest += tmp; }