GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/stringutils.cpp Lines: 598 611 97.9 %
Date: 2018-06-18 21:15:20 Branches: 433 528 82.0 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2007-2009  The Mana World Development Team
4
 *  Copyright (C) 2009-2010  The Mana Developers
5
 *  Copyright (C) 2011-2018  The ManaPlus Developers
6
 *
7
 *  This file is part of The ManaPlus Client.
8
 *
9
 *  This program is free software; you can redistribute it and/or modify
10
 *  it under the terms of the GNU General Public License as published by
11
 *  the Free Software Foundation; either version 2 of the License, or
12
 *  any later version.
13
 *
14
 *  This program is distributed in the hope that it will be useful,
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 *  GNU General Public License for more details.
18
 *
19
 *  You should have received a copy of the GNU General Public License
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "utils/stringutils.h"
24
25
#include "const/utils/utf8.h"
26
27
#ifdef DYECMD
28
#include "utils/cast.h"
29
#else  // DYECMD
30
#include "resources/iteminfo.h"
31
#include "resources/db/itemdb.h"
32
#endif  // DYECMD
33
34
#include "utils/gettext.h"
35
#include "utils/foreach.h"
36
37
#include <algorithm>
38
#include <sstream>
39
40
#ifdef WIN32
41
#include <sys/time.h>
42
#endif  // WIN32
43
44
#include "debug.h"
45
46
11515
std::string &trim(std::string &str)
47
{
48
11343
    size_t pos = str.find_last_not_of(' ');
49
11343
    if (pos != std::string::npos)
50
    {
51
11337
        str.erase(pos + 1);
52
11337
        pos = str.find_first_not_of(' ');
53
54
11337
        if (pos != std::string::npos)
55
11337
            str.erase(0, pos);
56
    }
57
    else
58
    {
59
        // There is nothing else but whitespace in the string
60
        str.clear();
61
    }
62
11515
    return str;
63
}
64
65
179
std::string &toLower(std::string &str)
66
{
67
1660
    std::transform(str.begin(), str.end(), str.begin(), &tolower);
68
179
    return str;
69
}
70
71
8
std::string &toUpper(std::string &str)
72
{
73
32
    std::transform(str.begin(), str.end(), str.begin(), &toupper);
74
8
    return str;
75
}
76
77
18030
unsigned int atox(const std::string &str)
78
{
79
18030
    unsigned int value = 0;
80
18030
    if (sscanf(str.c_str(), "0x%06x", &value) != 0)
81
18028
        return value;
82
    return 0;
83
}
84
85
4
const char *ipToString(const uint32_t address)
86
{
87
    static char asciiIP[18];
88
89
16
    snprintf(asciiIP, sizeof(asciiIP), "%i.%i.%i.%i",
90
            CAST_U8(address),
91
4
            CAST_U8(address >> 8),
92
4
            CAST_U8(address >> 16),
93
4
            CAST_U8(address >> 24));
94
4
    asciiIP[17] = 0;
95
96
4
    return asciiIP;
97
}
98
99
236575
std::string strprintf(const char *const format, ...)
100
{
101
    char buf[257];
102
    va_list args;
103
236575
    va_start(args, format);
104
236575
    size_t nb = vsnprintf(buf, 256, format, args);
105
236575
    buf[256] = 0;
106
236575
    va_end(args);
107
236575
    if (nb < 256)
108
709719
        return buf;
109
110
    // The static size was not big enough, try again with a dynamic allocation.
111
2
    ++nb;
112
2
    char *buf2 = new char[nb];
113
2
    va_start(args, format);
114
2
    vsnprintf(buf2, nb, format, args);
115
2
    va_end(args);
116
6
    std::string res(buf2);
117
2
    delete [] buf2;
118
2
    return res;
119
}
120
121
20
std::string removeColors(std::string msg)
122
{
123

44
    for (unsigned int f = 0; f < msg.length() - 2 && msg.length() > 2; f++)
124
    {
125
82
        while (msg.length() > f + 2 && msg.at(f) == '#'
126

62
               && msg.at(f + 1) == '#')
127
        {
128
10
            msg = msg.erase(f, 3);
129
        }
130
    }
131
20
    return msg;
132
}
133
134
42647058
int compareStrI(const std::string &a, const std::string &b)
135
{
136
42647058
    std::string::const_iterator itA = a.begin();
137
42647058
    const std::string::const_iterator endA = a.end();
138
42647058
    std::string::const_iterator itB = b.begin();
139
42647058
    const std::string::const_iterator endB = b.end();
140
141

125547170
    for (; itA < endA && itB < endB; ++itA, ++itB)
142
    {
143
55543986
        const int comp = tolower(*itA) - tolower(*itB);
144
55543986
        if (comp != 0)
145
            return comp;
146
    }
147
148
    // Check string lengths
149

971954
    if (itA == endA && itB == endB)
150
        return 0;
151
303564
    else if (itA == endA)
152
        return -1;
153
    else
154
295158
        return 1;
155
}
156
157
8
const std::string findSameSubstring(const std::string &restrict str1,
158
                                    const std::string &restrict str2)
