GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/utils/stringutils.cpp Lines: 614 627 97.9 %
Date: 2018-11-12 Branches: 464 556 83.5 %

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
5774
std::string &trim(std::string &str)
47
{
48
5774
    size_t pos = str.find_last_not_of(' ');
49
5774
    if (pos != std::string::npos)
50
    {
51
5685
        str.erase(pos + 1);
52
5685
        pos = str.find_first_not_of(' ');
53
54
5685
        if (pos != std::string::npos)
55
5685
            str.erase(0, pos);
56
    }
57
    else
58
    {
59
        // There is nothing else but whitespace in the string
60
        str.clear();
61
    }
62
5774
    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
118495
std::string strprintf(const char *const format, ...)
100
{
101
    char buf[257];
102
    va_list args;
103
118495
    va_start(args, format);
104
118495
    size_t nb = vsnprintf(buf, 256, format, args);
105
118495
    buf[256] = 0;
106
118495
    va_end(args);
107
118495
    if (nb < 256)
108
236988
        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
9664
void getSafeUtf8String(std::string text, char *const buf)
318
{
319
9664
    if (buf == nullptr)
320
        return;
321
9663
    const size_t sz = text.size();
322
9663
    const size_t size = sz + UTF8_MAX_SIZE;
323
9663
    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
19324
        memcpy(buf, text.c_str(), sz);
333
9662
        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
22
    if (pos1 == std::string::npos)
342
        pos1 = pos2;
343
20
    else if (pos2 != std::string::npos && pos2 > pos1)
344
1
        pos1 = pos2;
345
346
22
    if (pos1 == std::string::npos)
347
        return path;
348
20
    return path.substr(pos1 + 1);
349
}
350
351
505
std::string getFileDir(const std::string &path)
352
{
353
505
    size_t pos1 = path.rfind('/');
354
505
    const size_t pos2 = path.rfind('\\');
355
505
    if (pos1 == std::string::npos)
356
        pos1 = pos2;
357
384
    else if (pos2 != std::string::npos && pos2 > pos1)
358
1
        pos1 = pos2;
359
360
505
    if (pos1 == std::string::npos)
361
        return path;
362
384
    return path.substr(0, pos1);
363
}
364
365
21593
std::string& replaceAll(std::string& context,
366
                        const std::string &restrict from,
367
                        const std::string &restrict to)
368
{
369
21593
    if (from.empty())
370
        return context;
371
21590
    size_t lookHere = 0;
372
    size_t foundHere;
373
21590
    const size_t fromSize = from.size();
374
21590
    const size_t toSize = to.size();
375
22002
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
376
    {
377
206
        context.replace(foundHere, fromSize, to);
378
206
        lookHere = foundHere + toSize;
379
    }
380
    return context;
381
}
382
383
28323
void replaceRecursiveAll(std::string& context,
384
                         const std::string &restrict from,
385
                         const char to)
386
{
387
28323
    size_t lookHere = 0;
388
    size_t foundHere;
389
28323
    const size_t fromSize = from.size();
390
28807
    while ((foundHere = context.find(from, lookHere)) != std::string::npos)
391
    {
392
242
        context.replace(foundHere, fromSize, 1, to);
393
242
        lookHere = foundHere;
394
    }
395
28323
}
396
397
38
bool getBoolFromString(const std::string &text)
398
{
399
76
    std::string txt = text;
400
38
    toLower(trim(txt));
401


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


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

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

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

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

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

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

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

18028
    while (std::getline(ss, item, separator))
489
    {
490
10902
        item = trim(item);
491
5451
        if (!item.empty())
492
5433
            tokens.push_back(item);
493
    }
494
3563
}
495
496
7
void splitToStringSet(std::set<std::string> &tokens,
497
                      const std::string &text,
498
                      const char separator)
499
{
500
14
    std::stringstream ss(text);
501
7
    std::string item;
502

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

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

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

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

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

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


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


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

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

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


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

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

7
    else if (str[0] == 'h' || str[0] == 'x')
923
2
        idx = 1;
924
6
    if (idx > 0)
925
12
        sscanf(str.substr(idx).c_str(), "%10x", &i);
926
    else
927
4
        i = atoi(str.c_str());
928
6
    return i;
929
}
930
931
6
std::string removeToken(std::string &str,
932
                        const std::string &token)
933
{
934
6
    const size_t idx = str.find(token);
935
6
    if (idx > 0 && idx != std::string::npos)
936
4
        str = str.substr(idx + 1);
937
    else
938
        str.clear();
939
6
    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
10
std::string timeDiffToString(int timeDiff)
953
{
954
10
    std::string str;
955
956
10
    const int weeks = timeDiff / 60 / 60 / 24 / 7;
957
10
    if (weeks > 0)
958
    {
959
        // TRANSLATORS: uptime command
960
10
        str = strprintf(ngettext(N_("%d week"), N_("%d weeks"),
961
5
            weeks), weeks);
962
5
        timeDiff -= weeks * 60 * 60 * 24 * 7;
963
    }
964
965
10
    const int days = timeDiff / 60 / 60 / 24;
966
10
    if (days > 0)
967
    {
968
5
        if (!str.empty())
969
4
            str.append(", ");
970
        // TRANSLATORS: uptime command
971
10
        str.append(strprintf(ngettext(N_("%d day"), N_("%d days"),
972
5
            days), days));
973
5
        timeDiff -= days * 60 * 60 * 24;
974
    }
975
10
    const int hours = timeDiff / 60 / 60;
976
10
    if (hours > 0)
977
    {
978
4
        if (!str.empty())
979
3
            str.append(", ");
980
        // TRANSLATORS: uptime command
981
8
        str.append(strprintf(ngettext(N_("%d hour"), N_("%d hours"),
982
4
            hours), hours));
983
4
        timeDiff -= hours * 60 * 60;
984
    }
985
10
    const int min = timeDiff / 60;
986
10
    if (min > 0)
987
    {
988
3
        if (!str.empty())
989
2
            str.append(", ");
990
        // TRANSLATORS: uptime command
991
6
        str.append(strprintf(ngettext(N_("%d minute"), N_("%d minutes"),
992
3
            min), min));
993
3
        timeDiff -= min * 60;
994
    }
995
996
10
    if (timeDiff > 0)
997
    {
998
2
        if (!str.empty())
999
1
            str.append(", ");
1000
        // TRANSLATORS: uptime command
1001
4
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1002
2
            timeDiff), timeDiff));
1003
    }
1004
10
    if (str.empty())
1005
    {
1006
        // TRANSLATORS: uptime command
1007
2
        str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1008
1
            0), 0));
