ManaPlus
stringutils.cpp
Go to the documentation of this file.
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 std::string &trim(std::string &str)
48 {
49  size_t pos = str.find_last_not_of(' ');
50  if (pos != std::string::npos)
51  {
52  str.erase(pos + 1);
53  pos = str.find_first_not_of(' ');
54 
55  if (pos != std::string::npos)
56  str.erase(0, pos);
57  }
58  else
59  {
60  // There is nothing else but whitespace in the string
61  str.clear();
62  }
63  return str;
64 }
65 
66 std::string &toLower(std::string &str)
67 {
68  std::transform(str.begin(), str.end(), str.begin(), &tolower);
69  return str;
70 }
71 
72 std::string &toUpper(std::string &str)
73 {
74  std::transform(str.begin(), str.end(), str.begin(), &toupper);
75  return str;
76 }
77 
78 unsigned int atox(const std::string &str)
79 {
80  unsigned int value = 0;
81  if (sscanf(str.c_str(), "0x%06x", &value) != 0)
82  return value;
83  return 0;
84 }
85 
86 const char *ipToString(const uint32_t address)
87 {
88  static char asciiIP[18];
89 
90  snprintf(asciiIP, sizeof(asciiIP), "%i.%i.%i.%i",
91  CAST_U8(address),
92  CAST_U8(address >> 8),
93  CAST_U8(address >> 16),
94  CAST_U8(address >> 24));
95  asciiIP[17] = 0;
96 
97  return asciiIP;
98 }
99 
100 std::string strprintf(const char *const format, ...)
101 {
102  char buf[257];
103  va_list args;
104  va_start(args, format);
105  size_t nb = vsnprintf(buf, 256, format, args);
106  buf[256] = 0;
107  va_end(args);
108  if (nb < 256)
109  return buf;
110 
111  // The static size was not big enough, try again with a dynamic allocation.
112  ++nb;
113  char *buf2 = new char[nb];
114  va_start(args, format);
115  vsnprintf(buf2, nb, format, args);
116  va_end(args);
117  std::string res(buf2);
118  delete [] buf2;
119  return res;
120 }
121 
122 std::string removeColors(std::string msg)
123 {
124  for (unsigned int f = 0; f < msg.length() - 2 && msg.length() > 2; f++)
125  {
126  while (msg.length() > f + 2 && msg.at(f) == '#'
127  && msg.at(f + 1) == '#')
128  {
129  msg = msg.erase(f, 3);
130  }
131  }
132  return msg;
133 }
134 
135 int compareStrI(const std::string &a, const std::string &b)
136 {
137  std::string::const_iterator itA = a.begin();
138  const std::string::const_iterator endA = a.end();
139  std::string::const_iterator itB = b.begin();
140  const std::string::const_iterator endB = b.end();
141 
142  for (; itA < endA && itB < endB; ++itA, ++itB)
143  {
144  const int comp = tolower(*itA) - tolower(*itB);
145  if (comp != 0)
146  return comp;
147  }
148 
149  // Check string lengths
150  if (itA == endA && itB == endB)
151  return 0;
152  else if (itA == endA)
153  return -1;
154  else
155  return 1;
156 }
157 
158 const std::string findSameSubstring(const std::string &restrict str1,
159  const std::string &restrict str2)
160 {
161  const int minLength = str1.length() > str2.length()
162  ? CAST_S32(str2.length()) : CAST_S32(str1.length());
163  for (int f = 0; f < minLength; f ++)
164  {
165  if (str1.at(f) != str2.at(f))
166  return str1.substr(0, f);
167  }
168  return str1.substr(0, minLength);
169 }
170 
171 const std::string findSameSubstringI(const std::string &restrict s1,
172  const std::string &restrict s2)
173 {
174  std::string str1 = s1;
175  std::string str2 = s2;
176  toLower(str1);
177  toLower(str2);
178 
179  const size_t minLength = str1.length() > str2.length()
180  ? str2.length() : str1.length();
181  for (size_t f = 0; f < minLength; f ++)
182  {
183  if (str1.at(f) != str2.at(f))
184  return s1.substr(0, f);
185  }
186  return s1.substr(0, minLength);
187 }
188 
189 size_t findI(std::string str, std::string subStr)
190 {
191  str = toLower(str);
192  subStr = toLower(subStr);
193  return str.find(subStr);
194 }
195 
196 size_t findI(std::string text, const StringVect &list)
197 {
198  toLower(text);
199  FOR_EACH (StringVectCIter, i, list)
200  {
201  std::string subStr = *i;
202  subStr = toLower(subStr);
203  const size_t idx = text.find(subStr);
204  if (idx != std::string::npos)
205  return idx;
206  }
207  return std::string::npos;
208 }
209 
210 size_t findAny(const std::string &restrict text,
211  const std::string &restrict chars,
212  const size_t pos)
213 {
214  size_t idx = std::string::npos;
215  const size_t sz = chars.size();
216  for (size_t f = 0; f < sz; f ++)
217  {
218  const size_t idx2 = text.find(chars[f], pos);
219  if (idx2 != std::string::npos && idx2 < idx)
220  idx = idx2;
221  }
222  return idx;
223 }
224 
225 namespace
226 {
227  unsigned int base = 94;
228  unsigned int start = 33;
229 } // namespace
230 
231 const std::string encodeStr(unsigned int value, const unsigned int size)
232 {
233  std::string buf;
234 
235  do
236  {
237  buf += CAST_S8(value % base + start);
238  value /= base;
239  }
240  while (value != 0U);
241 
242  while (buf.length() < size)
243  buf += CAST_S8(start);
244  return buf;
245 }
246 
247 
248 unsigned int decodeStr(const std::string &str)
249 {
250  if (str.empty())
251  return 0;
252 
253  int res = str[0] - start;
254  int mult = 1;
255  for (size_t f = 1; f < str.length(); f ++)
256  {
257  mult *= base;
258  res = res + (str[f] - start) * mult;
259  }
260  return res;
261 }
262 
263 std::string extractNameFromSprite(std::string str)
264 {
265  const size_t pos1 = str.rfind('.');
266  if (pos1 != std::string::npos)
267  {
268  size_t pos2 = str.rfind('/');
269  const size_t pos3 = str.rfind('\\');
270  if (pos3 != std::string::npos)
271  {
272  if (pos2 == std::string::npos || pos3 > pos2)
273  pos2 = pos3;
274  }
275  if (pos2 == std::string::npos)
276  pos2 = CAST_SIZE(-1);
277 
278  const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
279  if (size > 0)
280  str = str.substr(pos2 + 1, size);
281  }
282  return str;
283 }
284 
285 std::string removeSpriteIndex(std::string str)
286 {
287  const size_t pos1 = str.rfind('[');
288 
289  if (pos1 != std::string::npos)
290  {
291  size_t pos2 = str.rfind('/');
292  const size_t pos3 = str.rfind('\\');
293  if (pos3 != std::string::npos)
294  {
295  if (pos2 == std::string::npos || pos3 > pos2)
296  pos2 = pos3;
297  }
298  if (pos2 == std::string::npos)
299  pos2 = CAST_SIZE(-1);
300 
301  const int size = CAST_S32(pos1) - CAST_S32(pos2) - 1;
302  if (size > 0)
303  str = str.substr(pos2 + 1, size);
304  }
305  return str;
306 }
307 
308 const char* getSafeUtf8String(const std::string &text)
309 {
310  const size_t sz = text.size();
311  const size_t size = sz + UTF8_MAX_SIZE;
312  char *const buf = new char[size];
313  memcpy(buf, text.c_str(), sz);
314  memset(buf + sz, 0, UTF8_MAX_SIZE);
315  return buf;
316 }
317 
318 void getSafeUtf8String(std::string text, char *const buf)
319 {
320  if (buf == nullptr)
321  return;
322  const size_t sz = text.size();
323  const size_t size = sz + UTF8_MAX_SIZE;
324  if (size > 65500)
325  {
326  text = text.substr(0, 65500);
327  const size_t sz1 = text.size();
328  memcpy(buf, text.c_str(), sz1);
329  memset(buf + sz1, 0, UTF8_MAX_SIZE);
330  }
331  else
332  {
333  memcpy(buf, text.c_str(), sz);
334  memset(buf + sz, 0, UTF8_MAX_SIZE);
335  }
336 }
337 
338 std::string getFileName(const std::string &path)
339 {
340  size_t pos1 = path.rfind('/');
341  const size_t pos2 = path.rfind('\\');
342  if (pos1 == std::string::npos ||
343  (pos2 != std::string::npos && pos2 > pos1))
344  {
345  pos1 = pos2;
346  }
347 
348  if (pos1 == std::string::npos)
349  return path;
350  return path.substr(pos1 + 1);
351 }
352 
353 std::string getFileDir(const std::string &path)
354 {
355  size_t pos1 = path.rfind('/');
356  const size_t pos2 = path.rfind('\\');
357  if (pos1 == std::string::npos ||
358  (pos2 != std::string::npos && pos2 > pos1))
359  {
360  pos1 = pos2;
361  }
362 
363  if (pos1 == std::string::npos)
364  return path;
365  return path.substr(0, pos1);
366 }
367 
368 std::string& replaceAll(std::string& context,
369  const std::string &restrict from,
370  const std::string &restrict to)
371 {
372  if (from.empty())
373  return context;
374  size_t lookHere = 0;
375  size_t foundHere;
376  const size_t fromSize = from.size();
377  const size_t toSize = to.size();
378  while ((foundHere = context.find(from, lookHere)) != std::string::npos)
379  {
380  context.replace(foundHere, fromSize, to);
381  lookHere = foundHere + toSize;
382  }
383  return context;
384 }
385 
386 void replaceRecursiveAll(std::string& context,
387  const std::string &restrict from,
388  const char to)
389 {
390  size_t lookHere = 0;
391  size_t foundHere;
392  const size_t fromSize = from.size();
393  while ((foundHere = context.find(from, lookHere)) != std::string::npos)
394  {
395  context.replace(foundHere, fromSize, 1, to);
396  lookHere = foundHere;
397  }
398 }
399 
400 bool getBoolFromString(const std::string &text)
401 {
402  std::string txt = text;
403  toLower(trim(txt));
404  if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
405  return true;
406  else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
407  return false;
408  else
409  return static_cast<bool>(atoi(txt.c_str()));
410 }
411 
412 void replaceSpecialChars(std::string &text)
413 {
414  size_t pos1 = text.find('&');
415  while (pos1 != std::string::npos)
416  {
417  const size_t idx = pos1 + 1;
418  const size_t sz = text.size();
419  if (idx >= sz)
420  break;
421 
422  size_t f;
423  for (f = idx; f < sz; f ++)
424  {
425  if (text[f] < '0' || text[f] > '9')
426  break;
427  }
428  if (idx + 1 < f && text[f] == ';')
429  {
430  std::string str(" ");
431  str[0] = CAST_S8(atoi(text.substr(
432  idx, f - idx).c_str()));
433  text = text.substr(0, pos1).append(str).append(text.substr(f + 1));
434  pos1 += 1;
435  }
436  else
437  {
438  pos1 = f + 1;
439  }
440 
441  pos1 = text.find('&', pos1);
442  }
443 }
444 
445 std::string normalize(const std::string &name)
446 {
447  std::string normalized = name;
448  return toLower(trim(normalized));
449 }
450 
451 void splitToIntSet(std::set<int> &tokens,
452  const std::string &text,
453  const char separator)
454 {
455  std::stringstream ss(text);
456  std::string item;
457  while (std::getline(ss, item, separator))
458  tokens.insert(atoi(item.c_str()));
459 }
460 
461 std::list<int> splitToIntList(const std::string &text,
462  const char separator)
463 {
464  std::list<int> tokens;
465  std::stringstream ss(text);
466  std::string item;
467  while (std::getline(ss, item, separator))
468  tokens.push_back(atoi(item.c_str()));
469 
470  return tokens;
471 }
472 
473 std::list<std::string> splitToStringList(const std::string &text,
474  const char separator)
475 {
476  std::list<std::string> tokens;
477  std::stringstream ss(text);
478  std::string item;
479  while (std::getline(ss, item, separator))
480  tokens.push_back(item);
481 
482  return tokens;
483 }
484 
486  const std::string &text,
487  const char separator)
488 {
489  std::stringstream ss(text);
490  std::string item;
491  while (std::getline(ss, item, separator))
492  {
493  item = trim(item);
494  if (!item.empty())
495  tokens.push_back(item);
496  }
497 }
498 
499 void splitToStringSet(std::set<std::string> &tokens,
500  const std::string &text,
501  const char separator)
502 {
503  std::stringstream ss(text);
504  std::string item;
505  while (std::getline(ss, item, separator))
506  {
507  item = trim(item);
508  if (!item.empty())
509  tokens.insert(item);
510  }
511 }
512 
513 void splitToIntVector(STD_VECTOR<int> &tokens,
514  const std::string &text,
515  const char separator)
516 {
517  std::stringstream ss(text);
518  std::string item;
519  while (std::getline(ss, item, separator))
520  {
521  item = trim(item);
522  if (!item.empty())
523  tokens.push_back(atoi(item.c_str()));
524  }
525 }
526 
527 std::string combineDye(std::string file,
528  const std::string &dye)
529 {
530  if (dye.empty())
531  return file;
532  const size_t pos = file.find_last_of('|');
533  if (pos != std::string::npos)
534  return file.substr(0, pos).append("|").append(dye);
535  return file.append("|").append(dye);
536 }
537 
538 std::string combineDye2(std::string file,
539  const std::string &dye)
540 {
541  if (dye.empty())
542  return file;
543 
544  const size_t pos = file.find_last_of('|');
545  if (pos != std::string::npos)
546  {
547  const std::string dye1 = file.substr(pos + 1);
548  std::string str;
549  file = file.substr(0, pos);
550  const std::list<std::string> list1 = splitToStringList(dye1, ';');
551  const std::list<std::string> list2 = splitToStringList(dye, ';');
552  for (std::list<std::string>::const_iterator it1 = list1.begin(),
553  it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
554  it1 != it1_end && it2 != it2_end; ++it1, ++it2)
555  {
556  str.append(*it1).append(":").append(*it2).append(";");
557  }
558  return file.append("|").append(str);
559  }
560  return file;
561 }
562 
563 std::string combineDye3(std::string file,
564  const std::string &dye)
565 {
566  if (dye.empty())
567  return file;
568 
569  const size_t pos = file.find_last_of('|');
570  if (pos != std::string::npos)
571  {
572  const std::string dye1 = file.substr(pos + 1);
573  std::string str;
574  file = file.substr(0, pos);
575  const std::list<std::string> list1 = splitToStringList(dye1, ';');
576  const std::list<std::string> list2 = splitToStringList(dye, ';');
577  for (std::list<std::string>::const_iterator it1 = list1.begin(),
578  it2 = list2.begin(), it1_end = list1.end(), it2_end = list2.end();
579  it1 != it1_end && it2 != it2_end; ++it1, ++it2)
580  {
581  str.append(*it1).append(":").append(*it2).append(";");
582  }
583  return file.append("|").append(str);
584  }
585  if (file.empty())
586  return file;
587  return file.append("|").append(dye);
588 }
589 
590 std::string packList(const std::list<std::string> &list)
591 {
592  std::list<std::string>::const_iterator i = list.begin();
593  std::string str;
594  while (i != list.end())
595  {
596  str.append(*i).append("|");
597  ++ i;
598  }
599  const size_t sz = str.size();
600  if (sz > 1)
601  str = str.substr(0, sz - 1);
602  return str;
603 }
604 
605 std::list<std::string> unpackList(const std::string &str)
606 {
607  return splitToStringList(str, '|');
608 }
609 
610 std::string stringToHexPath(const std::string &str)
611 {
612  if (str.empty())
613  return "";
614 
615  std::string hex = strprintf("%%%2x/", CAST_U32(str[0]));
616  for (unsigned f = 1, fsz = CAST_U32(str.size());
617  f < fsz; f ++)
618  {
619  hex.append(strprintf("%%%2x", CAST_U32(str[f])));
620  }
621  return hex;
622 }
623 
624 void deleteCharLeft(std::string &str,
625  unsigned *const pos)
626 {
627  if (pos == nullptr)
628  return;
629 
630  while (*pos > 0)
631  {
632  (*pos)--;
633  const int v = str[*pos];
634  str.erase(*pos, 1);
635  if ((v & 192) != 128)
636  break;
637  }
638 }
639 
640 bool findLast(const std::string &restrict str1,
641  const std::string &restrict str2)
642 {
643  const size_t s1 = str1.size();
644  const size_t s2 = str2.size();
645  if (s1 < s2)
646  return false;
647  if (str1.substr(s1 - s2) == str2)
648  return true;
649  return false;
650 }
651 
652 bool findFirst(const std::string &restrict str1,
653  const std::string &restrict str2)
654 {
655  const size_t s1 = str1.size();
656  const size_t s2 = str2.size();
657  if (s1 < s2)
658  return false;
659  if (str1.substr(0, s2) == str2)
660  return true;
661  return false;
662 }
663 
664 bool findCutLast(std::string &restrict str1,
665  const std::string &restrict str2)
666 {
667  const size_t s1 = str1.size();
668  const size_t s2 = str2.size();
669  if (s1 < s2)
670  return false;
671  if (str1.substr(s1 - s2) == str2)
672  {
673  str1 = str1.substr(0, s1 - s2);
674  return true;
675  }
676  return false;
677 }
678 
679 void cutLast(std::string &restrict str1,
680  const std::string &restrict str2)
681 {
682  const size_t s1 = str1.size();
683  const size_t s2 = str2.size();
684  if (s1 < s2)
685  return;
686  if (str1.substr(s1 - s2) == str2)
687  str1 = str1.substr(0, s1 - s2);
688 }
689 
690 bool findCutFirst(std::string &restrict str1,
691  const std::string &restrict str2)
692 {
693  const size_t s1 = str1.size();
694  const size_t s2 = str2.size();
695  if (s1 < s2)
696  return false;
697  if (str1.substr(0, s2) == str2)
698  {
699  str1 = str1.substr(s2);
700  return true;
701  }
702  return false;
703 }
704 
705 void cutFirst(std::string &restrict str1,
706  const std::string &restrict str2)
707 {
708  const size_t s1 = str1.size();
709  const size_t s2 = str2.size();
710  if (s1 < s2)
711  return;
712  if (str1.substr(0, s2) == str2)
713  str1 = str1.substr(s2);
714 }
715 
716 std::string &removeProtocol(std::string &url)
717 {
718  const size_t i = url.find("://");
719  if (i != std::string::npos)
720  url = url.substr(i + 3);
721  return url;
722 }
723 
724 bool strStartWith(const std::string &restrict str1,
725  const std::string &restrict str2)
726 {
727  const size_t sz2 = str2.size();
728  if (str1.size() < sz2)
729  return false;
730  return str1.substr(0, sz2) == str2;
731 }
732 
733 std::string getDateString()
734 {
735  char buffer[80];
736  time_t rawtime;
737  time(&rawtime);
738  const tm *const timeinfo = localtime(&rawtime);
739 
740  strftime(buffer, 79, "%Y-%m-%d", timeinfo);
741  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 signed char parseBoolean(const std::string &value)
756 {
757  std::string txt = value;
758  toLower(trim(txt));
759  if (txt == "true" || txt == "yes" || txt == "on" || txt == "1")
760  return 1;
761  else if (txt == "false" || txt == "no" || txt == "off" || txt == "0")
762  return 0;
763  else
764  return -1;
765 }
766 
767 std::string encodeLinkText(std::string data)
768 {
769  return replaceAll(data, "|", "\342\235\230");
770 }
771 
772 std::string decodeLinkText(std::string data)
773 {
774  return replaceAll(data, "\342\235\230", "|");
775 }
776 
777 std::string toStringPrint(const unsigned int val)
778 {
779  static char str[100];
780  snprintf(str, sizeof(str), "%u 0x%x", val, val);
781  str[99] = 0;
782  return str;
783 }
784 
785 std::string toString(uint32_t num)
786 {
787  char buf[30];
788  buf[29] = '\0';
789  size_t idx = 28;
790  do
791  buf[idx--] = CAST_8((num % 10) + '0');
792  while ((num /= 10) != 0);
793  return buf + idx + 1;
794 }
795 
796 std::string toString(uint64_t num)
797 {
798  char buf[100];
799  buf[99] = '\0';
800  size_t idx = 98;
801  do
802  buf[idx--] = CAST_8((num % 10) + '0');
803  while ((num /= 10) != 0);
804  return buf + idx + 1;
805 }
806 
807 std::string toString(uint16_t num)
808 {
809  char buf[10];
810  buf[9] = '\0';
811  size_t idx = 8;
812  do
813  buf[idx--] = CAST_8((num % 10) + '0');
814  while ((num /= 10) != 0);
815  return buf + idx + 1;
816 }
817 
818 std::string toString(unsigned char num)
819 {
820  char buf[5];
821  buf[4] = '\0';
822  size_t idx = 3;
823  do
824  buf[idx--] = CAST_8((num % 10) + '0');
825  while ((num /= 10) != 0);
826  return buf + idx + 1;
827 }
828 
829 std::string toString(int32_t num)
830 {
831  char buf[30];
832  bool useSign(false);
833  buf[29] = '\0';
834  size_t idx = 28;
835 
836  if (num < 0)
837  {
838  useSign = true;
839  num = -num;
840  }
841  do
842  buf[idx--] = CAST_8((num % 10) + '0');
843  while ((num /= 10) != 0);
844  if (useSign)
845  buf[idx--] = '-';
846  return buf + idx + 1;
847 }
848 
849 std::string toString(const float num)
850 {
851  return strprintf("%f", num);
852 }
853 
854 std::string toString(const double num)
855 {
856  return strprintf("%f", static_cast<float>(num));
857 }
858 
859 bool isDigit(const std::string &str)
860 {
861  if (str.empty())
862  return false;
863  const size_t sz = str.size();
864  for (size_t f = 0; f < sz; f ++)
865  {
866  const char &chr = str[f];
867  if (chr < '0' || chr > '9')
868  return false;
869  }
870  return true;
871 }
872 
873 void secureChatCommand(std::string &str)
874 {
875  if (str[0] == '/' || str[0] == '@' || str[0] == '#')
876  str = "_" + str;
877 }
878 
879 bool parse2Int(const std::string &args,
880  int &x,
881  int &y)
882 {
883  bool isValid = false;
884  size_t pos = args.find(' ');
885  if (pos == std::string::npos)
886  pos = args.find(',');
887  if (pos != std::string::npos)
888  {
889  if (pos + 1 < args.length())
890  {
891  x = atoi(args.substr(0, pos).c_str());
892  y = atoi(args.substr(pos + 1, args.length()).c_str());
893  isValid = true;
894  }
895  }
896  return isValid;
897 }
898 
899 bool parse2Str(const std::string &args,
900  std::string &str1,
901  std::string &str2)
902 {
903  bool isValid = false;
904  size_t pos = args.find(' ');
905  if (pos == std::string::npos)
906  pos = args.find(',');
907  if (pos != std::string::npos)
908  {
909  if (pos + 1 < args.length())
910  {
911  str1 = args.substr(0, pos);
912  str2 = args.substr(pos + 1, args.length());
913  isValid = true;
914  }
915  }
916  return isValid;
917 }
918 
919 uint32_t parseNumber(const std::string &str)
920 {
921  uint32_t i = 0;
922  int idx = 0;
923  if (strStartWith(str, "0x"))
924  idx = 2;
925  else if (str[0] == 'h' || str[0] == 'x')
926  idx = 1;
927  if (idx > 0)
928  sscanf(str.substr(idx).c_str(), "%10x", &i);
929  else
930  i = atoi(str.c_str());
931  return i;
932 }
933 
934 std::string removeToken(std::string &str,
935  const std::string &token)
936 {
937  const size_t idx = str.find(token);
938  if (idx > 0 && idx != std::string::npos)
939  str = str.substr(idx + 1);
940  else
941  str.clear();
942  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 std::string timeDiffToString(int timeDiff)
956 {
957  std::string str;
958 
959  const int weeks = timeDiff / 60 / 60 / 24 / 7;
960  if (weeks > 0)
961  {
962  // TRANSLATORS: uptime command
963  str = strprintf(ngettext(N_("%d week"), N_("%d weeks"),
964  weeks), weeks);
965  timeDiff -= weeks * 60 * 60 * 24 * 7;
966  }
967 
968  const int days = timeDiff / 60 / 60 / 24;
969  if (days > 0)
970  {
971  if (!str.empty())
972  str.append(", ");
973  // TRANSLATORS: uptime command
974  str.append(strprintf(ngettext(N_("%d day"), N_("%d days"),
975  days), days));
976  timeDiff -= days * 60 * 60 * 24;
977  }
978  const int hours = timeDiff / 60 / 60;
979  if (hours > 0)
980  {
981  if (!str.empty())
982  str.append(", ");
983  // TRANSLATORS: uptime command
984  str.append(strprintf(ngettext(N_("%d hour"), N_("%d hours"),
985  hours), hours));
986  timeDiff -= hours * 60 * 60;
987  }
988  const int min = timeDiff / 60;
989  if (min > 0)
990  {
991  if (!str.empty())
992  str.append(", ");
993  // TRANSLATORS: uptime command
994  str.append(strprintf(ngettext(N_("%d minute"), N_("%d minutes"),
995  min), min));
996  timeDiff -= min * 60;
997  }
998 
999  if (timeDiff > 0)
1000  {
1001  if (!str.empty())
1002  str.append(", ");
1003  // TRANSLATORS: uptime command
1004  str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1005  timeDiff), timeDiff));
1006  }
1007  if (str.empty())
1008  {
1009  // TRANSLATORS: uptime command
1010  str.append(strprintf(ngettext(N_("%d second"), N_("%d seconds"),
1011  0), 0));
1012  }
1013  return str;
1014 }
1015 
1016 std::string escapeString(std::string str)
1017 {
1018  replaceAll(str, "\"", "\\\"");
1019  return "\"" + str + "\"";
1020 }
1021 
1022 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  const char sepStr = '/';
1030  const std::string sep2Str = "//";
1031  const std::string sepWrongStr = "\\";
1032 #endif
1033  replaceRecursiveAll(path, sepWrongStr, sepStr);
1034  replaceRecursiveAll(path, sep2Str, sepStr);
1035 }
1036 
1037 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  const char sep = '/';
1045  std::string sepStr = "/";
1046 #endif
1047 
1048  if (str1.empty())
1049  {
1050  if (str2[0] == sep)
1051  return str2;
1052  return sepStr.append(str2);
1053  }
1054  const size_t sz1 = str1.size();
1055  if (str2.empty())
1056  {
1057  if (str1[sz1 - 1] == sep)
1058  return str1;
1059  return str1.append(sepStr);
1060  }
1061  if (str1[sz1 - 1] == sep)
1062  {
1063  if (str2[0] == sep)
1064  return str1.append(str2.substr(1));
1065  return str1.append(str2);
1066  }
1067  else
1068  {
1069  if (str2[0] == sep)
1070  return str1.append(str2);
1071  return str1.append(sepStr).append(str2);
1072  }
1073 }
1074 
1075 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  const char sep = '/';
1084  std::string sepStr = "/";
1085 #endif
1086 
1087  if (str1.empty())
1088  {
1089  return pathJoin(str2, str3);
1090  }
1091  size_t sz1 = str1.size();
1092  if (str2.empty())
1093  {
1094  return pathJoin(str1, str3);
1095  }
1096  if (str3.empty())
1097  {
1098  return pathJoin(str1, str2);
1099  }
1100  if (str1[sz1 - 1] == sep)
1101  {
1102  if (str2[0] == sep)
1103  str1.append(str2.substr(1));
1104  else
1105  str1.append(str2);
1106  }
1107  else
1108  {
1109  if (str2[0] == sep)
1110  str1.append(str2);
1111  else
1112  str1.append(sepStr).append(str2);
1113  }
1114 
1115  sz1 = str1.size();
1116  if (str1[sz1 - 1] == sep)
1117  {
1118  if (str3[0] == sep)
1119  return str1.append(str3.substr(1));
1120  return str1.append(str3);
1121  }
1122  else
1123  {
1124  if (str3[0] == sep)
1125  return str1.append(str3);
1126  return str1.append(sepStr).append(str3);
1127  }
1128 }
1129 
1130 std::string urlJoin(std::string str1,
1131  const std::string &str2)
1132 {
1133  const char sep = '/';
1134  std::string sepStr = "/";
1135 
1136  if (str1.empty())
1137  {
1138  if (str2[0] == sep)
1139  return str2;
1140  return sepStr.append(str2);
1141  }
1142  const size_t sz1 = str1.size();
1143  if (str2.empty())
1144  {
1145  if (str1[sz1 - 1] == sep)
1146  return str1;
1147  return str1.append(sepStr);
1148  }
1149  if (str1[sz1 - 1] == sep)
1150  {
1151  if (str2[0] == sep)
1152  return str1.append(str2.substr(1));
1153  return str1.append(str2);
1154  }
1155  else
1156  {
1157  if (str2[0] == sep)
1158  return str1.append(str2);
1159  return str1.append(sepStr).append(str2);
1160  }
1161 }
1162 
1163 size_t rfindSepatator(const std::string &str1)
1164 {
1165  const size_t idx1 = str1.rfind('/');
1166  const size_t idx2 = str1.rfind('\\');
1167  if (idx1 != std::string::npos)
1168  { // idx1
1169  if (idx2 != std::string::npos)
1170  { // idx1, idx2
1171  if (idx1 >= idx2)
1172  return idx1;
1173  else
1174  return idx2;
1175  }
1176  else
1177  { // idx1, not idx2
1178  return idx1;
1179  }
1180  }
1181  else
1182  { // not idx1
1183  if (idx2 != std::string::npos)
1184  { // not idx1, idx2
1185  return idx2;
1186  }
1187  else
1188  { // not idx1, not idx2
1189  return std::string::npos;
1190  }
1191  }
1192 }
1193 
1194 #ifndef DYECMD
1195 void replaceItemLinks(std::string &msg)
1196 {
1197  // Check for item link
1198  size_t start2 = msg.find('[');
1199  size_t sz = msg.size();
1200  while (start2 + 1 < sz &&
1201  start2 != std::string::npos &&
1202  msg[start2 + 1] != '@')
1203  {
1204  const size_t end = msg.find(']', start2);
1205  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  while ((msg.find('[', start2 + 1) != std::string::npos) &&
1211  (msg.find('[', start2 + 1) < end))
1212  {
1213  start2 = msg.find('[', start2 + 1);
1214  }
1215 
1216  if (start2 + 1 < sz &&
1217  end < sz &&
1218  end > start2 + 1)
1219  {
1220  std::string itemStr = msg.substr(start2 + 1, end - start2 - 1);
1221 
1222  StringVect parts;
1223  splitToStringVector(parts, itemStr, ',');
1224  if (parts.empty())
1225  return;
1226 
1227  const ItemInfo &itemInfo = ItemDB::get(parts[0]);
1228  const int itemId = itemInfo.getId();
1229  if (itemId != 0)
1230  {
1231  std::string temp = strprintf("@@%d", itemId);
1232  std::string name = parts[0];
1233  msg.erase(start2 + 1, end - start2 - 1);
1234  parts.erase(parts.begin());
1235  if (!parts.empty())
1236  name.clear();
1237 
1238  FOR_EACH (StringVectCIter, it, parts)
1239  {
1240  std:: string str = *it;
1241  trim(str);
1242  const ItemInfo &itemInfo2 = ItemDB::get(str);
1243  const int cardId = itemInfo2.getId();
1244  if (cardId != 0)
1245  temp.append(strprintf(",%d", cardId));
1246  }
1247  temp.append("|");
1248  temp.append(name);
1249  temp.append("@@");
1250  msg.insert(start2 + 1, temp);
1251  sz = msg.size();
1252  }
1253  }
1254  }
1255  start2 = msg.find('[', start2 + 1);
1256  }
1257 }
1258 #else // DYECMD
1259 
1260 void replaceItemLinks(std::string &msg A_UNUSED)
1261 {
1262 }
1263 #endif // DYECMD
#define CAST_S8
Definition: cast.h:26
#define CAST_S32
Definition: cast.h:30
#define CAST_U32
Definition: cast.h:31
#define CAST_SIZE
Definition: cast.h:34
#define CAST_U8
Definition: cast.h:27
#define CAST_8
Definition: cast.h:25
int getId() const
Definition: iteminfo.h:68
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define N_(s)
Definition: gettext.h:36
#define restrict
Definition: localconsts.h:165
#define A_UNUSED
Definition: localconsts.h:160
uint32_t data
bool msg(InputEvent &event)
Definition: chat.cpp:39
bool itemInfo(InputEvent &event)
Definition: commands.cpp:105
bool url(InputEvent &event)
Definition: commands.cpp:64
int size()
Definition: emotedb.cpp:306
const ItemInfo & get(const int id)
Definition: itemdb.cpp:792
std::string toString(uint32_t num)
std::string removeColors(std::string msg)
void sanitizePath(std::string &path)
std::string packList(const std::list< std::string > &list)
void cutFirst(std::string &str1, const std::string &str2)
std::string combineDye3(std::string file, const std::string &dye)
std::string & toUpper(std::string &str)
Definition: stringutils.cpp:72
std::string removeSpriteIndex(std::string str)
std::string getFileName(const std::string &path)
unsigned int atox(const std::string &str)
Definition: stringutils.cpp:78
std::list< std::string > splitToStringList(const std::string &text, const char separator)
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)
void deleteCharLeft(std::string &str, unsigned *const pos)
void cutLast(std::string &str1, const std::string &str2)
std::string combineDye(std::string file, const std::string &dye)
void splitToIntVector(std::vector< int > &tokens, const std::string &text, const char separator)
bool parse2Int(const std::string &args, int &x, int &y)
std::string stringToHexPath(const std::string &str)
std::string & removeProtocol(std::string &url)
std::string toStringPrint(const unsigned int val)
std::string strprintf(const char *const format,...)
std::string getDateTimeString()
bool parse2Str(const std::string &args, std::string &str1, std::string &str2)
std::string & toLower(std::string &str)
Definition: stringutils.cpp:66
std::string removeToken(std::string &str, const std::string &token)
void splitToStringVector(StringVect &tokens, const std::string &text, const char separator)
int compareStrI(const std::string &a, const std::string &b)
std::string timeDiffToString(int timeDiff)
std::string getFileDir(const std::string &path)
std::string escapeString(std::string str)
void replaceRecursiveAll(std::string &context, const std::string &from, const char to)
unsigned int decodeStr(const std::string &str)
bool findCutFirst(std::string &str1, const std::string &str2)
void splitToIntSet(std::set< int > &tokens, const std::string &text, const char separator)
size_t findI(std::string str, std::string subStr)
bool getBoolFromString(const std::string &text)
void replaceItemLinks(std::string &msg)
void splitToStringSet(std::set< std::string > &tokens, const std::string &text, const char separator)
bool findLast(const std::string &str1, const std::string &str2)
std::string decodeLinkText(std::string data)
signed char parseBoolean(const std::string &value)
size_t rfindSepatator(const std::string &str1)
std::string timeToStr(const uint32_t time)
bool findCutLast(std::string &str1, const std::string &str2)
std::string combineDye2(std::string file, const std::string &dye)
const char * getSafeUtf8String(const std::string &text)
std::string pathJoin(std::string str1, const std::string &str2)
size_t findAny(const std::string &text, const std::string &chars, const size_t pos)
std::string urlJoin(std::string str1, const std::string &str2)
const std::string encodeStr(unsigned int value, const unsigned int size)
bool isDigit(const std::string &str)
std::string normalize(const std::string &name)
std::list< int > splitToIntList(const std::string &text, const char separator)
void secureChatCommand(std::string &str)
std::string extractNameFromSprite(std::string str)
void replaceSpecialChars(std::string &text)
bool strStartWith(const std::string &str1, const std::string &str2)
const char * ipToString(const uint32_t address)
Definition: stringutils.cpp:86
const std::string findSameSubstring(const std::string &str1, const std::string &str2)
uint32_t parseNumber(const std::string &str)
std::string encodeLinkText(std::string data)
std::string getDateString()
const std::string findSameSubstringI(const std::string &s1, const std::string &s2)
bool findFirst(const std::string &str1, const std::string &str2)
std::string & trim(std::string &str)
Definition: stringutils.cpp:47
std::list< std::string > unpackList(const std::string &str)
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:31
std::vector< std::string > StringVect
Definition: stringvector.h:29
static const size_t UTF8_MAX_SIZE
Definition: utf8.h:27