159
{
160
8
    const int minLength = str1.length() > str2.length()
161
8
        ? CAST_S32(str2.length()) : CAST_S32(str1.length());
162
40
    for (int f = 0; f < minLength; f ++)
163
    {
164
102
        if (str1.at(f) != str2.at(f))
165
2
            return str1.substr(0, f);
166
    }
167
6
    return str1.substr(0, minLength);
168
}
169
170
10
const std::string findSameSubstringI(const std::string &restrict s1,
171
                                     const std::string &restrict s2)
172
{
173
20
    std::string str1 = s1;
174
20
    std::string str2 = s2;
175
10
    toLower(str1);
176
10
    toLower(str2);
177
178
10
    const size_t minLength = str1.length() > str2.length()
179
10
        ? str2.length() : str1.length();
180
56
    for (size_t f = 0; f < minLength; f ++)
181
    {
182
96
        if (str1.at(f) != str2.at(f))
183
2
            return s1.substr(0, f);
184
    }
185
8
    return s1.substr(0, minLength);
186
}
187
188
10
size_t findI(std::string str, std::string subStr)
189
{
190
20
    str = toLower(str);
191
20
    subStr = toLower(subStr);
192
10
    return str.find(subStr);
193
}
194
195
10
size_t findI(std::string text, const StringVect &list)
196
{
197
10
    toLower(text);
198
54
    FOR_EACH (StringVectCIter, i, list)
199
    {
200
54
        std::string subStr = *i;
201
40
        subStr = toLower(subStr);
202
20
        const size_t idx = text.find(subStr);
203
20
        if (idx != std::string::npos)
204
12
            return idx;
205
    }
206
    return std::string::npos;
207
}
208
209
274
size_t findAny(const std::string &restrict text,
210
               const std::string &restrict chars,
211
               const size_t pos)
212
{
213
274
    size_t idx = std::string::npos;
214
274
    const size_t sz = chars.size();
215
556
    for (size_t f = 0; f < sz; f ++)
216
    {
217
282
        const size_t idx2 = text.find(chars[f], pos);
218
282
        if (idx2 != std::string::npos && idx2 < idx)
219
214
            idx = idx2;
220
    }
221
274
    return idx;
222
}
223
224
namespace
225
{
226
    unsigned int base = 94;
227
    unsigned int start = 33;
228
}  // namespace
229
230
8
const std::string encodeStr(unsigned int value, const unsigned int size)
231
{
232
    std::string buf;
233
234
    do
235
    {
236
24
        buf += CAST_S8(value % base + start);
237
12
        value /= base;
238
    }
239
12
    while (value != 0u);
240
241
16
    while (buf.length() < size)
242
8
        buf += CAST_S8(start);
243
8
    return buf;
244
}
245
246
247
10
unsigned int decodeStr(const std::string &str)
248
{
249
10
    if (str.empty())
250
        return 0;
251
252
8
    int res = str[0] - start;
253
8
    int mult = 1;
254
20
    for (unsigned int f = 1; f < str.length(); f ++)
255
    {
256
12
        mult *= base;
257
24
        res = res + (str[f] - start) * mult;
258
    }
259
8
    return res;
260
}
261
262
14
std::string extractNameFromSprite(std::string str)
263
{
264
12
    const size_t pos1 = str.rfind('.');
265
12
    if (pos1 != std::string::npos)
266
    {
267
10
        size_t pos2 = str.rfind('/');
268
10
        const size_t pos3 = str.rfind('\\');
269
10
        if (pos3 != std::string::npos)
270
        {
271
6
            if (pos2 == std::string::npos || pos3 > pos2)
272
4
                pos2 = pos3;
273
        }
274
10
        if (pos2 == std::string::npos)
275
2
            pos2 = CAST_SIZE(-1);
276
277
10
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
278
10
        if (size > 0)
279
20
            str = str.substr(pos2 + 1, size);
280
    }
281
14
    return str;
282
}
283
284
14
std::string removeSpriteIndex(std::string str)
285
{
286
12
    const size_t pos1 = str.rfind('[');
287
288
12
    if (pos1 != std::string::npos)
289
    {
290
10
        size_t pos2 = str.rfind('/');
291
10
        const size_t pos3 = str.rfind('\\');
292
10
        if (pos3 != std::string::npos)
293
        {
294
6
            if (pos2 == std::string::npos || pos3 > pos2)
295
4
                pos2 = pos3;
296
        }
297
10
        if (pos2 == std::string::npos)
298
2
            pos2 = CAST_SIZE(-1);
299
300
10
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
301
10
        if (size > 0)
302
20
            str = str.substr(pos2 + 1, size);
303
    }
304
14
    return str;
305
}
306
307
6
const char* getSafeUtf8String(const std::string &text)
308
{
309
6
    const size_t sz = text.size();
310
6
    const size_t size = sz + UTF8_MAX_SIZE;
311
6
    char *const buf = new char[size];
312
12
    memcpy(buf, text.c_str(), sz);
313
12
    memset(buf + sz, 0, UTF8_MAX_SIZE);
314
6
    return buf;
315
}
316
317
19158
void getSafeUtf8String(std::string text, char *const buf)
318
{
319
19158
    if (buf == nullptr)
320
        return;
321
19156
    const size_t sz = text.size();
322
19156
    const size_t size = sz + UTF8_MAX_SIZE;
323
19156
    if (size > 65500)
324
    {
325
4
        text = text.substr(0, 65500);
326
2
        const size_t sz1 = text.size();
327
4
        memcpy(buf, text.c_str(), sz1);
328
2
        memset(buf + sz1, 0, UTF8_MAX_SIZE);
329
    }
330
    else
331
    {
332
38308
        memcpy(buf, text.c_str(), sz);
333
19154
        memset(buf + sz, 0, UTF8_MAX_SIZE);
334
    }
335
}
336
337
44
std::string getFileName(const std::string &path)
338
{
339
44
    size_t pos1 = path.rfind('/');
340
44
    const size_t pos2 = path.rfind('\\');
341
44
    if (pos1 == std::string::npos)
342
        pos1 = pos2;
343
40
    else if (pos2 != std::string::npos && pos2 > pos1)
344
2
        pos1 = pos2;
345
346
44
    if (pos1 == std::string::npos)
347
        return path;
348
40
    return path.substr(pos1 + 1);
349
}
350
351
1008
std::string getFileDir(const std::string &path)
352
{
353
1008
    size_t pos1 = path.rfind('/');
354
1008
    const size_t pos2 = path.rfind('\\');
355
1008
    if (pos1 == std::string::npos)
356
        pos1 = pos2;
357
766
    else if (pos2 != std::string::npos && pos2 > pos1)
358
2
        pos1 = pos2;
359
360
1008
    if (pos1 == std::string::npos)
361
        return path;
362
766
    return path.substr(0, pos1);
363
}
364
365
43186
std::string& replaceAll(std::string& context,
366
                        const std::string &restrict from,
367
                        const std::string &restrict to)
