GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/translation/poparser.cpp Lines: 100 108 92.6 %
Date: 2017-11-29 Branches: 77 124 62.1 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2017  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "utils/translation/poparser.h"
22
23
#include "fs/virtfs/fs.h"
24
25
#include "utils/stringutils.h"
26
27
#include "utils/translation/podict.h"
28
29
#include "logger.h"
30
31
#include "debug.h"
32
33
6
PoParser::PoParser() :
34
    mLang(),
35
    mFile(),
36
    mLine(),
37
    mMsgId(),
38
    mMsgStr(),
39
    mDict(nullptr),
40
    mReadingId(false),
41
    mReadingStr(false),
42
30
    mSkipId(false)
43
{
44
6
}
45
46
6
void PoParser::openFile(const std::string &name)
47
{
48
    int size;
49
12
    const char *buf = VirtFs::loadFile(getFileName(name), size);
50
51
6
    if (buf != nullptr)
52
    {
53
20
        mFile.str(std::string(buf, size));
54
4
        delete [] buf;
55
    }
56
    else
57
    {
58
2
        mFile.clear();
59
    }
60
6
}
61
62
6
PoDict *PoParser::load(const std::string &restrict lang,
63
                       const std::string &restrict fileName,
64
                       PoDict *restrict const dict)
