TrinityCore
Util.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Util.h"
19#include "Common.h"
20#include "Containers.h"
21#include "IpAddress.h"
22#include "StringConvert.h"
23#include "StringFormat.h"
24#include <boost/core/demangle.hpp>
25#include <utf8.h>
26#include <algorithm>
27#include <string>
28#include <cctype>
29#include <cstdarg>
30#include <ctime>
31
33{
34#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
35 auto isWindowsBuildGreaterOrEqual = [](DWORD build)
36 {
37 OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, build, 0, {0}, 0, 0, 0, 0 };
38 ULONGLONG conditionMask = 0;
39 VER_SET_CONDITION(conditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);
40
41 return VerifyVersionInfo(&osvi, VER_BUILDNUMBER, conditionMask);
42 };
43
44 if (!isWindowsBuildGreaterOrEqual(TRINITY_REQUIRED_WINDOWS_BUILD))
45 {
46 OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0, 0, 0 };
47 GetVersionEx((LPOSVERSIONINFO)&osvi);
48 ABORT_MSG("TrinityCore requires Windows 10 19H1 (1903) or Windows Server 2019 (1903) - require build number 10.0.%d but found %d.%d.%d",
49 TRINITY_REQUIRED_WINDOWS_BUILD, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
50 }
51#endif
52}
53
54std::vector<std::string_view> Trinity::Tokenize(std::string_view str, char sep, bool keepEmpty)
55{
56 std::vector<std::string_view> tokens;
57
58 size_t start = 0;
59 for (size_t end = str.find(sep); end != std::string_view::npos; end = str.find(sep, start))
60 {
61 if (keepEmpty || (start < end))
62 tokens.push_back(str.substr(start, end - start));
63 start = end+1;
64 }
65
66 if (keepEmpty || (start < str.length()))
67 tokens.push_back(str.substr(start));
68
69 return tokens;
70}
71
72#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
73struct tm* localtime_r(time_t const* time, struct tm *result)
74{
75 if (localtime_s(result, time) != 0)
76 return nullptr;
77 return result;
78}
79struct tm* gmtime_r(time_t const* time, struct tm* result)
80{
81 if (gmtime_s(result, time) != 0)
82 return nullptr;
83 return result;
84}
85time_t timegm(struct tm* tm)
86{
87 return _mkgmtime(tm);
88}
89#endif
90
91tm TimeBreakdown(time_t time)
92{
93 tm timeLocal;
94 localtime_r(&time, &timeLocal);
95 return timeLocal;
96}
97
98time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime)
99{
100 tm timeLocal = TimeBreakdown(time);
101 timeLocal.tm_hour = 0;
102 timeLocal.tm_min = 0;
103 timeLocal.tm_sec = 0;
104 time_t midnightLocal = mktime(&timeLocal);
105 time_t hourLocal = midnightLocal + hour * HOUR;
106
107 if (onlyAfterTime && hourLocal <= time)
108 hourLocal += DAY;
109
110 return hourLocal;
111}
112
113std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hoursOnly)
114{
115 uint64 secs = timeInSecs % MINUTE;
116 uint64 minutes = timeInSecs % HOUR / MINUTE;
117 uint64 hours = timeInSecs % DAY / HOUR;
118 uint64 days = timeInSecs / DAY;
119
120 if (timeFormat == TimeFormat::Numeric)
121 {
122 if (days)
123 return Trinity::StringFormat("{}:{:02}:{:02}:{:02}", days, hours, minutes, secs);
124 else if (hours)
125 return Trinity::StringFormat("{}:{:02}:{:02}", hours, minutes, secs);
126 else if (minutes)
127 return Trinity::StringFormat("{}:{:02}", minutes, secs);
128 else
129 return Trinity::StringFormat("0:{:02}", secs);
130 }
131
132 std::string result;
133 if (timeFormat == TimeFormat::ShortText)
134 {
135 std::back_insert_iterator<std::string> itr = std::back_inserter(result);
136 if (days)
137 Trinity::StringFormatTo(itr, "{}d", days);
138 if (hours || hoursOnly)
139 Trinity::StringFormatTo(itr, "{}h", hours);
140 if (!hoursOnly)
141 {
142 if (minutes)
143 Trinity::StringFormatTo(itr, "{}m", minutes);
144 if (secs || result.empty())
145 Trinity::StringFormatTo(itr, "{}s", secs);
146 }
147 }
148 else if (timeFormat == TimeFormat::FullText)
149 {
150 auto formatTimeField = [](std::string& result, uint64 value, std::string_view label)
151 {
152 if (!result.empty())
153 result.append(1, ' ');
154 Trinity::StringFormatTo(std::back_inserter(result), "{} {}", value, label);
155 if (value != 1)
156 result.append(1, 's');
157 };
158 if (days)
159 formatTimeField(result, days, "Day");
160 if (hours || hoursOnly)
161 formatTimeField(result, hours, "Hour");
162 if (!hoursOnly)
163 {
164 if (minutes)
165 formatTimeField(result, minutes, "Minute");
166 if (secs || result.empty())
167 formatTimeField(result, secs, "Second");
168 }
169 result.append(1, '.');
170 }
171 else
172 result = "<Unknown time format>";
173
174 return result;
175}
176
177Optional<int64> MoneyStringToMoney(std::string const& moneyString)
178{
179 int64 money = 0;
180
181 bool hadG = false;
182 bool hadS = false;
183 bool hadC = false;
184
185 for (std::string_view token : Trinity::Tokenize(moneyString, ' ', false))
186 {
187 uint32 unit;
188 switch (token[token.length() - 1])
189 {
190 case 'g':
191 if (hadG) return std::nullopt;
192 hadG = true;
193 unit = 100 * 100;
194 break;
195 case 's':
196 if (hadS) return std::nullopt;
197 hadS = true;
198 unit = 100;
199 break;
200 case 'c':
201 if (hadC) return std::nullopt;
202 hadC = true;
203 unit = 1;
204 break;
205 default:
206 return std::nullopt;
207 }
208
209 Optional<uint64> amount = Trinity::StringTo<uint32>(token.substr(0, token.length() - 1));
210 if (amount)
211 money += (unit * *amount);
212 else
213 return std::nullopt;
214 }
215
216 return money;
217}
218
219uint32 TimeStringToSecs(std::string const& timestring)
220{
221 uint32 secs = 0;
222 uint32 buffer = 0;
223 uint32 multiplier = 0;
224
225 for (char itr : timestring)
226 {
227 if (isdigit(itr))
228 {
229 buffer *= 10;
230 buffer += itr - '0';
231 }
232 else
233 {
234 switch (itr)
235 {
236 case 'd': multiplier = DAY; break;
237 case 'h': multiplier = HOUR; break;
238 case 'm': multiplier = MINUTE; break;
239 case 's': multiplier = 1; break;
240 default : return 0; //bad format
241 }
242 buffer *= multiplier;
243 secs += buffer;
244 buffer = 0;
245 }
246 }
247
248 return secs;
249}
250
251std::string TimeToTimestampStr(time_t t)
252{
253 tm aTm;
254 localtime_r(&t, &aTm);
255 // YYYY year
256 // MM month (2 digits 01-12)
257 // DD day (2 digits 01-31)
258 // HH hour (2 digits 00-23)
259 // MM minutes (2 digits 00-59)
260 // SS seconds (2 digits 00-59)
261 return Trinity::StringFormat("{:04}-{:02}-{:02}_{:02}-{:02}-{:02}", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
262}
263
264std::string TimeToHumanReadable(time_t t)
265{
266 tm time;
267 localtime_r(&t, &time);
268 char buf[30];
269 strftime(buf, 30, "%c", &time);
270 return std::string(buf);
271}
272
274bool IsIPAddress(char const* ipaddress)
275{
276 if (!ipaddress)
277 return false;
278
279 boost::system::error_code error;
280 Trinity::Net::make_address(ipaddress, error);
281 return !error;
282}
283
285uint32 CreatePIDFile(std::string const& filename)
286{
287 FILE* pid_file = fopen(filename.c_str(), "w");
288 if (pid_file == nullptr)
289 return 0;
290
291 uint32 pid = GetPID();
292
293 fprintf(pid_file, "%u", pid);
294 fclose(pid_file);
295
296 return pid;
297}
298
300{
301#ifdef _WIN32
302 DWORD pid = GetCurrentProcessId();
303#else
304 pid_t pid = getpid();
305#endif
306
307 return uint32(pid);
308}
309
310size_t utf8length(std::string& utf8str)
311{
312 try
313 {
314 return utf8::distance(utf8str.c_str(), utf8str.c_str()+utf8str.size());
315 }
316 catch (std::exception const&)
317 {
318 utf8str.clear();
319 return 0;
320 }
321}
322
323void utf8truncate(std::string& utf8str, size_t len)
324{
325 try
326 {
327 size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str()+utf8str.size());
328 if (wlen <= len)
329 return;
330
331 std::wstring wstr;
332 wstr.resize(wlen);
333 utf8::utf8to16(utf8str.c_str(), utf8str.c_str()+utf8str.size(), &wstr[0]);
334 wstr.resize(len);
335 char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str()+wstr.size(), &utf8str[0]);
336 utf8str.resize(oend-(&utf8str[0])); // remove unused tail
337 }
338 catch (std::exception const&)
339 {
340 utf8str.clear();
341 }
342}
343
344bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
345{
346 try
347 {
349 out = utf8::utf8to16(utf8str, utf8str+csize, out);
350 wsize -= out.remaining(); // remaining unused space
351 wstr[wsize] = L'\0';
352 }
353 catch (std::exception const&)
354 {
355 // Replace the converted string with an error message if there is enough space
356 // Otherwise just return an empty string
357 wchar_t const* errorMessage = L"An error occurred converting string from UTF-8 to WStr";
358 size_t errorMessageLength = wcslen(errorMessage);
359 if (wsize >= errorMessageLength)
360 {
361 wcscpy(wstr, errorMessage);
362 wsize = wcslen(wstr);
363 }
364 else if (wsize > 0)
365 {
366 wstr[0] = L'\0';
367 wsize = 0;
368 }
369 else
370 wsize = 0;
371
372 return false;
373 }
374
375 return true;
376}
377
378bool Utf8toWStr(std::string_view utf8str, std::wstring& wstr)
379{
380 wstr.clear();
381 try
382 {
383 utf8::utf8to16(utf8str.begin(), utf8str.end(), std::back_inserter(wstr));
384 }
385 catch (std::exception const&)
386 {
387 wstr.clear();
388 return false;
389 }
390
391 return true;
392}
393
394bool WStrToUtf8(wchar_t const* wstr, size_t size, std::string& utf8str)
395{
396 try
397 {
398 std::string utf8str2;
399 utf8str2.resize(size*4); // allocate for most long case
400
401 if (size)
402 {
403 char* oend = utf8::utf16to8(wstr, wstr+size, &utf8str2[0]);
404 utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
405 }
406 utf8str = utf8str2;
407 }
408 catch (std::exception const&)
409 {
410 utf8str.clear();
411 return false;
412 }
413
414 return true;
415}
416
417bool WStrToUtf8(std::wstring_view wstr, std::string& utf8str)
418{
419 try
420 {
421 std::string utf8str2;
422 utf8str2.resize(wstr.size()*4); // allocate for most long case
423
424 if (!wstr.empty())
425 {
426 char* oend = utf8::utf16to8(wstr.begin(), wstr.end(), &utf8str2[0]);
427 utf8str2.resize(oend-(&utf8str2[0])); // remove unused tail
428 }
429 utf8str = utf8str2;
430 }
431 catch (std::exception const&)
432 {
433 utf8str.clear();
434 return false;
435 }
436
437 return true;
438}
439
440void wstrToUpper(std::wstring& str) { std::ranges::transform(str, std::begin(str), wcharToUpper); }
441void wstrToLower(std::wstring& str) { std::ranges::transform(str, std::begin(str), wcharToLower); }
442void strToUpper(std::string& str) { std::ranges::transform(str, std::begin(str), charToUpper); }
443void strToLower(std::string& str) { std::ranges::transform(str, std::begin(str), charToLower); }
444
445std::wstring wstrCaseAccentInsensitiveParse(std::wstring_view wstr, LocaleConstant locale)
446{
447 std::wstring result;
448 result.reserve(wstr.length() * 2);
449
450 switch (locale)
451 {
452 case LOCALE_frFR:
453 for (wchar_t wchar : wstr)
454 {
455 wchar = wcharToLower(wchar);
456 switch (wchar)
457 {
458 case 0x00A0: // NO-BREAK SPACE
459 result += L' ';
460 break;
461 case 0x00AB: // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
462 case 0x00BB: // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
463 result += L'"';
464 break;
465 case 0x00E7: // LATIN SMALL LETTER C WITH CEDILLA
466 result += L'c';
467 break;
468 case 0x00E8: // LATIN SMALL LETTER E WITH GRAVE
469 case 0x00E9: // LATIN SMALL LETTER E WITH ACUTE
470 case 0x00EA: // LATIN SMALL LETTER E WITH CIRCUMFLEX
471 case 0x00EB: // LATIN SMALL LETTER E WITH DIAERESIS
472 result += L'e';
473 break;
474 case 0x00EE: // LATIN SMALL LETTER I WITH CIRCUMFLEX
475 case 0x00EF: // LATIN SMALL LETTER I WITH DIAERESIS
476 result += L'i';
477 break;
478 case 0x00F2: // LATIN SMALL LETTER O WITH GRAVE
479 case 0x00F3: // LATIN SMALL LETTER O WITH ACUTE
480 case 0x00F4: // LATIN SMALL LETTER O WITH CIRCUMFLEX
481 case 0x00F6: // LATIN SMALL LETTER O WITH DIAERESIS
482 result += L'o';
483 break;
484 case 0x00F9: // LATIN SMALL LETTER U WITH GRAVE
485 case 0x00FA: // LATIN SMALL LETTER U WITH ACUTE
486 case 0x00FB: // LATIN SMALL LETTER U WITH CIRCUMFLEX
487 case 0x00FC: // LATIN SMALL LETTER U WITH DIAERESIS
488 result += L'u';
489 break;
490 case 0x0153: // LATIN SMALL LIGATURE OE
491 result += L'o';
492 result += L'e';
493 break;
494 case 0x2013: // EN DASH
495 result += L'-';
496 break;
497 case 0x2018: // LEFT SINGLE QUOTATION MARK
498 case 0x2019: // RIGHT SINGLE QUOTATION MARK
499 result += L'\'';
500 break;
501 default:
502 result += wchar;
503 break;
504 }
505 }
506 break;
507 case LOCALE_deDE:
508 for (wchar_t wchar : wstr)
509 {
510 wchar = wcharToLower(wchar);
511 if (wchar == 0x00DF) // LATIN SMALL LETTER SHARP S
512 {
513 result += L's';
514 result += L's';
515 }
516 else
517 result += wchar;
518 }
519 break;
520 case LOCALE_esES:
521 case LOCALE_esMX:
522 case LOCALE_itIT:
523 for (wchar_t wchar : wstr)
524 {
525 wchar = wcharToLower(wchar);
526 switch (wchar)
527 {
528 case 0x00E1: // LATIN SMALL LETTER A WITH ACUTE
529 result += L'a';
530 break;
531 case 0x00E9: // LATIN SMALL LETTER E WITH ACUTE
532 result += L'e';
533 break;
534 case 0x00ED: // LATIN SMALL LETTER I WITH ACUTE
535 result += L'i';
536 break;
537 case 0x00F1: // LATIN SMALL LETTER N WITH TILDE
538 result += L'n';
539 break;
540 case 0x00F3: // LATIN SMALL LETTER O WITH ACUTE
541 result += L'o';
542 break;
543 case 0x00FA: // LATIN SMALL LETTER U WITH ACUTE
544 case 0x00FC: // LATIN SMALL LETTER U WITH DIAERESIS
545 result += L'u';
546 break;
547 default:
548 result += wchar;
549 break;
550 }
551 }
552 break;
553 case LOCALE_ruRU:
554 for (wchar_t wchar : wstr)
555 {
556 wchar = wcharToLower(wchar);
557 switch (wchar)
558 {
559 case 0x451: // CYRILLIC SMALL LETTER IO
560 result += wchar_t(0x435);
561 break;
562 case 0x2013: // EN DASH
563 result += L'-';
564 break;
565 default:
566 result += wchar;
567 break;
568 }
569 }
570 break;
571 case LOCALE_ptBR:
572 for (wchar_t wchar : wstr)
573 {
574 wchar = wcharToLower(wchar);
575 switch (wchar)
576 {
577 case 0x00E0: // LATIN SMALL LETTER A WITH GRAVE
578 case 0x00E1: // LATIN SMALL LETTER A WITH ACUTE
579 case 0x00E2: // LATIN SMALL LETTER A WITH CIRCUMFLEX
580 case 0x00E3: // LATIN SMALL LETTER A WITH TILDE
581 case 0x00E4: // LATIN SMALL LETTER A WITH DIAERESIS
582 result += L'a';
583 break;
584 case 0x00E7: // LATIN SMALL LETTER C WITH CEDILLA
585 result += L'c';
586 break;
587 case 0x00E8: // LATIN SMALL LETTER E WITH GRAVE
588 case 0x00E9: // LATIN SMALL LETTER E WITH ACUTE
589 case 0x00EA: // LATIN SMALL LETTER E WITH CIRCUMFLEX
590 case 0x00EB: // LATIN SMALL LETTER E WITH DIAERESIS
591 result += L'e';
592 break;
593 case 0x00EC: // LATIN SMALL LETTER I WITH GRAVE
594 case 0x00ED: // LATIN SMALL LETTER I WITH ACUTE
595 case 0x00EE: // LATIN SMALL LETTER I WITH CIRCUMFLEX
596 case 0x00EF: // LATIN SMALL LETTER I WITH DIAERESIS
597 result += L'i';
598 break;
599 case 0x00F1: // LATIN SMALL LETTER N WITH TILDE
600 result += L'n';
601 break;
602 case 0x00F2: // LATIN SMALL LETTER O WITH GRAVE
603 case 0x00F3: // LATIN SMALL LETTER O WITH ACUTE
604 case 0x00F4: // LATIN SMALL LETTER O WITH CIRCUMFLEX
605 case 0x00F5: // LATIN SMALL LETTER O WITH TILDE
606 case 0x00F6: // LATIN SMALL LETTER O WITH DIAERESIS
607 result += L'o';
608 break;
609 case 0x00F9: // LATIN SMALL LETTER U WITH GRAVE
610 case 0x00FA: // LATIN SMALL LETTER U WITH ACUTE
611 case 0x00FB: // LATIN SMALL LETTER U WITH CIRCUMFLEX
612 case 0x00FC: // LATIN SMALL LETTER U WITH DIAERESIS
613 result += L'u';
614 break;
615 default:
616 result += wchar;
617 break;
618 }
619 }
620 break;
621 default:
622 result = wstr;
623 wstrToLower(result);
624 break;
625 }
626
627 return result;
628}
629
630std::wstring GetMainPartOfName(std::wstring const& wname, uint32 declension)
631{
632 std::wstring result = wname;
633
634 // supported only Cyrillic cases
635 if (wname.empty() || !isCyrillicCharacter(wname[0]) || declension > 5)
636 return result;
637
638 // Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
639 static constexpr std::wstring_view a_End = L"\x430";
640 static constexpr std::wstring_view o_End = L"\x43E";
641 static constexpr std::wstring_view ya_End = L"\x44F";
642 static constexpr std::wstring_view ie_End = L"\x435";
643 static constexpr std::wstring_view i_End = L"\x438";
644 static constexpr std::wstring_view yeru_End = L"\x44B";
645 static constexpr std::wstring_view u_End = L"\x443";
646 static constexpr std::wstring_view yu_End = L"\x44E";
647 static constexpr std::wstring_view oj_End = L"\x43E\x439";
648 static constexpr std::wstring_view ie_j_End = L"\x435\x439";
649 static constexpr std::wstring_view io_j_End = L"\x451\x439";
650 static constexpr std::wstring_view o_m_End = L"\x43E\x43C";
651 static constexpr std::wstring_view io_m_End = L"\x451\x43C";
652 static constexpr std::wstring_view ie_m_End = L"\x435\x43C";
653 static constexpr std::wstring_view soft_End = L"\x44C";
654 static constexpr std::wstring_view j_End = L"\x439";
655
656 static constexpr std::array<std::array<std::wstring_view, 7>, 6> dropEnds = {{
657 { a_End, o_End, ya_End, ie_End, soft_End, j_End, {} },
658 { a_End, ya_End, yeru_End, i_End, {}, {}, {} },
659 { ie_End, u_End, yu_End, i_End, {}, {}, {} },
660 { u_End, yu_End, o_End, ie_End, soft_End, ya_End, a_End },
661 { oj_End, io_j_End, ie_j_End, o_m_End, io_m_End, ie_m_End, yu_End },
662 { ie_End, i_End, {}, {}, {}, {}, {} }
663 }};
664
665 std::size_t const thisLen = wname.length();
666 std::array<std::wstring_view, 7> const& endings = dropEnds[declension];
667 for (auto itr = endings.begin(), end = endings.end(); itr != end && !itr->empty(); ++itr)
668 {
669 std::size_t const endLen = itr->length();
670 if (endLen > thisLen)
671 continue;
672
673 if (wname.ends_with(*itr))
674 {
675 result.erase(thisLen - endLen);
676 break;
677 }
678 }
679
680 return result;
681}
682
683bool utf8ToConsole(std::string_view utf8str, std::string& conStr)
684{
685#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
686 std::wstring wstr;
687 if (!Utf8toWStr(utf8str, wstr))
688 return false;
689
690 conStr.resize(wstr.size());
691 CharToOemBuffW(&wstr[0], &conStr[0], uint32(wstr.size()));
692#else
693 // not implemented yet
694 conStr = utf8str;
695#endif
696
697 return true;
698}
699
700bool consoleToUtf8(std::string_view conStr, std::string& utf8str)
701{
702#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
703 std::wstring wstr;
704 wstr.resize(conStr.size());
705 OemToCharBuffW(&conStr[0], &wstr[0], uint32(conStr.size()));
706
707 return WStrToUtf8(wstr, utf8str);
708#else
709 // not implemented yet
710 utf8str = conStr;
711 return true;
712#endif
713}
714
715bool Utf8FitTo(std::string_view str, std::wstring_view search)
716{
717 std::wstring temp;
718
719 if (!Utf8toWStr(str, temp))
720 return false;
721
722 // converting to lower case
723 wstrToLower(temp);
724
725 if (temp.find(search) == std::wstring::npos)
726 return false;
727
728 return true;
729}
730
731void utf8printf(FILE* out, const char *str, ...)
732{
733 va_list ap;
734 va_start(ap, str);
735 vutf8printf(out, str, &ap);
736 va_end(ap);
737}
738
739void vutf8printf(FILE* out, const char *str, va_list* ap)
740{
741#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
742 char temp_buf[32 * 1024];
743 wchar_t wtemp_buf[32 * 1024];
744
745 size_t temp_len = vsnprintf(temp_buf, 32 * 1024, str, *ap);
746 //vsnprintf returns -1 if the buffer is too small
747 if (temp_len == size_t(-1))
748 temp_len = 32*1024-1;
749
750 size_t wtemp_len = 32*1024-1;
751 Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
752
753 CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], uint32(wtemp_len + 1));
754 fprintf(out, "%s", temp_buf);
755#else
756 vfprintf(out, str, *ap);
757#endif
758}
759
760bool Utf8ToUpperOnlyLatin(std::string& utf8String)
761{
762 std::wstring wstr;
763 if (!Utf8toWStr(utf8String, wstr))
764 return false;
765
766 std::ranges::transform(wstr, wstr.begin(), wcharToUpperOnlyLatin);
767
768 return WStrToUtf8(wstr, utf8String);
769}
770
771#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS
772bool ReadWinConsole(std::string& str, size_t size /*= 256*/)
773{
774 wchar_t* commandbuf = new wchar_t[size + 1];
775 HANDLE hConsole = GetStdHandle(STD_INPUT_HANDLE);
776 DWORD read = 0;
777
778 if (!ReadConsoleW(hConsole, commandbuf, size, &read, nullptr) || read == 0)
779 {
780 delete[] commandbuf;
781 return false;
782 }
783
784 commandbuf[read] = 0;
785
786 bool ok = WStrToUtf8(commandbuf, wcslen(commandbuf), str);
787 delete[] commandbuf;
788 return ok;
789}
790
791bool WriteWinConsole(std::string_view str, bool error /*= false*/)
792{
793 std::wstring wstr;
794 wstr.reserve(str.length());
795 if (!Utf8toWStr(str, wstr))
796 return false;
797
798 HANDLE hConsole = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
799 DWORD write = 0;
800
801 return WriteConsoleW(hConsole, wstr.c_str(), wstr.size(), &write, nullptr);
802}
803#endif
804
806{
807 std::size_t nextLineIndex = str.find_first_of("\r\n");
808 if (nextLineIndex == std::string::npos)
809 return std::nullopt;
810
811 str.erase(nextLineIndex);
812 return nextLineIndex;
813}
814
815std::string Trinity::Impl::ByteArrayToHexStr(uint8 const* bytes, size_t arrayLen, bool reverse /* = false */)
816{
817 int32 init = 0;
818 int32 end = arrayLen;
819 int8 op = 1;
820
821 if (reverse)
822 {
823 init = arrayLen - 1;
824 end = -1;
825 op = -1;
826 }
827
828 std::string result;
829 result.reserve(arrayLen * 2);
830 auto inserter = std::back_inserter(result);
831 for (int32 i = init; i != end; i += op)
832 Trinity::StringFormatTo(inserter, "{:02X}", bytes[i]);
833
834 return result;
835}
836
837void Trinity::Impl::HexStrToByteArray(std::string_view str, uint8* out, size_t outlen, bool reverse /*= false*/)
838{
839 ASSERT(str.size() == (2 * outlen));
840
841 int32 init = 0;
842 int32 end = int32(str.length());
843 int8 op = 1;
844
845 if (reverse)
846 {
847 init = int32(str.length() - 2);
848 end = -2;
849 op = -1;
850 }
851
852 uint32 j = 0;
853 for (int32 i = init; i != end; i += 2 * op)
854 out[j++] = Trinity::StringTo<uint8>(str.substr(i, 2), 16).value_or(0);
855}
856
857bool StringEqualI(std::string_view a, std::string_view b)
858{
859 return std::ranges::equal(a, b, {}, charToLower, charToLower);
860}
861
862bool StringContainsStringI(std::string_view haystack, std::string_view needle)
863{
864 return haystack.end() !=
865 std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), [](char c1, char c2) { return charToLower(c1) == charToLower(c2); });
866}
867
868bool StringCompareLessI(std::string_view a, std::string_view b)
869{
870 return std::ranges::lexicographical_compare(a, b, {}, charToLower, charToLower);
871}
872
873std::string Trinity::Impl::GetTypeName(std::type_info const& info)
874{
875 return boost::core::demangle(info.name());
876}
877
878float DegToRad(float degrees)
879{
880 return degrees * (2.f * float(M_PI) / 360.f);
881}
LocaleConstant
Definition: Common.h:48
@ LOCALE_deDE
Definition: Common.h:52
@ LOCALE_ptBR
Definition: Common.h:59
@ LOCALE_itIT
Definition: Common.h:60
@ LOCALE_esES
Definition: Common.h:55
@ LOCALE_ruRU
Definition: Common.h:57
@ LOCALE_frFR
Definition: Common.h:51
@ LOCALE_esMX
Definition: Common.h:56
@ MINUTE
Definition: Common.h:29
@ HOUR
Definition: Common.h:30
@ DAY
Definition: Common.h:31
#define M_PI
Definition: Common.h:115
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
#define TC_COMMON_API
Definition: Define.h:99
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
#define ABORT_MSG
Definition: Errors.h:75
#define ASSERT
Definition: Errors.h:68
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
float DegToRad(float degrees)
Definition: Util.cpp:878
bool consoleToUtf8(std::string_view conStr, std::string &utf8str)
Definition: Util.cpp:700
std::wstring GetMainPartOfName(std::wstring const &wname, uint32 declension)
Definition: Util.cpp:630
bool StringEqualI(std::string_view a, std::string_view b)
Definition: Util.cpp:857
bool WriteWinConsole(std::string_view str, bool error)
Definition: Util.cpp:791
bool WStrToUtf8(wchar_t const *wstr, size_t size, std::string &utf8str)
Definition: Util.cpp:394
bool Utf8ToUpperOnlyLatin(std::string &utf8String)
Definition: Util.cpp:760
void wstrToLower(std::wstring &str)
Definition: Util.cpp:441
bool IsIPAddress(char const *ipaddress)
Check if the string is a valid ip address representation.
Definition: Util.cpp:274
std::string TimeToTimestampStr(time_t t)
Definition: Util.cpp:251
bool StringContainsStringI(std::string_view haystack, std::string_view needle)
Definition: Util.cpp:862
time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime)
Definition: Util.cpp:98
void utf8printf(FILE *out, const char *str,...)
Definition: Util.cpp:731
void strToLower(std::string &str)
Definition: Util.cpp:443
TC_COMMON_API Optional< std::size_t > RemoveCRLF(std::string &str)
Definition: Util.cpp:805
uint32 CreatePIDFile(std::string const &filename)
create PID file
Definition: Util.cpp:285
bool utf8ToConsole(std::string_view utf8str, std::string &conStr)
Definition: Util.cpp:683
tm TimeBreakdown(time_t time)
Definition: Util.cpp:91
std::wstring wstrCaseAccentInsensitiveParse(std::wstring_view wstr, LocaleConstant locale)
Definition: Util.cpp:445
std::string TimeToHumanReadable(time_t t)
Definition: Util.cpp:264
bool StringCompareLessI(std::string_view a, std::string_view b)
Definition: Util.cpp:868
bool Utf8FitTo(std::string_view str, std::wstring_view search)
Definition: Util.cpp:715
std::string secsToTimeString(uint64 timeInSecs, TimeFormat timeFormat, bool hoursOnly)
Definition: Util.cpp:113
uint32 GetPID()
Definition: Util.cpp:299
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition: Util.cpp:344
Optional< int64 > MoneyStringToMoney(std::string const &moneyString)
Definition: Util.cpp:177
bool ReadWinConsole(std::string &str, size_t size)
Definition: Util.cpp:772
size_t utf8length(std::string &utf8str)
Definition: Util.cpp:310
void utf8truncate(std::string &utf8str, size_t len)
Definition: Util.cpp:323
uint32 TimeStringToSecs(std::string const &timestring)
Definition: Util.cpp:219
void wstrToUpper(std::wstring &str)
Definition: Util.cpp:440
void strToUpper(std::string &str)
Definition: Util.cpp:442
void vutf8printf(FILE *out, const char *str, va_list *ap)
Definition: Util.cpp:739
struct WcharToUpperOnlyLatin wcharToUpperOnlyLatin
TimeFormat
Definition: Util.h:35
struct WcharToLower wcharToLower
struct CharToUpper charToUpper
bool isCyrillicCharacter(wchar_t wchar)
Definition: Util.h:175
struct CharToLower charToLower
struct WcharToUpper wcharToUpper
TC_COMMON_API void HexStrToByteArray(std::string_view str, uint8 *out, size_t outlen, bool reverse=false)
Definition: Util.cpp:837
TC_COMMON_API std::string ByteArrayToHexStr(uint8 const *bytes, size_t length, bool reverse=false)
Definition: Util.cpp:815
TC_COMMON_API std::string GetTypeName(std::type_info const &)
Definition: Util.cpp:873
TC_COMMON_API void VerifyOsVersion()
Definition: Util.cpp:32
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:54
OutputIt StringFormatTo(OutputIt out, FormatString< Args... > fmt, Args &&... args)
Definition: StringFormat.h:51
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
Definition: StringFormat.h:38
constexpr std::size_t size()
Definition: UpdateField.h:769