368
{
369
43186
    if (from.empty())
370
        return context;
371
43180
    size_t lookHere = 0;
372
    size_t foundHere;
373
43180
    const size_t fromSize = from.size();
374
43180
    const size_t toSize = to.size();
375
44004
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
376
    {
377
412
        context.replace(foundHere, fromSize, to);
378
412
        lookHere = foundHere + toSize;
379
    }
380
    return context;
381
}
382
383
56494
void replaceRecursiveAll(std::string& context,
384
                         const std::string &restrict from,
385
                         const char to)
386
{
387
56494
    size_t lookHere = 0;
388
    size_t foundHere;
389
56494
    const size_t fromSize = from.size();
390
57454
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
391
    {
392
480
        context.replace(foundHere, fromSize, 1, to);
393
480
        lookHere = foundHere;
394
    }
395
56494
}
396
397
77
bool getBoolFromString(const std::string &text)
398
{
399
154
    std::string txt = text;
400
77
    toLower(trim(txt));
401


272
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
402
        return true;
403


152
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
404
        return false;
405
    else
406
28
        return static_cast<bool>(atoi(txt.c_str()));
407
}
408
409
22
void replaceSpecialChars(std::string &text)
410
{
411
22
    size_t pos1 = text.find('&');
412
54
    while (pos1 != std::string::npos)
413
    {
414
20
        const size_t idx = pos1 + 1;
415
20
        const size_t sz = text.size();
416
20
        if (idx >= sz)
417
            break;
418
419
        size_t f;
420
76
        for (f = idx; f < sz; f ++)
421
        {
422

84
            if (text[f] < '0' || text[f] > '9')
423
                break;
424
        }
425

30
        if (idx + 1 < f && text[f] == ';')
426
        {
427
40
            std::string str(" ");
428
50
            str[0] = CAST_S8(atoi(text.substr(
429
                idx, f - idx).c_str()));
430

60
            text = text.substr(0, pos1).append(str).append(text.substr(f + 1));
431
10
            pos1 += 1;
432
        }
433
        else
434
        {
435
6
            pos1 = f + 1;
436
        }
437
438
16
        pos1 = text.find('&', pos1);
439
    }
440
22
}
441
442
196
std::string normalize(const std::string &name)
443
{
444
392
    std::string normalized = name;
445
784
    return toLower(trim(normalized));
446
}
447
448
12
void splitToIntSet(std::set<int> &tokens,
449
                   const std::string &text,
450
                   const char separator)
451
{
452
24
    std::stringstream ss(text);
453
12
    std::string item;
454

108
    while (std::getline(ss, item, separator))
455
84
        tokens.insert(atoi(item.c_str()));
456
12
}
457
458
12
std::list<int> splitToIntList(const std::string &text,
459
                              const char separator)
