ManaPlus
poparser.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2012-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
23 
24 #include "fs/virtfs/fs.h"
25 
26 #include "utils/stringutils.h"
27 
29 
30 #include "logger.h"
31 
32 #include "debug.h"
33 
35  mLang(),
36  mFile(),
37  mLine(),
38  mMsgId(),
39  mMsgStr(),
40  mDict(nullptr),
41  mReadingId(false),
42  mReadingStr(false),
43  mSkipId(false)
44 {
45 }
46 
47 void PoParser::openFile(const std::string &name)
48 {
49  int size;
50  const char *buf = VirtFs::loadFile(getFileName(name), size);
51 
52  if (buf != nullptr)
53  {
54  mFile.str(std::string(buf, size));
55  delete [] buf;
56  }
57  else
58  {
59  mFile.clear();
60  }
61 }
62 
63 PoDict *PoParser::load(const std::string &restrict lang,
64  const std::string &restrict fileName,
65  PoDict *restrict const dict)
66 {
67  logger->log("loading lang: %s, file: %s", lang.c_str(), fileName.c_str());
68 
69  setLang(lang);
70  if (dict == nullptr)
71  mDict = getDict();
72  else
73  mDict = dict;
74 
75  if (fileName.empty())
76  openFile(mLang);
77  else
79 
80  mMsgId.clear();
81  mMsgStr.clear();
82 
83  // cycle by msgid+msgstr
84  while (readLine())
85  {
86  // reading msgid
87  while (readMsgId())
88  {
89  if (!readLine())
90  break;
91  }
92 
93  if (!mMsgId.empty())
94  {
95  // if we got msgid then reading msgstr
96  while (readMsgStr())
97  {
98  if (!readLine())
99  break;
100  }
101  }
102 
103  if (!mMsgId.empty() && !mMsgStr.empty())
104  {
105 // logger->log("add key: " + mMsgId);
106 // logger->log("add value: " + mMsgStr);
107 
110  // store key and value
111  mDict->set(mMsgId, mMsgStr);
112  }
113 
114  mMsgId.clear();
115  mMsgStr.clear();
116  }
117 
118  return mDict;
119 }
120 
122 {
123  char line[1001];
124  if (!mFile.getline(line, 1000))
125  return false;
126  // skip plurals msgid if present
127  if (strStartWith(line, "msgid_plural \""))
128  {
129  if (!mFile.getline(line, 1000))
130  return false;
131  }
132  mLine = line;
133  return true;
134 }
135 
137 {
138  // if we reading msgstr then stop here
139  if (mReadingStr)
140  return false;
141 
142  const std::string msgId1("msgid \"");
143 
144  // check if in reading process
145  if (mReadingId)
146  {
147  // if we get empty line in file then stop reading
148  if (mLine.empty())
149  {
150  mReadingId = false;
151  return false;
152  }
153  else if (checkLine())
154  {
155  // reading text from: "text"
156  mMsgId.append(mLine.substr(1, mLine.size() - 2));
157  mLine.clear();
158  return true;
159  }
160  // stop reading in other case
161  mReadingId = false;
162  return false;
163  }
164 
165  // check line start from msgid "
166  if (strStartWith(mLine, msgId1))
167  {
168  if (!mSkipId)
169  { // translation not fuzzed and can be processed
170  mReadingId = true;
171  const size_t msgId1Size = msgId1.size();
172  // reading text from: msgid "text"
173  mMsgId.append(mLine.substr(msgId1Size,
174  mLine.size() - 1 - msgId1Size));
175  }
176  else
177  { // skipped fuzzed translation. reset skip flag
178  mSkipId = false;
179  }
180  mLine.clear();
181  return true;
182  }
183  else if (mLine == "#, fuzzy")
184  { // check for fuzzy translation
185  mSkipId = true;
186  mLine.clear();
187  return true;
188  }
189  // stop reading if we don't read msgid before
190  return mMsgId.empty();
191 }
192 
194 {
195  // normal msgstr
196  const std::string msgStr1("msgstr \"");
197  // plurals first msgstr
198  const std::string msgStr2("msgstr[0] \"");
199 
200  // check if in reading process
201  if (mReadingStr)
202  {
203  // if we get empty line in file then stop reading
204  if (mLine.empty())
205  {
206  mReadingStr = false;
207  return false;
208  }
209  if (checkLine())
210  {
211  // reading text from: "text"
212  mMsgStr.append(mLine.substr(1, mLine.size() - 2));
213  mLine.clear();
214  return true;
215  }
216  // stop reading in other case
217  mReadingStr = false;
218  }
219  else
220  {
221  // check line start from msgstr "
222  if (strStartWith(mLine, msgStr1))
223  {
224  mReadingStr = true;
225  const size_t msgStr1Size = msgStr1.size();
226  // reading text from: msgstr "text"
227  mMsgStr.append(mLine.substr(msgStr1Size,
228  mLine.size() - 1 - msgStr1Size));
229  mLine.clear();
230  return true;
231  }
232  // checl list start from msgstr[0] "
233  else if (strStartWith(mLine, msgStr2))
234  {
235  mReadingStr = true;
236  const size_t msgStr2Size = msgStr2.size();
237  // reading text from: msgstr[0] "text"
238  mMsgStr.append(mLine.substr(msgStr2Size,
239  mLine.size() - 1 - msgStr2Size));
240  mLine.clear();
241  return true;
242  }
243  }
244 
245  // stop reading in other case
246  return false;
247 }
248 
250 {
251  const size_t sz = mLine.size();
252  // check is line in format: "text"
253  return sz > 2 && mLine[0] == '\"' && mLine[sz - 1] == '\"';
254 }
255 
257 {
258  return new PoDict("");
259 }
260 
261 bool PoParser::checkLang(const std::string &lang)
262 {
263  // check is po file exists
264  return VirtFs::exists(getFileName(lang));
265 }
266 
267 std::string PoParser::getFileName(const std::string &lang)
268 {
269  // get po file name from lang name
270 // logger->log("getFileName: translations/%s.po", lang.c_str());
271  return strprintf("translations/%s.po", lang.c_str());
272 }
273 
275 {
276  return new PoDict(mLang);
277 }
278 
279 void PoParser::convertStr(std::string &str)
280 {
281  if (str.empty())
282  return;
283 
284  replaceAll(str, "\\n", "\n");
285  replaceAll(str, "\\\"", "\"");
286  replaceAll(str, "\\\\", "\\");
287 }
void log(const char *const log_text,...)
Definition: logger.cpp:269
Definition: podict.h:33
void set(const std::string &key, const std::string &value)
Definition: podict.h:56
bool mSkipId
Definition: poparser.h:85
PoDict * mDict
Definition: poparser.h:79
PoDict * load(const std::string &lang, const std::string &fileName, PoDict *const dict)
Definition: poparser.cpp:63
void openFile(const std::string &name)
Definition: poparser.cpp:47
std::string mLine
Definition: poparser.h:73
bool readMsgId()
Definition: poparser.cpp:136
bool mReadingStr
Definition: poparser.h:83
bool readMsgStr()
Definition: poparser.cpp:193
PoParser()
Definition: poparser.cpp:34
PoDict * getDict() const
Definition: poparser.cpp:274
bool checkLine() const
Definition: poparser.cpp:249
static std::string getFileName(const std::string &lang)
Definition: poparser.cpp:267
static PoDict * getEmptyDict()
Definition: poparser.cpp:256
std::string mLang
Definition: poparser.h:67
static bool checkLang(const std::string &lang)
Definition: poparser.cpp:261
void setLang(const std::string &lang)
Definition: poparser.h:47
std::string mMsgId
Definition: poparser.h:75
bool readLine()
Definition: poparser.cpp:121
static void convertStr(std::string &str)
Definition: poparser.cpp:279
std::string mMsgStr
Definition: poparser.h:77
std::istringstream mFile
Definition: poparser.h:70
bool mReadingId
Definition: poparser.h:81
#define restrict
Definition: localconsts.h:165
#define nullptr
Definition: localconsts.h:45
Logger * logger
Definition: logger.cpp:89
int size()
Definition: emotedb.cpp:306
const char * loadFile(std::string filename, int &fileSize)
Definition: fs.cpp:859
bool exists(std::string name)
Definition: fs.cpp:124
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)
std::string strprintf(const char *const format,...)
bool strStartWith(const std::string &str1, const std::string &str2)
std::string fileName
Definition: testmain.cpp:39