GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/stringutils.cpp Lines: 623 636 98.0 %
Date: 2019-08-19 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
 *
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
5780
std::string &trim(std::string &str)
47
{
48
5780
    size_t pos = str.find_last_not_of(' ');
49
5780
    if (pos != std::string::npos)
50
    {
51
5691
        str.erase(pos + 1);
52
5691
        pos = str.find_first_not_of(' ');
53
54
5691
        if (pos != std::string::npos)
55
5691
            str.erase(0, pos);
56
    }
57
    else
58
    {
59
        // There is nothing else but whitespace in the string
60
        str.clear();
61
    }
62
5780
    return str;
63
}
64
65
89
std::string &toLower(std::string &str)
66
{
67
828
    std::transform(str.begin(), str.end(), str.begin(), &tolower);
68
89
    return str;
69
}
70
71
4
std::string &toUpper(std::string &str)
72
{
73
16
    std::transform(str.begin(), str.end(), str.begin(), &toupper);
74
4
    return str;
75
}
76
77
9015
unsigned int atox(const std::string &str)
78
{
79
9015
    unsigned int value = 0;
80
9015
    if (sscanf(str.c_str(), "0x%06x", &value) != 0)
81
9014
        return value;
82
    return 0;
83
}
84
85
2
const char *ipToString(const uint32_t address)
86
{
87
    static char asciiIP[18];
88
89
6
    snprintf(asciiIP, sizeof(asciiIP), "%i.%i.%i.%i",
90
            CAST_U8(address),
91
2
            CAST_U8(address >> 8),
92
2
            CAST_U8(address >> 16),
93
4
            CAST_U8(address >> 24));
94
2
    asciiIP[17] = 0;
95
96
2
    return asciiIP;
97
}
98
99
118494
std::string strprintf(const char *const format, ...)
100
{
101
    char buf[257];
102
    va_list args;
103
118494
    va_start(args, format);
104
118494
    size_t nb = vsnprintf(buf, 256, format, args);
105
118494
    buf[256] = 0;
106
118494
    va_end(args);
107
118494
    if (nb < 256)
108
236986
        return buf;
109
110
    // The static size was not big enough, try again with a dynamic allocation.
111
1
    ++nb;
112
1
    char *buf2 = new char[nb];
113
1
    va_start(args, format);
114
1
    vsnprintf(buf2, nb, format, args);
115
1
    va_end(args);
116
3
    std::string res(buf2);
117
1
    delete [] buf2;
118
1
    return res;
119
}
120
121
10
std::string removeColors(std::string msg)
122
{
123

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

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

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

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

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

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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

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

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


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

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

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

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

268
    while (start2 + 1 < sz &&
1200

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

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

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

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