460
{
461
12
    std::list<int> tokens;
462
24
    std::stringstream ss(text);
463
12
    std::string item;
464

108
    while (std::getline(ss, item, separator))
465
84
        tokens.push_back(atoi(item.c_str()));
466
467
12
    return tokens;
468
}
469
470
66
std::list<std::string> splitToStringList(const std::string &text,
471
                                         const char separator)
472
{
473
66
    std::list<std::string> tokens;
474
132
    std::stringstream ss(text);
475
66
    std::string item;
476

180
    while (std::getline(ss, item, separator))
477
24
        tokens.push_back(item);
478
479
66
    return tokens;
480
}
481
482
7102
void splitToStringVector(StringVect &tokens,
483
                         const std::string &text,
484
                         const char separator)
485
{
486
14204
    std::stringstream ss(text);
487
7102
    std::string item;
488

35940
    while (std::getline(ss, item, separator))
489
    {
490
21736
        item = trim(item);
491
10868
        if (!item.empty())
492
10832
            tokens.push_back(item);
493
    }
494
7102
}
495
496
14
void splitToStringSet(std::set<std::string> &tokens,
497
                      const std::string &text,
498
                      const char separator)
499
{
500
28
    std::stringstream ss(text);
501
14
    std::string item;
502

96
    while (std::getline(ss, item, separator))
503
    {
504
68
        item = trim(item);
505
34
        if (!item.empty())
506
            tokens.insert(item);
507
    }
508
14
}
509
510
14
void splitToIntVector(STD_VECTOR<int> &tokens,
511
                      const std::string &text,
512
                      const char separator)
513
{
514
28
    std::stringstream ss(text);
515
14
    std::string item;
516

96
    while (std::getline(ss, item, separator))
517
    {
518
68
        item = trim(item);
519
34
        if (!item.empty())
520
96
            tokens.push_back(atoi(item.c_str()));
521
    }
522
14
}
523
524
14
std::string combineDye(std::string file,
525
                       const std::string &dye)
526
{
527
14
    if (dye.empty())
528
        return file;
529
8
    const size_t pos = file.find_last_of('|');
530
8
    if (pos != std::string::npos)
531
24
        return file.substr(0, pos).append("|").append(dye);
532
8
    return file.append("|").append(dye);
533
}
534
535
20
std::string combineDye2(std::string file,
536
                        const std::string &dye)
