539 lines
12 KiB
C++
539 lines
12 KiB
C++
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 <StlUtils.h>
|
|
#include <IInput.h>
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// 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<wchar_t> 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<char> sTemp;
|
|
sTemp.resize(sSource.size()+1);
|
|
|
|
sprintf (&sTemp[0], "%S", sSource.c_str());
|
|
string tmp(&sTemp[0]);
|
|
sDest += tmp;
|
|
} |