1009
    }
1010
10
    return str;
1011
}
1012
1013
10
std::string escapeString(std::string str)
1014
{
1015

70
    replaceAll(str, "\"", "\\\"");
1016
20
    return "\"" + str + "\"";
1017
}
1018
1019
14155
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
14155
    const char sepStr = '/';
1027
56620
    const std::string sep2Str = "//";
1028
56620
    const std::string sepWrongStr = "\\";
1029
#endif
1030
14155
    replaceRecursiveAll(path, sepWrongStr, sepStr);
1031
14155
    replaceRecursiveAll(path, sep2Str, sepStr);
1032
14155
}
1033
1034
9189
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
9189
    const char sep = '/';
1042
36756
    std::string sepStr = "/";
1043
#endif
1044
1045
9189
    if (str1.empty())
1046
    {
1047
8
        if (str2[0] == sep)
1048
            return str2;
1049
6
        return sepStr.append(str2);
1050
    }
1051
9181
    const size_t sz1 = str1.size();
1052
9181
    if (str2.empty())
1053
    {
1054
6
        if (str1[sz1 - 1] == sep)
1055
            return str1;
1056
        return str1.append(sepStr);
1057
    }
1058
18356
    if (str1[sz1 - 1] == sep)
1059
    {
1060
2594
        if (str2[0] == sep)
1061
36
            return str1.append(str2.substr(1));
1062
2585
        return str1.append(str2);
1063
    }
1064
    else
1065
    {
1066
6584
        if (str2[0] == sep)
1067
2
            return str1.append(str2);
1068
13164
        return str1.append(sepStr).append(str2);
1069
    }
1070
}
1071
1072
337
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
337
    const char sep = '/';
1081
1348
    std::string sepStr = "/";
1082
#endif
1083
1084
337
    if (str1.empty())
1085
    {
1086
8
        return pathJoin(str2, str3);
1087
    }
1088
333
    size_t sz1 = str1.size();
1089
333
    if (str2.empty())
1090
    {
1091
4
        return pathJoin(str1, str3);
1092
    }
1093
331
    if (str3.empty())
1094
    {
1095
2
        return pathJoin(str1, str2);
1096
    }
1097
660
    if (str1[sz1 - 1] == sep)
1098
    {
1099
316
        if (str2[0] == sep)
1100
18
            str1.append(str2.substr(1));
1101
        else
1102
            str1.append(str2);
1103
    }
1104
    else
1105
    {
1106
14
        if (str2[0] == sep)
1107
            str1.append(str2);
1108
        else
1109
12
            str1.append(sepStr).append(str2);
1110
    }
1111
1112
330
    sz1 = str1.size();
1113
660
    if (str1[sz1 - 1] == sep)
1114
    {
1115
6
        if (str3[0] == sep)
1116
8
            return str1.append(str3.substr(1));
1117
4
        return str1.append(str3);
1118
    }
1119
    else
1120
    {
1121
324
        if (str3[0] == sep)
1122
5
            return str1.append(str3);
1123
638
        return str1.append(sepStr).append(str3);
1124
    }
1125
}
1126
1127
13
std::string urlJoin(std::string str1,
1128
                    const std::string &str2)
1129
{
1130
13
    const char sep = '/';
1131
52
    std::string sepStr = "/";
1132
1133
13
    if (str1.empty())
1134
    {
1135
3
        if (str2[0] == sep)
1136
            return str2;
1137
2
        return sepStr.append(str2);
1138
    }
1139
10
    const size_t sz1 = str1.size();
1140
10
    if (str2.empty())
1141
    {
1142
2
        if (str1[sz1 - 1] == sep)
1143
            return str1;
1144
        return str1.append(sepStr);
1145
    }
1146
18
    if (str1[sz1 - 1] == sep)
1147
    {
1148
4
        if (str2[0] == sep)
1149
8
            return str1.append(str2.substr(1));
1150
2
        return str1.append(str2);
1151
    }
1152
    else
1153
    {
1154
5
        if (str2[0] == sep)
1155
2
            return str1.append(str2);
1156
6
        return str1.append(sepStr).append(str2);
1157
    }
1158
}
1159
1160
#ifndef DYECMD
1161
43
void replaceItemLinks(std::string &msg)
1162
{
1163
    // Check for item link
1164
43
    size_t start2 = msg.find('[');
1165
43
    size_t sz = msg.size();
1166

268
    while (start2 + 1 < sz &&
1167

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

39
        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

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

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