537
{
538
20
    if (dye.empty())
539
        return file;
540
541
8
    const size_t pos = file.find_last_of('|');
542
8
    if (pos != std::string::npos)
543
    {
544
8
        const std::string dye1 = file.substr(pos + 1);
545
8
        std::string str;
546
8
        file = file.substr(0, pos);
547
8
        const std::list<std::string> list1 = splitToStringList(dye1, ';');
548
8
        const std::list<std::string> list2 = splitToStringList(dye, ';');
549
14
        for (std::list<std::string>::const_iterator it1 = list1.begin(),
550
16
             it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
551

10
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
552
        {
553

24
            str.append(*it1).append(":").append(*it2).append(";");
554
        }
555
16
        return file.append("|").append(str);
556
    }
557
    return file;
558
}
559
560
14
std::string combineDye3(std::string file,
561
                        const std::string &dye)
562
{
563
14
    if (dye.empty())
564
        return file;
565
566
6
    const size_t pos = file.find_last_of('|');
567
6
    if (pos != std::string::npos)
568
    {
569
8
        const std::string dye1 = file.substr(pos + 1);
570
8
        std::string str;
571
8
        file = file.substr(0, pos);
572
8
        const std::list<std::string> list1 = splitToStringList(dye1, ';');
573
8
        const std::list<std::string> list2 = splitToStringList(dye, ';');
574
14
        for (std::list<std::string>::const_iterator it1 = list1.begin(),
575
16
             it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
576

10
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
577
        {
578

24
            str.append(*it1).append(":").append(*it2).append(";");
579
        }
580
16
        return file.append("|").append(str);
581
    }
582
4
    if (file.empty())
583
        return file;
584
4
    return file.append("|").append(dye);
585
}
586
587
62
std::string packList(const std::list<std::string> &list)
588
{
589
124
    std::list<std::string>::const_iterator i = list.begin();
590
    std::string str;
591
100
    while (i != list.end())
592
    {
593
76
        str.append(*i).append("|");
594
        ++ i;
595
    }
596
62
    const size_t sz = str.size();
597
62
    if (sz > 1)
598
16
        str = str.substr(0, sz - 1);
599
62
    return str;
600
}
601
602
50
std::list<std::string> unpackList(const std::string &str)
603
{
604
50
    return splitToStringList(str, '|');
605
}
606
607
10
std::string stringToHexPath(const std::string &str)
608
{
609
10
    if (str.empty())
610
6
        return "";
611
612
8
    std::string hex = strprintf("%%%2x/", CAST_U32(str[0]));
613
20
    for (unsigned f = 1, fsz = CAST_U32(str.size());
614
20
         f < fsz; f ++)
615
    {
616
48
        hex.append(strprintf("%%%2x", CAST_U32(str[f])));
617
    }
618
8
    return hex;
619
}
620
621
8
void deleteCharLeft(std::string &str,
622
                    unsigned *const pos)
623
{
624
8
    if (pos == nullptr)
625
        return;
626
627
8
    while (*pos > 0)
628
    {
629
8
        (*pos)--;
630
16
        const int v = str[*pos];
631
8
        str.erase(*pos, 1);
632
8
        if ((v & 192) != 128)
633
            break;
634
    }
635
}
636
637
220288
bool findLast(const std::string &restrict str1,
638
              const std::string &restrict str2)
639
{
640
220288
    const size_t s1 = str1.size();
641
220288
    const size_t s2 = str2.size();
642
220288
    if (s1 < s2)
643
        return false;
644
461532
    if (str1.substr(s1 - s2) == str2)
645
        return true;
646
91178
    return false;
647
}
648
649
8
bool findFirst(const std::string &restrict str1,
650
               const std::string &restrict str2)
651
{
652
8
    const size_t s1 = str1.size();
653
8
    const size_t s2 = str2.size();
654
8
    if (s1 < s2)
655
        return false;
656
18
    if (str1.substr(0, s2) == str2)
657
        return true;
658
2
    return false;
659
}
660
661
100
bool findCutLast(std::string &restrict str1,
662
                 const std::string &restrict str2)
663
{
664
100
    const size_t s1 = str1.size();
665
100
    const size_t s2 = str2.size();
666
100
    if (s1 < s2)
667
        return false;
668
294
    if (str1.substr(s1 - s2) == str2)
669
    {
670
160
        str1 = str1.substr(0, s1 - s2);
671
80
        return true;
672
    }
673
    return false;
674
}
675
676
8
void cutLast(std::string &restrict str1,
677
             const std::string &restrict str2)
678
{
679
8
    const size_t s1 = str1.size();
680
8
    const size_t s2 = str2.size();
681
8
    if (s1 < s2)
682
        return;
683
18
    if (str1.substr(s1 - s2) == str2)
684
8
        str1 = str1.substr(0, s1 - s2);
685
}
686
687
394
bool findCutFirst(std::string &restrict str1,
688
                  const std::string &restrict str2)
689
{
690
394
    const size_t s1 = str1.size();
691
394
    const size_t s2 = str2.size();
692
394
    if (s1 < s2)
693
        return false;
694
1176
    if (str1.substr(0, s2) == str2)
695
    {
696
304
        str1 = str1.substr(s2);
697
152
        return true;
698
    }
699
    return false;
700
}
701
702
8
void cutFirst(std::string &restrict str1,
703
              const std::string &restrict str2)
704
{
705
8
    const size_t s1 = str1.size();
706
8
    const size_t s2 = str2.size();
707
8
    if (s1 < s2)
708
        return;
709
18
    if (str1.substr(0, s2) == str2)
710
8
        str1 = str1.substr(s2);
711
}
712
713
8
std::string &removeProtocol(std::string &url)
714
{
715
8
    const size_t i = url.find("://");
716
8
    if (i != std::string::npos)
717
8
        url = url.substr(i + 3);
718
8
    return url;
719
}
720
721
74062
bool strStartWith(const std::string &restrict str1,
722
                  const std::string &restrict str2)
723
{
724
74062
    const size_t sz2 = str2.size();
725
74062
    if (str1.size() < sz2)
726
        return false;
727
192750
    return str1.substr(0, sz2) == str2;
728
}
729
730
5
std::string getDateString()
731
{
732
    char buffer[80];
733
    time_t rawtime;
734
5
    time(&rawtime);
735
5
    const tm *const timeinfo = localtime(&rawtime);
736
737
5
    strftime(buffer, 79, "%Y-%m-%d", timeinfo);
738
15
    return std::string(buffer);
739
}
740
741
std::string getDateTimeString()
742
{
743
    char buffer[80];
744
    time_t rawtime;
745
    time(&rawtime);
746
    const tm *const timeinfo = localtime(&rawtime);
747
748
    strftime(buffer, 79, "%Y-%m-%d %H:%M:%S", timeinfo);
749
    return std::string(buffer);
750
}
751
752
58
signed char parseBoolean(const std::string &value)
753
{
754
116
    std::string txt = value;
755
58
    toLower(trim(txt));
756


196
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
757
        return 1;
758


108
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
759
        return 0;
760
    else
761
        return -1;
762
}
763
764
12
std::string encodeLinkText(std::string data)
765
{
766

96
    return replaceAll(data, "|", "\342\235\230");
767
}
768
769
2
std::string decodeLinkText(std::string data)
770
{
771

16
    return replaceAll(data, "\342\235\230", "|");
772
}
773
774
6
std::string toStringPrint(const unsigned int val)
775
{
776
    static char str[100];
777
6
    snprintf(str, sizeof(str), "%u 0x%x", val, val);
778
6
    str[99] = 0;
779
18
    return str;
780
}
781
782
1630
std::string toString(uint32_t num)
783
{
784
    char buf[30];
785
1630
    buf[29] = '\0';
786
1630
    size_t idx = 28;
787
    do
788
3152
        buf[idx--] = CAST_8((num % 10) + '0');
789
3152
    while ((num /= 10) != 0);
790
4890
    return buf + idx + 1;
791
}
792
793
14
std::string toString(uint64_t num)
794
{
795
    char buf[100];
796
14
    buf[99] = '\0';
797
14
    size_t idx = 98;
798
    do
799
14
        buf[idx--] = CAST_8((num % 10) + '0');
800
14
    while ((num /= 10) != 0);
801
42
    return buf + idx + 1;
802
}
803
804
4
std::string toString(uint16_t num)
805
{
806
    char buf[10];
807
4
    buf[9] = '\0';
808
4
    size_t idx = 8;
809
    do
810
16
        buf[idx--] = CAST_8((num % 10) + '0');
811
16
    while ((num /= 10) != 0);
812
12
    return buf + idx + 1;
813
}
814
815
2
std::string toString(unsigned char num)
816
{
817
    char buf[5];
818
2
    buf[4] = '\0';
819
2
    size_t idx = 3;
820
    do
821
6
        buf[idx--] = CAST_8((num % 10) + '0');
822
6
    while ((num /= 10) != 0);
823
6
    return buf + idx + 1;
824
}
825
826
257136
std::string toString(int32_t num)
827
{
828
    char buf[30];
829
257136
    bool useSign(false);
830
257136
    buf[29] = '\0';
831
257136
    size_t idx = 28;
832
833
257136
    if (num < 0)
834
    {
835
3204
        useSign = true;
836
3204
        num = -num;
837
    }
838
    do
839
1288680
        buf[idx--] = CAST_8((num % 10) + '0');
840
1288680
    while ((num /= 10) != 0);
841
257136
    if (useSign)
842
3204
        buf[idx--] = '-';
843
771408
    return buf + idx + 1;
844
}
845
846
604
std::string toString(const float num)
847
{
848
604
    return strprintf("%f", num);
849
}
850
851
10
std::string toString(const double num)
852
{
853
10
    return strprintf("%f", static_cast<float>(num));
854
}
855
856
14
bool isDigit(const std::string &str)
857
{
858
14
    if (str.empty())
859
        return false;
860
    const size_t sz = str.size();
861
40
    for (size_t f = 0; f < sz; f ++)
862
    {
863
22
        const char &chr = str[f];
864
22
        if (chr < '0' || chr > '9')
865
            return false;
866
    }
867
    return true;
868
}
869
870
12
void secureChatCommand(std::string &str)
871
{
872

30
    if (str[0] == '/' || str[0] == '@' || str[0] == '#')
873
12
        str = "_" + str;
874
12
}
875
876
10
bool parse2Int(const std::string &args,
877
               int &x,
878
               int &y)
879
{
880
10
    bool isValid = false;
881
10
    size_t pos = args.find(' ');
882
10
    if (pos == std::string::npos)
883
6
        pos = args.find(',');
884
10
    if (pos != std::string::npos)
885
    {
886
8
        if (pos + 1 < args.length())
887
        {
888
24
            x = atoi(args.substr(0, pos).c_str());
889
24
            y = atoi(args.substr(pos + 1, args.length()).c_str());
890
6
            isValid = true;
891
        }
892
    }
893
10
    return isValid;
894
}
895
896
8
bool parse2Str(const std::string &args,
897
               std::string &str1,
898
               std::string &str2)
899
{
900
8
    bool isValid = false;
901
8
    size_t pos = args.find(' ');
902
8
    if (pos == std::string::npos)
903
6
        pos = args.find(',');
904
8
    if (pos != std::string::npos)
905
    {
906
6
        if (pos + 1 < args.length())
907
        {
908
8
            str1 = args.substr(0, pos);
909
8
            str2 = args.substr(pos + 1, args.length());
910
4
            isValid = true;
911
        }
912
    }
913
8
    return isValid;
914
}
915
916
12
uint32_t parseNumber(const std::string &str)
917
{
918
12
    uint32_t i = 0;
919
12
    int idx = 0;
920

48
    if (strStartWith(str, "0x"))
921
        idx = 2;
922

14
    else if (str[0] == 'h' || str[0] == 'x')
923
        idx = 1;
924
    if (idx > 0)
925
24
        sscanf(str.substr(idx).c_str(), "%10x", &i);
926
    else
927
8
        i = atoi(str.c_str());
928
12
    return i;
929
}
930
931
12
std::string removeToken(std::string &str,
932
                        const std::string &token)
933
{
934
12
    const size_t idx = str.find(token);
935
12
    if (idx > 0 && idx != std::string::npos)
936
8
        str = str.substr(idx + 1);
937
    else
938
        str.clear();
939
12
    return str;
940
}
941
942
std::string timeToStr(const uint32_t time)
943
{
944
    char buf[101];
945
    const time_t tempTime = time;
946
    tm *const timeInfo = localtime(&tempTime);
947
    if (strftime(&buf[0], 100, "%Y-%m-%d_%H-%M-%S", timeInfo) != 0u)
948
        return std::string(buf);
949
    return "unknown";
950
}
951
952
20
std::string timeDiffToString(int timeDiff)
953
{
954
20
    std::string str;
955
956
20
    const int weeks = timeDiff / 60 / 60 / 24 / 7;
957
20
    if (weeks > 0)
958
    {
959
        // TRANSLATORS: uptime command
960
20
        str = strprintf(ngettext(N_("%d week"), N_("%d weeks"),
961
            weeks), weeks);
962
10
        timeDiff -= weeks * 60 * 60 * 24 * 7;
963
    }
964
965
20
    const int days = timeDiff / 60 / 60 / 24;
966
20
    if (days > 0)
967
    {
968
10
        if (!str.empty())
969
8
            str.append(", ");
970
        // TRANSLATORS: uptime command
971
30
        str.append(strprintf(ngettext(N_("%d day"), N_("%d days"),
972
            days), days));
973
10
        timeDiff -= days * 60 * 60 * 24;
974
    }
975
20
    const int hours = timeDiff / 60 / 60;
976
20
    if (hours > 0)
977
    {
978
8
        if (!str.empty())
979
6
            str.append(", ");
980
        // TRANSLATORS: uptime command
981
24
        str.append(strprintf(ngettext(N_("%d hour"), N_("%d hours"),
982
            hours), hours));
983
8
        timeDiff -= hours * 60 * 60;
984
    }
985
20
    const int min = timeDiff / 60;
986
20
    if (min > 0)
987
    {
988
6
        if (!str.empty())
989
4
            str.append(", ");
990
        // TRANSLATORS: uptime command
991
18
        str.append(strprintf(ngettext(N_("%d minute"), N_("%d minutes"),
992
            min), min));
993
6
        timeDiff -= min * 60;
994
    }
995
996
20
    if (timeDiff > 0)
997
    {
998
4
        if (!str.empty())
999
2
            str.append(", ");
1000
        // TRANSLATORS: uptime command
1001
12
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1002
            timeDiff), timeDiff));
1003
    }
