GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/stringutils.cpp Lines: 623 636 98.0 %
Date: 2021-03-17 Branches: 472 564 83.7 %

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

22
    for (unsigned int f = 0; f < msg.length() - 2 && msg.length() > 2; f++)
125
    {
126

58
        while (msg.length() > f + 2 && msg.at(f) == '#'
127

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

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

488126
    if (itA == endA && itB == endB)
151
        return 0;
152
152453
    else if (itA == endA)
153
        return -1;
154
    else
155
148232
        return 1;
156
}
157
158
4
const std::string findSameSubstring(const std::string &restrict str1,
159
                                    const std::string &restrict str2)
160
{
161
4
    const int minLength = str1.length() > str2.length()
162
4
        ? CAST_S32(str2.length()) : CAST_S32(str1.length());
163
20
    for (int f = 0; f < minLength; f ++)
164
    {
165
51
        if (str1.at(f) != str2.at(f))
166
1
            return str1.substr(0, f);
167
    }
168
3
    return str1.substr(0, minLength);
169
}
170
171
5
const std::string findSameSubstringI(const std::string &restrict s1,
172
                                     const std::string &restrict s2)
173
{
174
10
    std::string str1 = s1;
175
10
    std::string str2 = s2;
176
5
    toLower(str1);
177
5
    toLower(str2);
178
179
5
    const size_t minLength = str1.length() > str2.length()
180
5
        ? str2.length() : str1.length();
181
28
    for (size_t f = 0; f < minLength; f ++)
182
    {
183
48
        if (str1.at(f) != str2.at(f))
184
1
            return s1.substr(0, f);
185
    }
186
4
    return s1.substr(0, minLength);
187
}
188
189
5
size_t findI(std::string str, std::string subStr)
190
{
191
10
    str = toLower(str);
192
10
    subStr = toLower(subStr);
193
5
    return str.find(subStr);
194
}
195
196
5
size_t findI(std::string text, const StringVect &list)
197
{
198
5
    toLower(text);
199
27
    FOR_EACH (StringVectCIter, i, list)
200
    {
201
27
        std::string subStr = *i;
202
20
        subStr = toLower(subStr);
203
10
        const size_t idx = text.find(subStr);
204
10
        if (idx != std::string::npos)
205
6
            return idx;
206
    }
207
    return std::string::npos;
208
}
209
210
137
size_t findAny(const std::string &restrict text,
211
               const std::string &restrict chars,
212
               const size_t pos)
213
{
214
137
    size_t idx = std::string::npos;
215
137
    const size_t sz = chars.size();
216
278
    for (size_t f = 0; f < sz; f ++)
217
    {
218
141
        const size_t idx2 = text.find(chars[f], pos);
219
141
        if (idx2 != std::string::npos && idx2 < idx)
220
107
            idx = idx2;
221
    }
222
137
    return idx;
223
}
224
225
namespace
226
{
227
    unsigned int base = 94;
228
    unsigned int start = 33;
229
}  // namespace
230
231
4
const std::string encodeStr(unsigned int value, const unsigned int size)
232
{
233
    std::string buf;
234
235
    do
236
    {
237
12
        buf += CAST_S8(value % base + start);
238
6
        value /= base;
239
    }
240
6
    while (value != 0U);
241
242
8
    while (buf.length() < size)
243
4
        buf += CAST_S8(start);
244
4
    return buf;
245
}
246
247
248
5
unsigned int decodeStr(const std::string &str)
249
{
250
5
    if (str.empty())
251
        return 0;
252
253
4
    int res = str[0] - start;
254
4
    int mult = 1;
255
10
    for (size_t f = 1; f < str.length(); f ++)
256
    {
257
6
        mult *= base;
258
6
        res = res + (str[f] - start) * mult;
259
    }
260
4
    return res;
261
}
262
263
7
std::string extractNameFromSprite(std::string str)
264
{
265
7
    const size_t pos1 = str.rfind('.');
266
7
    if (pos1 != std::string::npos)
267
    {
268
5
        size_t pos2 = str.rfind('/');
269
5
        const size_t pos3 = str.rfind('\\');
270
5
        if (pos3 != std::string::npos)
271
        {
272
3
            if (pos2 == std::string::npos || pos3 > pos2)
273
2
                pos2 = pos3;
274
        }
275
5
        if (pos2 == std::string::npos)
276
1
            pos2 = CAST_SIZE(-1);
277
278
5
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
279
5
        if (size > 0)
280
10
            str = str.substr(pos2 + 1, size);
281
    }
282
7
    return str;
283
}
284
285
7
std::string removeSpriteIndex(std::string str)
286
{
287
7
    const size_t pos1 = str.rfind('[');
288
289
7
    if (pos1 != std::string::npos)
290
    {
291
5
        size_t pos2 = str.rfind('/');
292
5
        const size_t pos3 = str.rfind('\\');
293
5
        if (pos3 != std::string::npos)
294
        {
295
3
            if (pos2 == std::string::npos || pos3 > pos2)
296
2
                pos2 = pos3;
297
        }
298
5
        if (pos2 == std::string::npos)
299
1
            pos2 = CAST_SIZE(-1);
300
301
5
        const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
302
5
        if (size > 0)
303
10
            str = str.substr(pos2 + 1, size);
304
    }
305
7
    return str;
306
}
307
308
3
const char* getSafeUtf8String(const std::string &text)
309
{
310
3
    const size_t sz = text.size();
311
3
    const size_t size = sz + UTF8_MAX_SIZE;
312
3
    char *const buf = new char[size];
313
6
    memcpy(buf, text.c_str(), sz);
314
6
    memset(buf + sz, 0, UTF8_MAX_SIZE);
315
3
    return buf;
316
}
317
318
9670
void getSafeUtf8String(std::string text, char *const buf)
319
{
320
9670
    if (buf == nullptr)
321
        return;
322
9669
    const size_t sz = text.size();
323
9669
    const size_t size = sz + UTF8_MAX_SIZE;
324
9669
    if (size > 65500)
325
    {
326
2
        text = text.substr(0, 65500);
327
1
        const size_t sz1 = text.size();
328
2
        memcpy(buf, text.c_str(), sz1);
329
1
        memset(buf + sz1, 0, UTF8_MAX_SIZE);
330
    }
331
    else
332
    {
333
19336
        memcpy(buf, text.c_str(), sz);
334
9668
        memset(buf + sz, 0, UTF8_MAX_SIZE);
335
    }
336
}
337
338
22
std::string getFileName(const std::string &path)
339
{
340
22
    size_t pos1 = path.rfind('/');
341
22
    const size_t pos2 = path.rfind('\\');
342

42
    if (pos1 == std::string::npos ||
343
20
        (pos2 != std::string::npos && pos2 > pos1))
344
    {
345
3
        pos1 = pos2;
346
    }
347
348
22
    if (pos1 == std::string::npos)
349
        return path;
350
20
    return path.substr(pos1 + 1);
351
}
352
353
505
std::string getFileDir(const std::string &path)
354
{
355
505
    size_t pos1 = path.rfind('/');
356
505
    const size_t pos2 = path.rfind('\\');
357

889
    if (pos1 == std::string::npos ||
358
384
        (pos2 != std::string::npos && pos2 > pos1))
359
    {
360
122
        pos1 = pos2;
361
    }
362
363
505
    if (pos1 == std::string::npos)
364
        return path;
365
384
    return path.substr(0, pos1);
366
}
367
368
21593
std::string& replaceAll(std::string& context,
369
                        const std::string &restrict from,
370
                        const std::string &restrict to)
371
{
372
21593
    if (from.empty())
373
        return context;
374
21590
    size_t lookHere = 0;
375
    size_t foundHere;
376
21590
    const size_t fromSize = from.size();
377
21590
    const size_t toSize = to.size();
378
22006
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
379
    {
380
208
        context.replace(foundHere, fromSize, to);
381
208
        lookHere = foundHere + toSize;
382
    }
383
    return context;
384
}
385
386
28319
void replaceRecursiveAll(std::string& context,
387
                         const std::string &restrict from,
388
                         const char to)
389
{
390
28319
    size_t lookHere = 0;
391
    size_t foundHere;
392
28319
    const size_t fromSize = from.size();
393
28803
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
394
    {
395
242
        context.replace(foundHere, fromSize, 1, to);
396
242
        lookHere = foundHere;
397
    }
398
28319
}
399
400
38
bool getBoolFromString(const std::string &text)
401
{
402
76
    std::string txt = text;
403
38
    toLower(trim(txt));
404


134
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
405
        return true;
406


74
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
407
        return false;
408
    else
409
14
        return static_cast<bool>(atoi(txt.c_str()));
410
}
411
412
11
void replaceSpecialChars(std::string &text)
413
{
414
11
    size_t pos1 = text.find('&');
415
27
    while (pos1 != std::string::npos)
416
    {
417
10
        const size_t idx = pos1 + 1;
418
10
        const size_t sz = text.size();
419
10
        if (idx >= sz)
420
            break;
421
422
        size_t f;
423
38
        for (f = idx; f < sz; f ++)
424
        {
425

42
            if (text[f] < '0' || text[f] > '9')
426
                break;
427
        }
428

15
        if (idx + 1 < f && text[f] == ';')
429
        {
430
20
            std::string str(" ");
431
20
            str[0] = CAST_S8(atoi(text.substr(
432
                idx, f - idx).c_str()));
433

30
            text = text.substr(0, pos1).append(str).append(text.substr(f + 1));
434
5
            pos1 += 1;
435
        }
436
        else
437
        {
438
3
            pos1 = f + 1;
439
        }
440
441
8
        pos1 = text.find('&', pos1);
442
    }
443
11
}
444
445
98
std::string normalize(const std::string &name)
446
{
447
196
    std::string normalized = name;
448
392
    return toLower(trim(normalized));
449
}
450
451
6
void splitToIntSet(std::set<int> &tokens,
452
                   const std::string &text,
453
                   const char separator)
454
{
455
12
    std::stringstream ss(text);
456
6
    std::string item;
457

54
    while (std::getline(ss, item, separator))
458
42
        tokens.insert(atoi(item.c_str()));
459
6
}
460
461
6
std::list<int> splitToIntList(const std::string &text,
462
                              const char separator)
463
{
464
6
    std::list<int> tokens;
465
12
    std::stringstream ss(text);
466
6
    std::string item;
467

54
    while (std::getline(ss, item, separator))
468
42
        tokens.push_back(atoi(item.c_str()));
469
470
6
    return tokens;
471
}
472
473
33
std::list<std::string> splitToStringList(const std::string &text,
474
                                         const char separator)
475
{
476
33
    std::list<std::string> tokens;
477
66
    std::stringstream ss(text);
478
33
    std::string item;
479

90
    while (std::getline(ss, item, separator))
480
12
        tokens.push_back(item);
481
482
33
    return tokens;
483
}
484
485
3565
void splitToStringVector(StringVect &tokens,
486
                         const std::string &text,
487
                         const char separator)
488
{
489
7130
    std::stringstream ss(text);
490
3565
    std::string item;
491

18044
    while (std::getline(ss, item, separator))
492
    {
493
10914
        item = trim(item);
494
5457
        if (!item.empty())
495
5439
            tokens.push_back(item);
496
    }
497
3565
}
498
499
7
void splitToStringSet(std::set<std::string> &tokens,
500
                      const std::string &text,
501
                      const char separator)
502
{
503
14
    std::stringstream ss(text);
504
7
    std::string item;
505

48
    while (std::getline(ss, item, separator))
506
    {
507
34
        item = trim(item);
508
17
        if (!item.empty())
509
            tokens.insert(item);
510
    }
511
7
}
512
513
7
void splitToIntVector(STD_VECTOR<int> &tokens,
514
                      const std::string &text,
515
                      const char separator)
516
{
517
14
    std::stringstream ss(text);
518
7
    std::string item;
519

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

5
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
555
        {
556

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

5
             it1 != it1_end && it2 != it2_end; ++it1, ++it2)
580
        {
581

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


98
    if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
760
        return 1;
761


54
    else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
762
        return 0;
763
    else
764
7
        return -1;
765
}
766
767
6
std::string encodeLinkText(std::string data)
768
{
769

48
    return replaceAll(data, "|", "\342\235\230");
770
}
771
772
1
std::string decodeLinkText(std::string data)
773
{
774

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


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

24
    if (strStartWith(str, "0x"))
924
        idx = 2;
925

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

70
    replaceAll(str, "\"", "\\\"");
1019
20
    return "\"" + str + "\"";
1020
}
1021
1022
14153
void sanitizePath(std::string &path)
1023
{
1024
#ifdef WIN32
1025
    const char sepStr = '\\';
1026
    const std::string sep2Str = "\\\\";
1027
    const std::string sepWrongStr = "/";
1028
#else
1029
14153
    const char sepStr = '/';
1030
56612
    const std::string sep2Str = "//";
1031
56612
    const std::string sepWrongStr = "\\";
1032
#endif
1033
14153
    replaceRecursiveAll(path, sepWrongStr, sepStr);
1034
14153
    replaceRecursiveAll(path, sep2Str, sepStr);
1035
14153
}
1036
1037
9185
std::string pathJoin(std::string str1,
1038
                     const std::string &str2)
1039
{
1040
#ifdef WIN32
1041
    const char sep = '\\';
1042
    std::string sepStr = "\\";
1043
#else
1044
9185
    const char sep = '/';
1045
36740
    std::string sepStr = "/";
1046
#endif
1047
1048
9185
    if (str1.empty())
1049
    {
1050
8
        if (str2[0] == sep)
1051
            return str2;
1052
6
        return sepStr.append(str2);
1053
    }
1054
9177
    const size_t sz1 = str1.size();
1055
9177
    if (str2.empty())
1056
    {
1057
6
        if (str1[sz1 - 1] == sep)
1058
            return str1;
1059
        return str1.append(sepStr);
1060
    }
1061
18348
    if (str1[sz1 - 1] == sep)
1062
    {
1063
2590
        if (str2[0] == sep)
1064
36
            return str1.append(str2.substr(1));
1065
2581
        return str1.append(str2);
1066
    }
1067
    else
1068
    {
1069
6584
        if (str2[0] == sep)
1070
2
            return str1.append(str2);
1071
13164
        return str1.append(sepStr).append(str2);
1072
    }
1073
}
1074
1075
337
std::string pathJoin(std::string str1,
1076
                     const std::string &str2,
1077
                     const std::string &str3)
1078
{
1079
#ifdef WIN32
1080
    const char sep = '\\';
1081
    std::string sepStr = "\\";
1082
#else
1083
337
    const char sep = '/';
1084
1348
    std::string sepStr = "/";
1085
#endif
1086
1087
337
    if (str1.empty())
1088
    {
1089
8
        return pathJoin(str2, str3);
1090
    }
1091
333
    size_t sz1 = str1.size();
1092
333
    if (str2.empty())
1093
    {
1094
4
        return pathJoin(str1, str3);
1095
    }
1096
331
    if (str3.empty())
1097
    {
1098
2
        return pathJoin(str1, str2);
1099
    }
1100
660
    if (str1[sz1 - 1] == sep)
1101
    {
1102
316
        if (str2[0] == sep)
1103
18
            str1.append(str2.substr(1));
1104
        else
1105
            str1.append(str2);
1106
    }
1107
    else
1108
    {
1109
14
        if (str2[0] == sep)
1110
            str1.append(str2);
1111
        else
1112
12
            str1.append(sepStr).append(str2);
1113
    }
1114
1115
330
    sz1 = str1.size();
1116
660
    if (str1[sz1 - 1] == sep)
1117
    {
1118
6
        if (str3[0] == sep)
1119
8
            return str1.append(str3.substr(1));
1120
4
        return str1.append(str3);
1121
    }
1122
    else
1123
    {
1124
324
        if (str3[0] == sep)
1125
5
            return str1.append(str3);
1126
638
        return str1.append(sepStr).append(str3);
1127
    }
1128
}
1129
1130
13
std::string urlJoin(std::string str1,
1131
                    const std::string &str2)
1132
{
1133
13
    const char sep = '/';
1134
52
    std::string sepStr = "/";
1135
1136
13
    if (str1.empty())
1137
    {
1138
3
        if (str2[0] == sep)
1139
            return str2;
1140
2
        return sepStr.append(str2);
1141
    }
1142
10
    const size_t sz1 = str1.size();
1143
10
    if (str2.empty())
1144
    {
1145
2
        if (str1[sz1 - 1] == sep)
1146
            return str1;
1147
        return str1.append(sepStr);
1148
    }
1149
18
    if (str1[sz1 - 1] == sep)
1150
    {
1151
4
        if (str2[0] == sep)
1152
8
            return str1.append(str2.substr(1));
1153
2
        return str1.append(str2);
1154
    }
1155
    else
1156
    {
1157
5
        if (str2[0] == sep)
1158
2
            return str1.append(str2);
1159
6
        return str1.append(sepStr).append(str2);
1160
    }
1161
}
1162
1163
11
size_t rfindSepatator(const std::string &str1)
1164
{
1165
11
    const size_t idx1 = str1.rfind('/');
1166
11
    const size_t idx2 = str1.rfind('\\');
1167
11
    if (idx1 != std::string::npos)
1168
    {   // idx1
1169
6
        if (idx2 != std::string::npos)
1170
        {   // idx1, idx2
1171
2
            if (idx1 >= idx2)
1172
                return idx1;
1173
            else
1174
1
                return idx2;
1175
        }
1176
        else
1177
        {   // idx1, not idx2
1178
            return idx1;
1179
        }
1180
    }
1181
    else
1182
    {   // not idx1
1183
5
        if (idx2 != std::string::npos)
1184
        {   // not idx1, idx2
1185
            return idx2;
1186
        }
1187
        else
1188
        {   // not idx1, not idx2
1189
1
            return std::string::npos;
1190
        }
1191
    }
1192
}
1193
1194
#ifndef DYECMD
1195
43
void replaceItemLinks(std::string &msg)
1196
{
1197
    // Check for item link
1198
43
    size_t start2 = msg.find('[');
1199
43
    size_t sz = msg.size();
1200

268
    while (start2 + 1 < sz &&
1201

119
           start2 != std::string::npos &&
1202
78
           msg[start2 + 1] != '@')
1203
    {
1204
39
        const size_t end = msg.find(']', start2);
1205

39
        if (start2 + 1 != end &&
1206
            end != std::string::npos)
1207
        {
1208
            // Catch multiple embeds and ignore them
1209
            // so it doesn't crash the client.
1210

73
            while ((msg.find('[', start2 + 1) != std::string::npos) &&
1211
18
                   (msg.find('[', start2 + 1) < end))
1212
            {
1213
15
                start2 = msg.find('[', start2 + 1);
1214
            }
1215
1216

25
            if (start2 + 1 < sz &&
1217
25
                end < sz &&
1218
                end > start2 + 1)
1219
            {
1220
36
                std::string itemStr = msg.substr(start2 + 1, end - start2 - 1);
1221
1222
36
                StringVect parts;
1223
19
                splitToStringVector(parts, itemStr, ',');
1224
19
                if (parts.empty())
1225
2
                    return;
1226
1227
17
                const ItemInfo &itemInfo = ItemDB::get(parts[0]);
1228
17
                const int itemId = itemInfo.getId();
1229
17
                if (itemId != 0)
1230
                {
1231
34
                    std::string temp = strprintf("@@%d", itemId);
1232
51
                    std::string name = parts[0];
1233
17
                    msg.erase(start2 + 1, end - start2 - 1);
1234
51
                    parts.erase(parts.begin());
1235
17
                    if (!parts.empty())
1236
                        name.clear();
1237
1238
87
                    FOR_EACH (StringVectCIter, it, parts)
1239
                    {
1240
6
                        std:: string str = *it;
1241
2
                        trim(str);
1242
2
                        const ItemInfo &itemInfo2 = ItemDB::get(str);
1243
2
                        const int cardId = itemInfo2.getId();
1244
2
                        if (cardId != 0)
1245
6
                            temp.append(strprintf(",%d", cardId));
1246
                    }
1247
17
                    temp.append("|");
1248
17
                    temp.append(name);
1249
17
                    temp.append("@@");
1250
34
                    msg.insert(start2 + 1, temp);
1251
17
                    sz = msg.size();
1252
                }
1253
            }
1254
        }
1255
37
        start2 = msg.find('[', start2 + 1);
1256
    }
1257
}
1258
#else  // DYECMD
1259
1260
void replaceItemLinks(std::string &msg A_UNUSED)
1261
{
1262
}
1263
#endif  // DYECMD