GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/translation/poparser.cpp Lines: 100 108 92.6 %
Date: 2018-09-09 Branches: 78 120 65.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2018  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
3
PoParser::PoParser() :
34
    mLang(),
35
    mFile(),
36
    mLine(),
37
    mMsgId(),
38
    mMsgStr(),
39
    mDict(nullptr),
40
    mReadingId(false),
41
    mReadingStr(false),
42
15
    mSkipId(false)
43
{
44
3
}
45
46
3
void PoParser::openFile(const std::string &name)
47
{
48
    int size;
49
6
    const char *buf = VirtFs::loadFile(getFileName(name), size);
50
51
3
    if (buf != nullptr)
52
    {
53
12
        mFile.str(std::string(buf, size));
54
2
        delete [] buf;
55
    }
56
    else
57
    {
58
1
        mFile.clear();
59
    }
60
3
}
61
62
3
PoDict *PoParser::load(const std::string &restrict lang,
63
                       const std::string &restrict fileName,
64
                       PoDict *restrict const dict)
65
{
66
6
    logger->log("loading lang: %s, file: %s", lang.c_str(), fileName.c_str());
67
68
3
    setLang(lang);
69
3
    if (dict == nullptr)
70
3
        mDict = getDict();
71
    else
72
        mDict = dict;
73
74
3
    if (fileName.empty())
75
        openFile(mLang);
76
    else
77
3
        openFile(fileName);
78
79
6
    mMsgId.clear();
80
3
    mMsgStr.clear();
81
82
    // cycle by msgid+msgstr
83
3635
    while (readLine())
84
    {
85
        // reading msgid
86
16788
        while (readMsgId())
87
        {
88
13156
            if (!readLine())
89
                break;
90
        }
91
92
7264
        if (!mMsgId.empty())
93
        {
94
            // if we got msgid then reading msgstr
95
7338
            while (readMsgStr())
96
            {
97
3710
                if (!readLine())
98
                    break;
99
            }
100
        }
101
102

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

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

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

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

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




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

408
    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
3
    return strprintf("translations/%s.po", lang.c_str());
271
}
272
273
3
PoDict *PoParser::getDict() const
274
{
275
3
    return new PoDict(mLang);
276
}
277
278
7144
void PoParser::convertStr(std::string &str)
279
{
280
7144
    if (str.empty())
281
        return;
282
283

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

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

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