1004
20
    if (str.empty())
1005
    {
1006
        // TRANSLATORS: uptime command
1007
6
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1008
            0), 0));
1009
    }
1010
20
    return str;
1011
}
1012
1013
20
std::string escapeString(std::string str)
1014
{
1015

140
    replaceAll(str, "\"", "\\\"");
1016
40
    return "\"" + str + "\"";
1017
}
1018
1019
28234
void sanitizePath(std::string &path)
1020
{
1021
#ifdef WIN32
1022
    const char sepStr = '\\';
1023
    const std::string sep2Str = "\\\\";
1024
    const std::string sepWrongStr = "/";
1025
#else
1026
28234
    const char sepStr = '/';
1027
112936
    const std::string sep2Str = "//";
1028
112936
    const std::string sepWrongStr = "\\";
1029
#endif
1030
28234
    replaceRecursiveAll(path, sepWrongStr, sepStr);
1031
28234
    replaceRecursiveAll(path, sep2Str, sepStr);
1032
28234
}
1033
1034
18326
std::string pathJoin(std::string str1,
1035
                     const std::string &str2)
1036
{
1037
#ifdef WIN32
1038
    const char sep = '\\';
1039
    std::string sepStr = "\\";
1040
#else
1041
18326
    const char sep = '/';
1042
73304
    std::string sepStr = "/";
1043
#endif
1044
1045
18326
    if (str1.empty())
1046
    {
1047
16
        if (str2[0] == sep)
1048
            return str2;
1049
12
        return sepStr.append(str2);
1050
    }
1051
18310
    const size_t sz1 = str1.size();
1052
18310
    if (str2.empty())
1053
    {
1054
12
        if (str1[sz1 - 1] == sep)
1055
            return str1;
1056
        return str1.append(sepStr);
1057
    }
1058
36608
    if (str1[sz1 - 1] == sep)
1059
    {
1060
5173
        if (str2[0] == sep)
1061
72
            return str1.append(str2.substr(1));
1062
5155
        return str1.append(str2);
1063
    }
1064
    else
1065
    {
1066
13131
        if (str2[0] == sep)
1067
4
            return str1.append(str2);
1068
26254
        return str1.append(sepStr).append(str2);
1069
    }
1070
}
1071
1072
672
std::string pathJoin(std::string str1,
1073
                     const std::string &str2,
1074
                     const std::string &str3)
