OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
C4LangStringTable.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // Loads StringTbl* and replaces $..$-strings by localized versions
17 
18 #include "C4Include.h"
20 
21 #include "lib/C4InputValidation.h"
22 
23 bool C4LangStringTable::HasTranslation(const std::string &text) const
24 {
25  if (strings.empty())
26  PopulateStringTable();
27  return strings.find(text) != strings.end();
28 }
29 
30 const std::string &C4LangStringTable::Translate(const std::string &text) const
31 {
32  if (strings.empty())
33  PopulateStringTable();
34  Table::const_iterator it = strings.find(text);
35  if (it == strings.end())
36  {
37  throw NoSuchTranslation(text);
38  }
39  return it->second;
40 }
41 
42 void C4LangStringTable::PopulateStringTable() const
43 {
44  assert(strings.empty());
45 
46  strings.clear();
47  std::string key, value;
48 
49  // read table
50  const char *data = GetData();
51  if (!data || !*data)
52  return;
53 
54  enum { PSTS_Key, PSTS_Val } state = PSTS_Key;
55  do
56  {
57  if (state == PSTS_Key)
58  {
59  if (*data == '=')
60  {
61  state = PSTS_Val;
62  }
63  else if (*data == '\0' || *data == '\n' || *data == '\r')
64  {
65  if (!key.empty() && key[0]!='#')
66  LogF(R"(%s: string table entry without a value: "%s")", GetFilePath() ? GetFilePath() : "<unknown>", key.c_str());
67  key.clear();
68  }
69  else
70  {
71  key.push_back(*data);
72  }
73  }
74  else
75  {
76  if (*data == '\0' || *data == '\n' || *data == '\r')
77  {
78  strings.insert(std::make_pair(key, value));
79  key.clear(); value.clear();
80  state = PSTS_Key;
81  }
82  else
83  {
84  value.push_back(*data);
85  }
86  }
87  }
88  while (*data++);
89 }
90 
92 {
93  if (!rBuf.getLength())
94  {
95  return;
96  }
97  // grab char ptr from buf
98  const char *Data = rBuf.getData();
99 
100  // Find Replace Positions
101  int iScriptLen = SLen(Data);
102  struct RP { const char *Pos; std::string String; unsigned int Len; RP *Next; } *pRPList = nullptr, *pRPListEnd = nullptr;
103  for (const char *pPos = SSearch(Data, "$"); pPos; pPos = SSearch(pPos, "$"))
104  {
105  // Get name
106  char szStringName[C4MaxName + 1];
107  SCopyUntil(pPos, szStringName, '$', C4MaxName); pPos += SLen(szStringName) + 1;
108  if (*(pPos-1) != '$') continue;
109  // valid?
110  const char *pPos2 = szStringName;
111  while (*pPos2)
112  if (!IsIdentifier(*(pPos2++)))
113  break;
114  if (*pPos2) continue;
115  // check termination
116  try
117  {
118  // search in string table
119  std::string pStrTblEntry = Translate(szStringName);
120  // add new replace-position entry
121  RP *pnRP = new RP;
122  pnRP->Pos = pPos - SLen(szStringName) - 2;
123  pnRP->String = pStrTblEntry;
124  pnRP->Len = SLen(szStringName) + 2;
125  pnRP->Next = nullptr;
126  pRPListEnd = (pRPListEnd ? pRPListEnd->Next : pRPList) = pnRP;
127  // calculate new script length
128  iScriptLen += pStrTblEntry.size() - pnRP->Len;
129  }
130  catch (NoSuchTranslation &)
131  {
132  LogF(R"(%s: string table entry not found: "%s")", GetFilePath() ? GetFilePath() : "<unknown>", szStringName);
133  }
134  }
135  // Alloc new Buffer
136  char *pNewBuf;
137  StdStrBuf sNewBuf;
138  sNewBuf.SetLength(iScriptLen);
139  pNewBuf = sNewBuf.getMData();
140  // Copy data
141  const char *pRPos = Data; char *pWPos = pNewBuf;
142  for (RP *pRPPos = pRPList; pRPPos; pRPPos = pRPPos->Next)
143  {
144  // copy preceding string data
145  SCopy(pRPos, pWPos, pRPPos->Pos - pRPos);
146  pWPos += pRPPos->Pos - pRPos;
147  // copy string
148  SCopyUntil(pRPPos->String.c_str(), pWPos, '\n');
149  SReplaceChar(pWPos, '\r', '\0');
150  // advance
151  pRPos = pRPPos->Pos + pRPPos->Len;
152  pWPos += SLen(pWPos);
153  }
154  SCopy(pRPos, pWPos);
155 
156  while (pRPList)
157  {
158  RP *pRP = pRPList;
159  pRPList = pRP->Next;
160  delete pRP;
161  }
162 
163  // assign this buf
164  rTarget.Clear();
165  rTarget.Take(std::move(sNewBuf));
166 }
167 
169 {
170  ReplaceStrings(rBuf, rBuf);
171 }
const char * getData() const
Definition: StdBuf.h:442
const std::string & Translate(const std::string &text) const
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:152
C4String * String(const char *str)
Definition: C4AulDefFunc.h:30
void Clear()
Definition: StdBuf.h:466
const char * GetData() const
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:363
size_t SLen(const char *sptr)
Definition: Standard.h:74
char * getMData()
Definition: StdBuf.h:443
StdCopyStrBuf Data
void Take(char *pnData)
Definition: StdBuf.h:457
const unsigned int C4MaxName
void ReplaceStrings(StdStrBuf &rBuf)
bool IsIdentifier(char cChar)
Definition: Standard.cpp:90
size_t getLength() const
Definition: StdBuf.h:445
void SetLength(size_t iLength)
Definition: StdBuf.h:509
const char * GetFilePath() const
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:250
void SCopyUntil(const char *szSource, char *sTarget, char cUntil, int iMaxL, int iIndex)
Definition: Standard.cpp:168
void SReplaceChar(char *str, char fc, char tc)
Definition: Standard.cpp:348
bool HasTranslation(const std::string &text) const