Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
Util.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Common.h"
7#include "Errors.h" // for ASSERT
9#include "sfmt.h"
10#include "utf8.h"
11#include "Util.h"
12
13#include <atomic>
14#include <cstdarg>
15#include <random>
16
17namespace
18{
19 uint32 BuildSfmtSeed()
20 {
21 static std::atomic<uint32> seedCounter{ 0 };
22
23 std::random_device entropy;
24
25 uint32 seed = static_cast<uint32>(entropy());
26 seed ^= static_cast<uint32>(entropy());
27 seed ^= ++seedCounter * 0x9E3779B9u;
28
29 return seed ? seed : 1;
30 }
31}
32
33static CRandomSFMT& SfmtRand()
34{
35 static thread_local CRandomSFMT sfmtRand(static_cast<int>(BuildSfmtSeed()));
36 return sfmtRand;
37}
38
39float frand(float min, float max)
40{
41 ASSERT(max >= min);
42 return float(SfmtRand().Random() * (max - min) + min);
43}
44
46{
47 return int32(SfmtRand().BRandom());
48}
49
50double rand_norm(void)
51{
52 return SfmtRand().Random();
53}
54
55double rand_chance(void)
56{
57 return SfmtRand().Random() * 100.0;
58}
59
60Tokenizer::Tokenizer(const std::string& src, const char sep, uint32 vectorReserve)
61{
62 m_str = new char[src.length() + 1];
63 memcpy(m_str, src.c_str(), src.length() + 1);
64
65 if (vectorReserve)
66 m_storage.reserve(vectorReserve);
67
68 char* posold = m_str;
69 char* posnew = m_str;
70
71 for (;;)
72 {
73 if (*posnew == sep)
74 {
75 m_storage.push_back(posold);
76 posold = posnew + 1;
77
78 *posnew = '\0';
79 }
80 else if (*posnew == '\0')
81 {
82 // Hack like, but the old code accepted these kind of broken strings,
83 // so changing it would break other things
84 if (posold != posnew)
85 m_storage.push_back(posold);
86
87 break;
88 }
89
90 ++posnew;
91 }
92}
93
94void stripLineInvisibleChars(std::string& str)
95{
96 static std::string const invChars = " \t\7\n";
97
98 size_t wpos = 0;
99
100 bool space = false;
101 for (size_t pos = 0; pos < str.size(); ++pos)
102 {
103 if (invChars.find(str[pos]) != std::string::npos)
104 {
105 if (!space)
106 {
107 str[wpos++] = ' ';
108 space = true;
109 }
110 }
111 else
112 {
113 if (wpos != pos)
114 str[wpos++] = str[pos];
115 else
116 ++wpos;
117 space = false;
118 }
119 }
120
121 if (wpos < str.size())
122 str.erase(wpos, str.size());
123 if (str.find("|TInterface") != std::string::npos)
124 str.clear();
125}
126
127std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly)
128{
129 uint64 secs = timeInSecs % MINUTE;
130 uint64 minutes = timeInSecs % HOUR / MINUTE;
131 uint64 hours = timeInSecs % DAY / HOUR;
132 uint64 days = timeInSecs / DAY;
133
134 std::ostringstream ss;
135 if (days)
136 ss << days << (shortText ? "d" : " Day(s) ");
137 if (hours || hoursOnly)
138 ss << hours << (shortText ? "h" : " Hour(s) ");
139 if (!hoursOnly)
140 {
141 if (minutes)
142 ss << minutes << (shortText ? "m" : " Minute(s) ");
143 if (secs || (!days && !hours && !minutes))
144 ss << secs << (shortText ? "s" : " Second(s).");
145 }
146
147 return ss.str();
148}
149
150int64 MoneyStringToMoney(const std::string& moneyString)
151{
152 int64 money = 0;
153
154 if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 ||
155 std::count(moneyString.begin(), moneyString.end(), 's') == 1 ||
156 std::count(moneyString.begin(), moneyString.end(), 'c') == 1))
157 return 0; // Bad format
158
159 Tokenizer tokens(moneyString, ' ');
160 for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr)
161 {
162 std::string tokenString(*itr);
163 size_t gCount = std::count(tokenString.begin(), tokenString.end(), 'g');
164 size_t sCount = std::count(tokenString.begin(), tokenString.end(), 's');
165 size_t cCount = std::count(tokenString.begin(), tokenString.end(), 'c');
166 if (gCount + sCount + cCount != 1)
167 return 0;
168
169 uint64 amount = atol(*itr);
170 if (gCount == 1)
171 money += amount * 100 * 100;
172 else if (sCount == 1)
173 money += amount * 100;
174 else if (cCount == 1)
175 money += amount;
176 }
177
178 return money;
179}
180
181uint32 TimeStringToSecs(const std::string& timestring)
182{
183 uint32 secs = 0;
184 uint32 buffer = 0;
185 uint32 multiplier = 0;
186
187 for (std::string::const_iterator itr = timestring.begin(); itr != timestring.end(); ++itr)
188 {
189 if (isdigit(*itr))
190 {
191 buffer *= 10;
192 buffer += (*itr) - '0';
193 }
194 else
195 {
196 switch (*itr)
197 {
198 case 'd': multiplier = DAY; break;
199 case 'h': multiplier = HOUR; break;
200 case 'm': multiplier = MINUTE; break;
201 case 's': multiplier = 1; break;
202 default: return 0; //bad format
203 }
204 buffer *= multiplier;
205 secs += buffer;
206 buffer = 0;
207 }
208 }
209
210 return secs;
211}
212
213std::string TimeToTimestampStr(time_t t)
214{
215 tm aTm;
216 Skyfire::LocalTime(t, aTm);
217 // YYYY year
218 // MM month (2 digits 01-12)
219 // DD day (2 digits 01-31)
220 // HH hour (2 digits 00-23)
221 // MM minutes (2 digits 00-59)
222 // SS seconds (2 digits 00-59)
223 char buf[72];
224 snprintf(buf, sizeof(buf), "%04d-%02d-%02d_%02d-%02d-%02d", aTm.tm_year + 1900, aTm.tm_mon + 1, aTm.tm_mday, aTm.tm_hour, aTm.tm_min, aTm.tm_sec);
225 return std::string(buf);
226}
227
229bool IsIPAddress(char const* ipaddress)
230{
231 if (!ipaddress)
232 return false;
233
234 return Skyfire::Net::IsIPv4Address(ipaddress);
235}
236
238{
239 std::ostringstream ss;
240 ss << addr.GetHost() << ':' << addr.GetPort();
241 return ss.str();
242}
243
245{
246 uint32 mask = subnetMask.ToIPv4NetworkOrder();
247 if ((net.ToIPv4NetworkOrder() & mask) == (addr.ToIPv4NetworkOrder() & mask))
248 return true;
249 return false;
250}
251
253uint32 CreatePIDFile(const std::string& filename)
254{
255 FILE* pid_file = fopen(filename.c_str(), "w");
256 if (pid_file == NULL)
257 return 0;
258
259#ifdef _WIN32
260 DWORD pid = GetCurrentProcessId();
261#else
262 pid_t pid = getpid();
263#endif
264
265 fprintf(pid_file, "%u", pid);
266 fclose(pid_file);
267
268 return (uint32)pid;
269}
270
271size_t utf8length(std::string& utf8str)
272{
273 try
274 {
275 return utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
276 }
277 catch (std::exception&)
278 {
279 utf8str = "";
280 return 0;
281 }
282}
283
284void utf8truncate(std::string& utf8str, size_t len)
285{
286 try
287 {
288 size_t wlen = utf8::distance(utf8str.c_str(), utf8str.c_str() + utf8str.size());
289 if (wlen <= len)
290 return;
291
292 std::wstring wstr;
293 wstr.resize(wlen);
294 utf8::utf8to16(utf8str.c_str(), utf8str.c_str() + utf8str.size(), &wstr[0]);
295 wstr.resize(len);
296 char* oend = utf8::utf16to8(wstr.c_str(), wstr.c_str() + wstr.size(), &utf8str[0]);
297 utf8str.resize(oend - (&utf8str[0])); // remove unused tail
298 }
299 catch (std::exception&)
300 {
301 utf8str = "";
302 }
303}
304
305bool Utf8toWStr(char const* utf8str, size_t csize, wchar_t* wstr, size_t& wsize)
306{
307 try
308 {
309 size_t len = utf8::distance(utf8str, utf8str + csize);
310 if (len > wsize)
311 {
312 if (wsize > 0)
313 wstr[0] = L'\0';
314 wsize = 0;
315 return false;
316 }
317
318 wsize = len;
319 utf8::utf8to16(utf8str, utf8str + csize, wstr);
320 wstr[len] = L'\0';
321 }
322 catch (std::exception&)
323 {
324 if (wsize > 0)
325 wstr[0] = L'\0';
326 wsize = 0;
327 return false;
328 }
329
330 return true;
331}
332
333bool Utf8toWStr(const std::string& utf8str, std::wstring& wstr)
334{
335 wstr.clear();
336 try
337 {
338 utf8::utf8to16(utf8str.begin(), utf8str.end(), std::back_inserter(wstr));
339 }
340 catch (std::exception const&)
341 {
342 wstr.clear();
343 return false;
344 }
345 return true;
346}
347
348bool WStrToUtf8(wchar_t* wstr, size_t size, std::string& utf8str)
349{
350 try
351 {
352 std::string utf8str2;
353 utf8str2.resize(size * 4); // allocate for most long case
354
355 if (size)
356 {
357 char* oend = utf8::utf16to8(wstr, wstr + size, &utf8str2[0]);
358 utf8str2.resize(oend - (&utf8str2[0])); // remove unused tail
359 }
360 utf8str = utf8str2;
361 }
362 catch (std::exception const&)
363 {
364 utf8str.clear();
365 return false;
366 }
367
368 return true;
369}
370
371bool WStrToUtf8(const std::wstring& wstr, std::string& utf8str)
372{
373 try
374 {
375 std::string utf8str2;
376 utf8str2.resize(wstr.size() * 4); // allocate for most long case
377
378 if (!wstr.empty())
379 {
380 char* oend = utf8::utf16to8(wstr.begin(), wstr.end(), &utf8str2[0]);
381 utf8str2.resize(oend - (&utf8str2[0])); // remove unused tail
382 }
383 utf8str = utf8str2;
384 }
385 catch (std::exception const&)
386 {
387 utf8str.clear();
388 return false;
389 }
390
391 return true;
392}
393
394typedef wchar_t const* const* wstrlist;
395
396std::wstring GetMainPartOfName(std::wstring wname, uint32 declension)
397{
398 // supported only Cyrillic cases
399 if (wname.size() < 1 || !isCyrillicCharacter(wname[0]) || declension > 5)
400 return wname;
401
402 // Important: end length must be <= MAX_INTERNAL_PLAYER_NAME-MAX_PLAYER_NAME (3 currently)
403
404 static wchar_t const a_End[] = { wchar_t(1), wchar_t(0x0430), wchar_t(0x0000) };
405 static wchar_t const o_End[] = { wchar_t(1), wchar_t(0x043E), wchar_t(0x0000) };
406 static wchar_t const ya_End[] = { wchar_t(1), wchar_t(0x044F), wchar_t(0x0000) };
407 static wchar_t const ie_End[] = { wchar_t(1), wchar_t(0x0435), wchar_t(0x0000) };
408 static wchar_t const i_End[] = { wchar_t(1), wchar_t(0x0438), wchar_t(0x0000) };
409 static wchar_t const yeru_End[] = { wchar_t(1), wchar_t(0x044B), wchar_t(0x0000) };
410 static wchar_t const u_End[] = { wchar_t(1), wchar_t(0x0443), wchar_t(0x0000) };
411 static wchar_t const yu_End[] = { wchar_t(1), wchar_t(0x044E), wchar_t(0x0000) };
412 static wchar_t const oj_End[] = { wchar_t(2), wchar_t(0x043E), wchar_t(0x0439), wchar_t(0x0000) };
413 static wchar_t const ie_j_End[] = { wchar_t(2), wchar_t(0x0435), wchar_t(0x0439), wchar_t(0x0000) };
414 static wchar_t const io_j_End[] = { wchar_t(2), wchar_t(0x0451), wchar_t(0x0439), wchar_t(0x0000) };
415 static wchar_t const o_m_End[] = { wchar_t(2), wchar_t(0x043E), wchar_t(0x043C), wchar_t(0x0000) };
416 static wchar_t const io_m_End[] = { wchar_t(2), wchar_t(0x0451), wchar_t(0x043C), wchar_t(0x0000) };
417 static wchar_t const ie_m_End[] = { wchar_t(2), wchar_t(0x0435), wchar_t(0x043C), wchar_t(0x0000) };
418 static wchar_t const soft_End[] = { wchar_t(1), wchar_t(0x044C), wchar_t(0x0000) };
419 static wchar_t const j_End[] = { wchar_t(1), wchar_t(0x0439), wchar_t(0x0000) };
420
421 static wchar_t const* const dropEnds[6][8] = {
422 { &a_End[1], &o_End[1], &ya_End[1], &ie_End[1], &soft_End[1], &j_End[1], NULL, NULL },
423 { &a_End[1], &ya_End[1], &yeru_End[1], &i_End[1], NULL, NULL, NULL, NULL },
424 { &ie_End[1], &u_End[1], &yu_End[1], &i_End[1], NULL, NULL, NULL, NULL },
425 { &u_End[1], &yu_End[1], &o_End[1], &ie_End[1], &soft_End[1], &ya_End[1], &a_End[1], NULL },
426 { &oj_End[1], &io_j_End[1], &ie_j_End[1], &o_m_End[1], &io_m_End[1], &ie_m_End[1], &yu_End[1], NULL },
427 { &ie_End[1], &i_End[1], NULL, NULL, NULL, NULL, NULL, NULL }
428 };
429
430 for (wchar_t const* const* itr = &dropEnds[declension][0]; *itr; ++itr)
431 {
432 size_t len = size_t((*itr)[-1]); // get length from string size field
433
434 if (wname.substr(wname.size() - len, len) == *itr)
435 return wname.substr(0, wname.size() - len);
436 }
437
438 return wname;
439}
440
441bool utf8ToConsole(const std::string& utf8str, std::string& conStr)
442{
443#if PLATFORM == PLATFORM_WINDOWS
444 std::wstring wstr;
445 if (!Utf8toWStr(utf8str, wstr))
446 return false;
447
448 conStr.resize(wstr.size());
449 CharToOemBuffW(&wstr[0], &conStr[0], wstr.size());
450#else
451 // not implemented yet
452 conStr = utf8str;
453#endif
454
455 return true;
456}
457
458bool consoleToUtf8(const std::string& conStr, std::string& utf8str)
459{
460#if PLATFORM == PLATFORM_WINDOWS
461 std::wstring wstr;
462 wstr.resize(conStr.size());
463 OemToCharBuffW(&conStr[0], &wstr[0], conStr.size());
464
465 return WStrToUtf8(wstr, utf8str);
466#else
467 // not implemented yet
468 utf8str = conStr;
469 return true;
470#endif
471}
472
473bool Utf8FitTo(const std::string& str, const std::wstring& search)
474{
475 std::wstring temp;
476
477 if (!Utf8toWStr(str, temp))
478 return false;
479
480 // converting to lower case
481 wstrToLower(temp);
482
483 if (temp.find(search) == std::wstring::npos)
484 return false;
485
486 return true;
487}
488
489void utf8printf(FILE* out, const char* str, ...)
490{
491 va_list ap;
492 va_start(ap, str);
493 vutf8printf(out, str, &ap);
494 va_end(ap);
495}
496
497void vutf8printf(FILE* out, const char* str, va_list* ap)
498{
499#if PLATFORM == PLATFORM_WINDOWS
500 char temp_buf[4 * 1024];
501 wchar_t wtemp_buf[4 * 1024];
502
503 size_t temp_len = vsnprintf(temp_buf, 4 * 1024, str, *ap);
504
505 size_t wtemp_len = 4 * 1024 - 1;
506 Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len);
507
508 CharToOemBuffW(&wtemp_buf[0], &temp_buf[0], wtemp_len + 1);
509 fprintf(out, "%s", temp_buf);
510#else
511 vfprintf(out, str, *ap);
512#endif
513}
514
515std::string SkyFire::Impl::ByteArrayToHexStr(uint8 const* bytes, size_t arrayLen, bool reverse /* = false */)
516{
517 int32 init = 0;
518 int32 end = arrayLen;
519 int8 op = 1;
520
521 if (reverse)
522 {
523 init = arrayLen - 1;
524 end = -1;
525 op = -1;
526 }
527
528 std::ostringstream ss;
529 for (int32 i = init; i != end; i += op)
530 {
531 char buffer[4];
532 sprintf(buffer, "%02X", bytes[i]);
533 ss << buffer;
534 }
535
536 return ss.str();
537}
538
539void SkyFire::Impl::HexStrToByteArray(std::string const& str, uint8* out, size_t outlen, bool reverse /*= false*/)
540{
541 ASSERT(str.size() == (2 * outlen));
542
543 int32 init = 0;
544 int32 end = int32(str.length());
545 int8 op = 1;
546
547 if (reverse)
548 {
549 init = int32(str.length() - 2);
550 end = -2;
551 op = -1;
552 }
553
554 uint32 j = 0;
555 for (int32 i = init; i != end; i += 2 * op)
556 {
557 char buffer[3] = { str[i], str[i + 1], '\0' };
558 out[j++] = uint8(strtoul(buffer, nullptr, 16));
559 }
560}
#define vsnprintf
Definition Common.h:100
@ MINUTE
Definition Common.h:119
@ HOUR
Definition Common.h:120
@ DAY
Definition Common.h:121
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::int8_t int8
Definition Define.h:75
std::uint64_t uint64
Definition Define.h:76
std::int64_t int64
Definition Define.h:72
#define ASSERT
Definition Errors.h:29
float frand(float min, float max)
Definition Util.cpp:39
wchar_t const *const * wstrlist
Definition Util.cpp:394
int32 rand32()
Definition Util.cpp:45
int64 MoneyStringToMoney(const std::string &moneyString)
Definition Util.cpp:150
bool IsIPAddrInNetwork(Skyfire::Net::Address const &net, Skyfire::Net::Address const &addr, Skyfire::Net::Address const &subnetMask)
Checks if address belongs to the a network with specified submask.
Definition Util.cpp:244
void stripLineInvisibleChars(std::string &str)
Definition Util.cpp:94
bool WStrToUtf8(wchar_t *wstr, size_t size, std::string &utf8str)
Definition Util.cpp:348
bool consoleToUtf8(const std::string &conStr, std::string &utf8str)
Definition Util.cpp:458
bool IsIPAddress(char const *ipaddress)
Check if the string is a valid ip address representation.
Definition Util.cpp:229
double rand_norm(void)
Definition Util.cpp:50
uint32 TimeStringToSecs(const std::string &timestring)
Definition Util.cpp:181
std::string TimeToTimestampStr(time_t t)
Definition Util.cpp:213
void utf8printf(FILE *out, const char *str,...)
Definition Util.cpp:489
bool utf8ToConsole(const std::string &utf8str, std::string &conStr)
Definition Util.cpp:441
static CRandomSFMT & SfmtRand()
Definition Util.cpp:33
bool Utf8FitTo(const std::string &str, const std::wstring &search)
Definition Util.cpp:473
uint32 CreatePIDFile(const std::string &filename)
create PID file
Definition Util.cpp:253
std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly)
Definition Util.cpp:127
bool Utf8toWStr(char const *utf8str, size_t csize, wchar_t *wstr, size_t &wsize)
Definition Util.cpp:305
size_t utf8length(std::string &utf8str)
Definition Util.cpp:271
void utf8truncate(std::string &utf8str, size_t len)
Definition Util.cpp:284
double rand_chance(void)
Definition Util.cpp:55
std::string GetAddressString(Skyfire::Net::Address const &addr)
Transforms network address into string format "dotted_ip:port".
Definition Util.cpp:237
std::wstring GetMainPartOfName(std::wstring wname, uint32 declension)
Definition Util.cpp:396
void vutf8printf(FILE *out, const char *str, va_list *ap)
Definition Util.cpp:497
void wstrToLower(std::wstring &str)
Definition Util.h:314
bool isCyrillicCharacter(wchar_t wchar)
Definition Util.h:172
uint32 ToIPv4NetworkOrder() const
uint16 GetPort() const
std::string const & GetHost() const
StorageType m_storage
Definition Util.h:53
char * m_str
Definition Util.h:52
StorageType::const_iterator const_iterator
Definition Util.h:35
Tokenizer(const std::string &src, char const sep, uint32 vectorReserve=0)
Definition Util.cpp:60
const_iterator end() const
Definition Util.h:44
const_iterator begin() const
Definition Util.h:43
std::string ByteArrayToHexStr(uint8 const *bytes, size_t length, bool reverse=false)
Definition Util.cpp:515
void HexStrToByteArray(std::string const &str, uint8 *out, size_t outlen, bool reverse=false)
Definition Util.cpp:539
bool IsIPv4Address(std::string const &host)
bool LocalTime(time_t const &time, tm &result)
Definition TimeUtils.h:57