1075
{
1076
#ifdef WIN32
1077
    const char sep = '\\';
1078
    std::string sepStr = "\\";
1079
#else
1080
672
    const char sep = '/';
1081
2688
    std::string sepStr = "/";
1082
#endif
1083
1084
672
    if (str1.empty())
1085
    {
1086
16
        return pathJoin(str2, str3);
1087
    }
1088
664
    size_t sz1 = str1.size();
1089
664
    if (str2.empty())
1090
    {
1091
8
        return pathJoin(str1, str3);
1092
    }
1093
660
    if (str3.empty())
1094
    {
1095
4
        return pathJoin(str1, str2);
1096
    }
1097
1316
    if (str1[sz1 - 1] == sep)
1098
    {
1099
630
        if (str2[0] == sep)
1100
36
            str1.append(str2.substr(1));
1101
        else
1102
            str1.append(str2);
1103
    }
1104
    else
1105
    {
1106
28
        if (str2[0] == sep)
1107
            str1.append(str2);
1108
        else
1109
24
            str1.append(sepStr).append(str2);
1110
    }
1111
1112
658
    sz1 = str1.size();
1113
1316
    if (str1[sz1 - 1] == sep)
1114
    {
1115
12
        if (str3[0] == sep)
1116
16
            return str1.append(str3.substr(1));
1117
8
        return str1.append(str3);
1118
    }
1119
    else
1120
    {
1121
646
        if (str3[0] == sep)
1122
10
            return str1.append(str3);
1123
1272
        return str1.append(sepStr).append(str3);
1124
    }
1125
}
1126
1127
26
std::string urlJoin(std::string str1,
1128
                    const std::string &str2)
