529 lines
13 KiB
C++
529 lines
13 KiB
C++
#include "types.h"
|
|
|
|
#include <memory.h>
|
|
|
|
#include <cstring>
|
|
#include <iomanip>
|
|
#include <ostream>
|
|
#include <regex>
|
|
#include <sstream>
|
|
|
|
#ifndef _WIN32
|
|
#include <arpa/inet.h>
|
|
#include <netinet/in.h>
|
|
#include <stdlib.h>
|
|
#include <sys/socket.h>
|
|
#endif
|
|
|
|
#include <algorithm>
|
|
#include <random>
|
|
|
|
#include "fs/directory.h"
|
|
|
|
namespace
|
|
{
|
|
const std::regex& invalidChars()
|
|
{
|
|
static const std::regex invalid(
|
|
#ifndef _WIN32
|
|
// / and ASCII 0 to 31
|
|
"[/\\x00-\\x1F]"
|
|
#else
|
|
// <>:"/|?\*, ASCII 0 to 31 and all reserved names such as CON or LPT1
|
|
// see here: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
|
|
"[:<>\"/|?\\*\\x00-\\x1F]|^CON$|^PRN$|^AUX$|^NUL$|^COM\\d$|^LPT\\d$"
|
|
#endif
|
|
,
|
|
std::regex_constants::ECMAScript | std::regex_constants::optimize);
|
|
return invalid;
|
|
}
|
|
} // namespace
|
|
|
|
using namespace std;
|
|
|
|
uint64_t my_ntohll(const uint64_t& original)
|
|
{
|
|
#ifdef SPARC_V9 // big endian
|
|
return original;
|
|
#else // little endian
|
|
return (((uint64_t)my_ntohl((uint32_t)original)) << 32) | ((uint64_t)my_ntohl((uint32_t)(original >> 32)));
|
|
#endif
|
|
}
|
|
|
|
uint64_t my_htonll(const uint64_t& original)
|
|
{
|
|
#ifdef SPARC_V9 // big endian
|
|
return original;
|
|
#else // little endian
|
|
return (((uint64_t)my_ntohl((uint32_t)original)) << 32) | ((uint64_t)my_ntohl((uint32_t)(original >> 32)));
|
|
#endif
|
|
}
|
|
|
|
// Simple types conversion
|
|
int64_t strToInt64(const char* const str)
|
|
{
|
|
#ifdef _WIN32
|
|
return _atoi64(str);
|
|
#else
|
|
return strtoll(str, 0, 10);
|
|
#endif
|
|
}
|
|
|
|
uint64_t strToInt64u(const char* const str)
|
|
{
|
|
#ifdef _WIN32
|
|
return _atoi64(str);
|
|
#else
|
|
return strtoull(str, 0, 10);
|
|
#endif
|
|
}
|
|
|
|
int32_t strToInt32(const char* const str) { return strtol(str, 0, 10); }
|
|
|
|
int32_t strToInt32(const std::string& str) { return strToInt32(str.c_str()); }
|
|
|
|
int32_t strToInt32(const char* const str, int radix) { return strtol(str, 0, radix); }
|
|
|
|
uint32_t strToInt32u(const char* const str, int radix) { return static_cast<uint32_t>(strtoul(str, 0, radix)); }
|
|
|
|
int16_t strToInt16(const char* const str) { return (int16_t)strtol(str, 0, 10); }
|
|
|
|
uint16_t strToInt16u(const char* const str) { return (uint16_t)strtol(str, 0, 10); }
|
|
|
|
int8_t strToInt8(const char* const str) { return (int8_t)strtol(str, 0, 10); }
|
|
|
|
uint8_t strToInt8u(const char* const str) { return (uint8_t)strtol(str, 0, 10); }
|
|
|
|
double strToDouble(const char* const str) { return strtod(str, 0); }
|
|
|
|
float strToFloat(const char* const str) { return strtof(str, 0); }
|
|
|
|
bool strToBool(const char* const str)
|
|
{
|
|
if (!strcmp(str, "true"))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
string int64ToStr(const int64_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int64uToStr(const uint64_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int32ToStr(const int32_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int32ToHex(const int32_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << std::hex << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int32uToStr(const uint32_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int32uToHex(const uint32_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << std::hex << x;
|
|
return str.str();
|
|
}
|
|
|
|
string doubleToStr(const double& x, int precision)
|
|
{
|
|
std::ostringstream str;
|
|
if (precision > 0)
|
|
str << fixed << std::setprecision(precision);
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int16ToStr(const int16_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int16uToStr(const uint16_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int8ToStr(const int8_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string int8uToStr(const uint8_t& x)
|
|
{
|
|
std::ostringstream str;
|
|
str << x;
|
|
return str.str();
|
|
}
|
|
|
|
string boolToStr(const bool& x) { return x ? "true" : "false"; }
|
|
|
|
uint32_t roundDown(const uint32_t& value, const uint32_t& roundVal)
|
|
{
|
|
return roundVal ? (value / roundVal) * roundVal : 0;
|
|
}
|
|
|
|
uint32_t roundUp(const uint32_t& value, const uint32_t& roundVal)
|
|
{
|
|
return roundVal ? ((value + roundVal - 1) / roundVal) * roundVal : 0;
|
|
}
|
|
|
|
uint64_t roundDown64(const uint64_t& value, const uint64_t& roundVal)
|
|
{
|
|
return roundVal ? (value / roundVal) * roundVal : 0;
|
|
}
|
|
|
|
uint64_t roundUp64(const uint64_t& value, const uint64_t& roundVal)
|
|
{
|
|
return roundVal ? ((value + roundVal - 1) / roundVal) * roundVal : 0;
|
|
}
|
|
|
|
string strPadLeft(const string& str, size_t newSize, char filler)
|
|
{
|
|
size_t cnt = newSize - str.size();
|
|
string prefix = "";
|
|
for (int i = 0; i < cnt; i++) prefix += filler;
|
|
return prefix + str;
|
|
}
|
|
|
|
string strPadRight(const string& str, size_t newSize, char filler)
|
|
{
|
|
size_t cnt = newSize - str.size();
|
|
string postfix = "";
|
|
for (int i = 0; i < cnt; i++) postfix += filler;
|
|
return str + postfix;
|
|
}
|
|
|
|
bool strEndWith(const string& str, const string& substr)
|
|
{
|
|
if (str.size() == 0)
|
|
return false;
|
|
size_t idx = str.size();
|
|
for (size_t i = substr.size(); i-- > 0;)
|
|
if (substr[i] != str[--idx])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool strStartWith(const string& str, const string& substr)
|
|
{
|
|
if (str.size() < substr.size())
|
|
return false;
|
|
for (size_t i = 0; i < substr.size(); i++)
|
|
if (substr[i] != str[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
vector<string> splitStr(const char* str, char splitter)
|
|
{
|
|
vector<string> rez;
|
|
const char* prevPos = str;
|
|
const char* buf = str;
|
|
for (; *buf; buf++)
|
|
{
|
|
if (*buf == splitter)
|
|
{
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
prevPos = buf + 1;
|
|
}
|
|
}
|
|
if (buf > prevPos)
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
return rez;
|
|
}
|
|
|
|
vector<string> splitStr(const string& str, const string& splitter)
|
|
{
|
|
vector<string> res;
|
|
|
|
size_t splitterSize = splitter.size();
|
|
size_t posBegin = 0;
|
|
size_t posEnd = string::npos;
|
|
|
|
if (splitterSize > 0 && !str.empty())
|
|
{
|
|
while ((posEnd = str.find(splitter, posBegin)) != string::npos)
|
|
{
|
|
res.push_back(str.substr(posBegin, posEnd - posBegin));
|
|
posBegin = posEnd + splitterSize;
|
|
}
|
|
|
|
// if ( res.size() == 0 )
|
|
res.push_back(str.substr(posBegin, str.size()));
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void splitStr(vector<string>& rez, const char* str, char splitter)
|
|
{
|
|
rez.clear();
|
|
const char* prevPos = str;
|
|
const char* buf = str;
|
|
for (; *buf; buf++)
|
|
{
|
|
if (*buf == splitter)
|
|
{
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
prevPos = buf + 1;
|
|
}
|
|
}
|
|
if (buf > prevPos)
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
}
|
|
|
|
string extractFileExt(const string& src)
|
|
{
|
|
for (size_t i = src.size() - 1; i > 0; i--)
|
|
if (src[i] == '.')
|
|
{
|
|
string rez = src.substr(i + 1);
|
|
if (rez.size() > 0 && rez[rez.size() - 1] == '\"')
|
|
return rez.substr(0, rez.size() - 1);
|
|
else
|
|
return rez;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
string extractFileName(const string& src)
|
|
{
|
|
size_t endPos = src.size();
|
|
for (size_t i = src.size(); i-- > 0;)
|
|
if (src[i] == '.')
|
|
{
|
|
if (endPos == src.size())
|
|
endPos = i;
|
|
}
|
|
else if (src[i] == '/' || src[i] == '\\')
|
|
{
|
|
string rez = src.substr(i + 1, endPos - i - 1);
|
|
if (rez.size() > 0 && rez[rez.size() - 1] == '\"')
|
|
return rez.substr(0, rez.size() - 1);
|
|
else
|
|
return rez;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
string extractFileName2(const string& src, bool withExt)
|
|
{
|
|
string fileName = src;
|
|
|
|
size_t extSep = fileName.find_last_of('.');
|
|
size_t dirSep = fileName.find_last_of('/');
|
|
|
|
if (dirSep == string::npos)
|
|
dirSep = fileName.find_last_of('\\');
|
|
|
|
if (extSep != string::npos && !withExt)
|
|
fileName = fileName.substr(0, extSep);
|
|
|
|
if (dirSep != string::npos)
|
|
fileName = fileName.substr(dirSep + 1, fileName.size());
|
|
|
|
return fileName;
|
|
}
|
|
|
|
string extractFilePath(const string& src)
|
|
{
|
|
for (size_t i = src.size(); i-- > 0;)
|
|
if (src[i] == '/' || src[i] == '\\')
|
|
{
|
|
string rez = src.substr(0, i);
|
|
return rez;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
string closeDirPath(const string& src, char delimiter)
|
|
{
|
|
if (delimiter == ' ')
|
|
delimiter = getDirSeparator();
|
|
if (src.length() == 0)
|
|
return src;
|
|
if (src[src.length() - 1] == '/' || src[src.length() - 1] == '\\')
|
|
return src;
|
|
return src + delimiter;
|
|
}
|
|
|
|
// extract the filename from a path, check for invalid characters
|
|
bool isValidFileName(const string& src)
|
|
{
|
|
string filename = extractFileName(src);
|
|
|
|
// invalidChars() returns a different regex pattern for Windows or Unix
|
|
bool isvalid = !(std::regex_search(filename, invalidChars()));
|
|
return isvalid;
|
|
}
|
|
|
|
string trimStr(const string& value)
|
|
{
|
|
const char* bufStart = value.c_str();
|
|
const char* bufEnd = bufStart + value.length() - 1;
|
|
const char* chBeg = bufStart;
|
|
const char* chEnd = bufEnd;
|
|
for (; chBeg < bufEnd && (*chBeg == '\n' || *chBeg == '\r' || *chBeg == ' '); chBeg++)
|
|
;
|
|
for (; chEnd >= chBeg && (*chEnd == '\n' || *chEnd == '\r' || *chEnd == ' '); chEnd--)
|
|
;
|
|
return value.substr(chBeg - bufStart, chEnd - chBeg + 1);
|
|
}
|
|
|
|
vector<string> splitQuotedStr(const char* str, char splitter)
|
|
{
|
|
vector<string> rez;
|
|
const char* prevPos = str;
|
|
const char* buf = str;
|
|
bool quoted = false;
|
|
for (; *buf; buf++)
|
|
{
|
|
if (*buf == '"')
|
|
quoted = !quoted;
|
|
if (*buf == splitter && !quoted)
|
|
{
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
prevPos = buf + 1;
|
|
}
|
|
}
|
|
if (buf > prevPos)
|
|
rez.push_back(string(prevPos, buf - prevPos));
|
|
return rez;
|
|
}
|
|
|
|
string strToUpperCase(const string& src)
|
|
{
|
|
string res = src;
|
|
|
|
transform(res.begin(), res.end(), res.begin(), CaseChanger<string>(CaseType::ctUpper));
|
|
|
|
return res;
|
|
}
|
|
|
|
string strToLowerCase(const string& src)
|
|
{
|
|
string res = src;
|
|
|
|
transform(res.begin(), res.end(), res.begin(), CaseChanger<string>(CaseType::ctLower));
|
|
|
|
return res;
|
|
}
|
|
|
|
uint32_t my_ntohl(const uint32_t val)
|
|
{
|
|
uint8_t* tmp = (uint8_t*)&val;
|
|
return tmp[3] + (tmp[2] << 8) + (tmp[1] << 16) + (tmp[0] << 24);
|
|
}
|
|
|
|
uint16_t my_ntohs(const uint16_t val)
|
|
{
|
|
uint8_t* tmp = (uint8_t*)&val;
|
|
return tmp[1] + (tmp[0] << 8);
|
|
}
|
|
|
|
char* strnstr(const char* s1, const char* s2, size_t len)
|
|
{
|
|
size_t l1 = len, l2;
|
|
|
|
l2 = strlen(s2);
|
|
if (!l2)
|
|
return (char*)s1;
|
|
while (l1 >= l2)
|
|
{
|
|
l1--;
|
|
if (!memcmp(s1, s2, l2))
|
|
return (char*)s1;
|
|
s1++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t random32()
|
|
{
|
|
static std::random_device dev;
|
|
static std::minstd_rand raand(dev());
|
|
return static_cast<std::uint32_t>(raand());
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
namespace
|
|
{
|
|
std::vector<wchar_t> mbtwc_wrapper(int codePage, const char* inputStr, int inputSize, int outputSize)
|
|
{
|
|
std::vector<wchar_t> multiByteBuf(static_cast<std::size_t>(outputSize));
|
|
MultiByteToWideChar(codePage, 0, inputStr, inputSize, multiByteBuf.data(), outputSize);
|
|
if (multiByteBuf.empty() || multiByteBuf.back() != 0)
|
|
{
|
|
multiByteBuf.push_back(0);
|
|
}
|
|
return multiByteBuf;
|
|
}
|
|
} // namespace
|
|
|
|
std::vector<wchar_t> fromAcp(const char* acpStr, int sz)
|
|
{
|
|
auto requiredSiz = MultiByteToWideChar(CP_ACP, 0, acpStr, sz, nullptr, 0);
|
|
return mbtwc_wrapper(CP_ACP, acpStr, sz, requiredSiz);
|
|
}
|
|
|
|
std::vector<wchar_t> toWide(const std::string& utf8Str) { return toWide(utf8Str.c_str(), (int)utf8Str.size()); }
|
|
|
|
std::vector<wchar_t> toWide(const char* utf8Str, int sz)
|
|
{
|
|
auto requiredSiz = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8Str, sz, nullptr, 0);
|
|
if (requiredSiz != 0)
|
|
{
|
|
return mbtwc_wrapper(CP_UTF8, utf8Str, sz, static_cast<std::size_t>(requiredSiz));
|
|
}
|
|
else
|
|
{
|
|
/* utf8Str is not a valid UTF-8 string. try converting it according to the currently active code page in order
|
|
* to keep compatibility with meta files saved by older versions of the GUI which put the file name through
|
|
* QString::toLocal8Bit, which uses the ACP on Windows. */
|
|
return fromAcp(utf8Str, sz);
|
|
}
|
|
}
|
|
|
|
std::string toUtf8(const wchar_t* wideStr)
|
|
{
|
|
auto needed = WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, nullptr, 0, nullptr, nullptr);
|
|
needed--; // includes terminating null byte, needless when returning a std::string.
|
|
std::string s(static_cast<std::size_t>(needed), 0);
|
|
WideCharToMultiByte(CP_UTF8, 0, wideStr, -1, &s[0], needed, nullptr, nullptr);
|
|
return s;
|
|
}
|
|
#endif
|