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"
19 
20 #include <utility>
21 #include <vector>
22 
24 #include "lib/C4InputValidation.h"
25 
27 
28 bool C4LangStringTable::HasTranslation(const std::string &text) const
29 {
30  if (strings.empty())
31  PopulateStringTable();
32  return strings.find(text) != strings.end();
33 }
34 
35 const std::string &C4LangStringTable::Translate(const std::string &text) const
36 {
37  if (strings.empty())
38  PopulateStringTable();
39  Table::const_iterator it = strings.find(text);
40  if (it == strings.end())
41  {
42  throw NoSuchTranslation(text);
43  }
44  return it->second;
45 }
46 
47 void C4LangStringTable::PopulateStringTable() const
48 {
49  assert(strings.empty());
50 
51  strings.clear();
52  std::string key, value;
53 
54  // read table
55  const char *data = GetData();
56  if (!data || !*data)
57  return;
58 
59  enum { PSTS_Key, PSTS_Val } state = PSTS_Key;
60  do
61  {
62  if (state == PSTS_Key)
63  {
64  if (*data == '=')
65  {
66  state = PSTS_Val;
67  }
68  else if (*data == '\0' || *data == '\n' || *data == '\r')
69  {
70  if (!key.empty() && key[0]!='#')
71  LogF("%s: string table entry without a value: \"%s\"", GetFilePath() ? GetFilePath() : "<unknown>", key.c_str());
72  key.clear();
73  }
74  else
75  {
76  key.push_back(*data);
77  }
78  }
79  else
80  {
81  if (*data == '\0' || *data == '\n' || *data == '\r')
82  {
83  strings.insert(std::make_pair(key, value));
84  key.clear(); value.clear();
85  state = PSTS_Key;
86  }
87  else
88  {
89  value.push_back(*data);
90  }
91  }
92  }
93  while (*data++);
94 }
95 
97 {
98  if (!rBuf.getLength())
99  {
100  return;
101  }
102  // grab char ptr from buf
103  const char *Data = rBuf.getData();
104 
105  // Find Replace Positions
106  int iScriptLen = SLen(Data);
107  struct RP { const char *Pos; std::string String; unsigned int Len; RP *Next; } *pRPList = nullptr, *pRPListEnd = nullptr;
108  for (const char *pPos = SSearch(Data, "$"); pPos; pPos = SSearch(pPos, "$"))
109  {
110  // Get name
111  char szStringName[C4MaxName + 1];
112  SCopyUntil(pPos, szStringName, '$', C4MaxName); pPos += SLen(szStringName) + 1;
113  if (*(pPos-1) != '$') continue;
114  // valid?
115  const char *pPos2 = szStringName;
116  while (*pPos2)
117  if (!IsIdentifier(*(pPos2++)))
118  break;
119  if (*pPos2) continue;
120  // check termination
121  try
122  {
123  // search in string table
124  std::string pStrTblEntry = Translate(szStringName);
125  // add new replace-position entry
126  RP *pnRP = new RP;
127  pnRP->Pos = pPos - SLen(szStringName) - 2;
128  pnRP->String = pStrTblEntry;
129  pnRP->Len = SLen(szStringName) + 2;
130  pnRP->Next = nullptr;
131  pRPListEnd = (pRPListEnd ? pRPListEnd->Next : pRPList) = pnRP;
132  // calculate new script length
133  iScriptLen += pStrTblEntry.size() - pnRP->Len;
134  }
135  catch (NoSuchTranslation &)
136  {
137  LogF("%s: string table entry not found: \"%s\"", GetFilePath() ? GetFilePath() : "<unknown>", szStringName);
138  }
139  }
140  // Alloc new Buffer
141  char *pNewBuf;
142  StdStrBuf sNewBuf;
143  sNewBuf.SetLength(iScriptLen);
144  pNewBuf = sNewBuf.getMData();
145  // Copy data
146  const char *pRPos = Data; char *pWPos = pNewBuf;
147  for (RP *pRPPos = pRPList; pRPPos; pRPPos = pRPPos->Next)
148  {
149  // copy preceding string data
150  SCopy(pRPos, pWPos, pRPPos->Pos - pRPos);
151  pWPos += pRPPos->Pos - pRPos;
152  // copy string
153  SCopyUntil(pRPPos->String.c_str(), pWPos, '\n');
154  SReplaceChar(pWPos, '\r', '\0');
155  // advance
156  pRPos = pRPPos->Pos + pRPPos->Len;
157  pWPos += SLen(pWPos);
158  }
159  SCopy(pRPos, pWPos);
160 
161  while (pRPList)
162  {
163  RP *pRP = pRPList;
164  pRPList = pRP->Next;
165  delete pRP;
166  }
167 
168  // assign this buf
169  rTarget.Clear();
170  rTarget.Take(std::move(sNewBuf));
171 }
172 
174 {
175  ReplaceStrings(rBuf, rBuf);
176 }
const char * getData() const
Definition: StdBuf.h:450
const std::string & Translate(const std::string &text) const
void SCopy(const char *szSource, char *sTarget, size_t iMaxL)
Definition: Standard.cpp:122
C4String * String(const char *str)
Definition: C4AulDefFunc.h:31
void Clear()
Definition: StdBuf.h:474
const char * GetData() const
const char * SSearch(const char *szString, const char *szIndex)
Definition: Standard.cpp:333
size_t SLen(const char *sptr)
Definition: Standard.h:78
char * getMData()
Definition: StdBuf.h:451
StdCopyStrBuf Data
void Take(char *pnData)
Definition: StdBuf.h:465
const unsigned int C4MaxName
void ReplaceStrings(StdStrBuf &rBuf)
bool IsIdentifier(char cChar)
Definition: Standard.cpp:67
size_t getLength() const
Definition: StdBuf.h:453
void SetLength(size_t iLength)
Definition: StdBuf.h:517
const char * GetFilePath() const
bool LogF(const char *strMessage,...)
Definition: C4Log.cpp:253
void SCopyUntil(const char *szSource, char *sTarget, char cUntil, int iMaxL, int iIndex)
Definition: Standard.cpp:138
void SReplaceChar(char *str, char fc, char tc)
Definition: Standard.cpp:318
bool HasTranslation(const std::string &text) const