1129
{
1130
26
    const char sep = '/';
1131
104
    std::string sepStr = "/";
1132
1133
26
    if (str1.empty())
1134
    {
1135
6
        if (str2[0] == sep)
1136
            return str2;
1137
4
        return sepStr.append(str2);
1138
    }
1139
20
    const size_t sz1 = str1.size();
1140
20
    if (str2.empty())
1141
    {
1142
4
        if (str1[sz1 - 1] == sep)
1143
            return str1;
1144
        return str1.append(sepStr);
1145
    }
1146
36
    if (str1[sz1 - 1] == sep)
1147
    {
1148
8
        if (str2[0] == sep)
1149
16
            return str1.append(str2.substr(1));
1150
4
        return str1.append(str2);
1151
    }
1152
    else
1153
    {
1154
10
        if (str2[0] == sep)
1155
4
            return str1.append(str2);
1156
12
        return str1.append(sepStr).append(str2);
1157
    }
1158
}
1159
1160
#ifndef DYECMD
1161
86
void replaceItemLinks(std::string &msg)
1162
{
1163
    // Check for item link
1164
86
    size_t start2 = msg.find('[');
1165
86
    size_t sz = msg.size();
1166
376
    while (start2 + 1 < sz &&
1167

238
           start2 != std::string::npos &&
1168
156
           msg[start2 + 1] != '@')
1169
    {
1170
78
        const size_t end = msg.find(']', start2);
1171

78
        if (start2 + 1 != end &&
1172
            end != std::string::npos)
1173
        {
1174
            // Catch multiple embeds and ignore them
1175
            // so it doesn't crash the client.
1176

80
            while ((msg.find('[', start2 + 1) != std::string::npos) &&
1177
                   (msg.find('[', start2 + 1) < end))
1178
            {
1179
                start2 = msg.find('[', start2 + 1);
1180
            }
1181
1182

50
            if (start2 + 1 < sz &&
1183
50
                end < sz &&
1184
                end > start2 + 1)
1185
            {
1186
72
                std::string itemStr = msg.substr(start2 + 1, end - start2 - 1);
1187
1188
72
                StringVect parts;
1189
38
                splitToStringVector(parts, itemStr, ',');
1190
38
                if (parts.empty())
1191
4
                    return;
1192
1193
34
                const ItemInfo &itemInfo = ItemDB::get(parts[0]);
1194
34
                const int itemId = itemInfo.getId();
1195
34
                if (itemId != 0)
1196
                {
1197
68
                    std::string temp = strprintf("@@%d", itemId);
1198
102
                    std::string name = parts[0];
1199
34
                    msg.erase(start2 + 1, end - start2 - 1);
1200
102
                    parts.erase(parts.begin());
1201
34
                    if (!parts.empty())
1202
                        name.clear();
1203
1204
174
                    FOR_EACH (StringVectCIter, it, parts)
1205
                    {
1206
12
                        std:: string str = *it;
1207
4
                        trim(str);
1208
4
                        const ItemInfo &itemInfo2 = ItemDB::get(str);
1209
4
                        const int cardId = itemInfo2.getId();
1210
4
                        if (cardId != 0)
1211
12
                            temp.append(strprintf(",%d", cardId));
1212
                    }
1213
34
                    temp.append("|");
1214
34
                    temp.append(name);
1215
34
                    temp.append("@@");
1216
68
                    msg.insert(start2 + 1, temp);
1217
34
                    sz = msg.size();
1218
                }
1219
            }
1220
        }
1221
74
        start2 = msg.find('[', start2 + 1);
1222
    }
1223
}
1224
#else  // DYECMD
1225
1226
void replaceItemLinks(std::string &msg A_UNUSED)
1227
{
1228
}
1229
#endif  // DYECMD