65
{
66
18
    logger->log("loading lang: %s, file: %s", lang.c_str(), fileName.c_str());
67
68
6
    setLang(lang);
69
6
    if (dict == nullptr)
70
6
        mDict = getDict();
71
    else
72
        mDict = dict;
73
74
6
    if (fileName.empty())
75
        openFile(mLang);
76
    else
77
6
        openFile(fileName);
78
79
12
    mMsgId.clear();
80
6
    mMsgStr.clear();
81
82
    // cycle by msgid+msgstr
83
7270
    while (readLine())
84
    {
85
        // reading msgid
86
33576
        while (readMsgId())
87
        {
88
26312
            if (!readLine())
89
                break;
90
        }
91
92
14528
        if (!mMsgId.empty())
93
        {
94
            // if we got msgid then reading msgstr
95
14676
            while (readMsgStr())
96
            {
97
7420
                if (!readLine())
98
                    break;
99
            }
100
        }
101
102

21788
        if (!mMsgId.empty() && !mMsgStr.empty())
103
        {
104
//            logger->log("add key: " + mMsgId);
105
//            logger->log("add value: " + mMsgStr);
106
107
7144
            convertStr(mMsgId);
108
7144
            convertStr(mMsgStr);
109
            // store key and value
110
7144
            mDict->set(mMsgId, mMsgStr);
111
        }
112
113
14528
        mMsgId.clear();
114
7264
        mMsgStr.clear();
115
    }
116
117
6
    return mDict;
118
}
119
120
41002
bool PoParser::readLine()
121
{
122
    char line[1001];
123
82004
    if (!mFile.getline(line, 1000))
124
        return false;
125
    // skip plurals msgid if present
126


286944
    if (strStartWith(line, "msgid_plural \""))
127
    {
128
24
        if (!mFile.getline(line, 1000))
129
            return false;
130
    }
131
40992
    mLine = line;
132
    return true;
133
}
134
135
33576
bool PoParser::readMsgId()
136
{
137
    // if we reading msgstr then stop here
138
33576
    if (mReadingStr)
139
        return false;
140
141
100728
    const std::string msgId1("msgid \"");
142
143
    // check if in reading process
144
33576
    if (mReadingId)
145
    {
146
        // if we get empty line in file then stop reading
147
15616
        if (mLine.empty())
148
        {
149
            mReadingId = false;
150
            return false;
151
        }
152
544
        else if (checkLine())
153
        {
154
            // reading text from: "text"
155
1632
            mMsgId.append(mLine.substr(1, mLine.size() - 2));
156
1088
            mLine.clear();
157
544
            return true;
158
        }
159
        // stop reading in other case
160
7264
        mReadingId = false;
161
7264
        return false;
162
    }
163
164
    // check line start from msgid "
165

25768
    if (strStartWith(mLine, msgId1))
166
    {
167
7268
        if (!mSkipId)
168
        {   // translation not fuzzed and can be processed
169
7264
            mReadingId = true;
170
7264
            const size_t msgId1Size = msgId1.size();
171
            // reading text from: msgid "text"
172
21792
            mMsgId.append(mLine.substr(msgId1Size,
173
7264
                mLine.size() - 1 - msgId1Size));
174
        }
175
        else
176
        {   // skipped fuzzed translation. reset skip flag
177
4
            mSkipId = false;
178
        }
179
14536
        mLine.clear();
180
7268
        return true;
181
    }
182
37000
    else if (mLine == "#, fuzzy")
183
    {   // check for fuzzy translation
184
4
        mSkipId = true;
185
8
        mLine.clear();
186
4
        return true;
187
    }
188
    // stop reading if we don't read msgid before
189
36992
    return mMsgId.empty();
190
}
191
192
14676
bool PoParser::readMsgStr()
193
{
194
    // normal msgstr
195
58704
    const std::string msgStr1("msgstr \"");
196
    // plurals first msgstr
197
58704
    const std::string msgStr2("msgstr[0] \"");
198
199
    // check if in reading process
200
14676
    if (mReadingStr)
201
    {
202
        // if we get empty line in file then stop reading
203
14832
        if (mLine.empty())
204
        {
205
7244
            mReadingStr = false;
206
7244
            return false;
207
        }
208
160
        if (checkLine())
209
        {
210
            // reading text from: "text"
211
480
            mMsgStr.append(mLine.substr(1, mLine.size() - 2));
212
320
            mLine.clear();
213
160
            return true;
214
        }
215
        // stop reading in other case
216
12
        mReadingStr = false;
217
    }
218
    else
219
    {
220
        // check line start from msgstr "
221

7260
        if (strStartWith(mLine, msgStr1))
222
        {
223
7248
            mReadingStr = true;
224
7248
            const size_t msgStr1Size = msgStr1.size();
225
            // reading text from: msgstr "text"
226
21744
            mMsgStr.append(mLine.substr(msgStr1Size,
227
7248
                mLine.size() - 1 - msgStr1Size));
228
14496
            mLine.clear();
229
7248
            return true;
230
        }
231
        // checl list start from msgstr[0] "
232

12
        else if (strStartWith(mLine, msgStr2))
233
        {
234
12
            mReadingStr = true;
235
12
            const size_t msgStr2Size = msgStr2.size();
236
            // reading text from: msgstr[0] "text"
237
36
            mMsgStr.append(mLine.substr(msgStr2Size,
238
12
                mLine.size() - 1 - msgStr2Size));
239
24
            mLine.clear();
240
12
            return true;
241
        }
242
    }
243
244
    // stop reading in other case
245
    return false;
246
}
247
248
bool PoParser::checkLine() const
249
{
250
7980
    const size_t sz = mLine.size();
251
    // check is line in format: "text"
252




16664
    return sz > 2 && mLine[0] == '\"' && mLine[sz - 1] == '\"';
253
}
254
255
152
PoDict *PoParser::getEmptyDict()
256
{
257

608
    return new PoDict("");
258
}
259
260
bool PoParser::checkLang(const std::string &lang)
261
{
262
    // check is po file exists
263
    return VirtFs::exists(getFileName(lang));
264
}
265
266
std::string PoParser::getFileName(const std::string &lang)
267
{
268
    // get po file name from lang name
269
//    logger->log("getFileName: translations/%s.po", lang.c_str());
270
6
    return strprintf("translations/%s.po", lang.c_str());
271
}
272
273
6
PoDict *PoParser::getDict() const
274
{
275
6
    return new PoDict(mLang);
276
}
277
278
14288
void PoParser::convertStr(std::string &str)
279
{
280
14288
    if (str.empty())
281
        return;
282
283

100016
    replaceAll(str, "\\n", "\n");
284

100016
    replaceAll(str, "\\\"", "\"");
285

100016
    replaceAll(str, "\\\\", "\\");
286
}