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