2017-01-16 11:42:50 -05:00
|
|
|
#include "STDInclude.hpp"
|
2017-01-27 08:43:52 -05:00
|
|
|
#ifdef ENABLE_BASE128
|
2017-01-16 11:42:50 -05:00
|
|
|
#include "base128.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Utils
|
|
|
|
{
|
|
|
|
namespace String
|
|
|
|
{
|
2017-01-06 09:27:35 -05:00
|
|
|
const char *VA(const char *fmt, ...)
|
|
|
|
{
|
2017-06-04 07:46:50 -04:00
|
|
|
static VAProvider<4, 100> globalProvider;
|
2017-06-02 16:05:32 -04:00
|
|
|
static thread_local VAProvider<8, 256> provider;
|
2017-01-06 09:27:35 -05:00
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2017-06-04 07:46:50 -04:00
|
|
|
|
|
|
|
const char* result;
|
2017-06-14 06:06:04 -04:00
|
|
|
if (Components::Loader::IsUninitializing()) result = globalProvider.get(fmt, ap);
|
2017-06-04 07:46:50 -04:00
|
|
|
else result = provider.get(fmt, ap);
|
|
|
|
|
2017-01-06 09:27:35 -05:00
|
|
|
va_end(ap);
|
2017-05-31 12:03:33 -04:00
|
|
|
return result;
|
2017-01-16 11:42:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string ToLower(std::string input)
|
|
|
|
{
|
|
|
|
std::transform(input.begin(), input.end(), input.begin(), ::tolower);
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string ToUpper(std::string input)
|
|
|
|
{
|
|
|
|
std::transform(input.begin(), input.end(), input.begin(), ::toupper);
|
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
2018-12-17 08:29:18 -05:00
|
|
|
std::string DumpHex(const std::string& data, const std::string& separator)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
std::string result;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < data.size(); ++i)
|
|
|
|
{
|
|
|
|
if (i > 0)
|
|
|
|
{
|
|
|
|
result.append(separator);
|
|
|
|
}
|
|
|
|
|
|
|
|
result.append(Utils::String::VA("%02X", data[i] & 0xFF));
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string XOR(std::string str, char value)
|
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < str.size(); ++i)
|
|
|
|
{
|
|
|
|
str[i] ^= value;
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> Explode(const std::string& str, char delim)
|
|
|
|
{
|
|
|
|
std::vector<std::string> result;
|
|
|
|
std::istringstream iss(str);
|
|
|
|
|
|
|
|
for (std::string token; std::getline(iss, token, delim);)
|
|
|
|
{
|
|
|
|
std::string _entry = std::move(token);
|
|
|
|
|
|
|
|
// Remove trailing 0x0 bytes
|
|
|
|
while (_entry.size() && !_entry.back())
|
|
|
|
{
|
|
|
|
_entry = _entry.substr(0, _entry.size() - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
result.push_back(_entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-12-17 08:29:18 -05:00
|
|
|
void Replace(std::string &string, const std::string& find, const std::string& replace)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
size_t nPos = 0;
|
|
|
|
|
|
|
|
while ((nPos = string.find(find, nPos)) != std::string::npos)
|
|
|
|
{
|
|
|
|
string = string.replace(nPos, find.length(), replace);
|
|
|
|
nPos += replace.length();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-17 08:29:18 -05:00
|
|
|
bool StartsWith(const std::string& haystack, const std::string& needle)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
2018-12-24 15:42:39 -05:00
|
|
|
return (haystack.size() >= needle.size() && haystack.substr(0, needle.size()) == needle);
|
2017-01-16 11:42:50 -05:00
|
|
|
}
|
|
|
|
|
2018-12-17 08:29:18 -05:00
|
|
|
bool EndsWith(const std::string& haystack, const std::string& needle)
|
2017-06-23 14:19:33 -04:00
|
|
|
{
|
2018-12-24 15:42:39 -05:00
|
|
|
return (haystack.size() >= needle.size() && haystack.substr(haystack.size() - needle.size()) == needle);
|
2017-06-23 14:19:33 -04:00
|
|
|
}
|
|
|
|
|
2017-01-16 11:42:50 -05:00
|
|
|
int IsSpace(int c)
|
|
|
|
{
|
|
|
|
if (c < -1) return 0;
|
|
|
|
return _isspace_l(c, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from start
|
|
|
|
std::string <rim(std::string &s)
|
|
|
|
{
|
2017-06-13 09:35:12 -04:00
|
|
|
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int val)
|
|
|
|
{
|
|
|
|
return !IsSpace(val);
|
|
|
|
}));
|
2017-01-16 11:42:50 -05:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from end
|
|
|
|
std::string &RTrim(std::string &s)
|
|
|
|
{
|
2017-06-13 09:35:12 -04:00
|
|
|
s.erase(std::find_if(s.rbegin(), s.rend(), [](int val)
|
|
|
|
{
|
|
|
|
return !IsSpace(val);
|
|
|
|
}).base(), s.end());
|
2017-01-16 11:42:50 -05:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
// trim from both ends
|
|
|
|
std::string &Trim(std::string &s)
|
|
|
|
{
|
|
|
|
return LTrim(RTrim(s));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FormatTimeSpan(int milliseconds)
|
|
|
|
{
|
|
|
|
int secondsTotal = milliseconds / 1000;
|
|
|
|
int seconds = secondsTotal % 60;
|
|
|
|
int minutesTotal = secondsTotal / 60;
|
|
|
|
int minutes = minutesTotal % 60;
|
|
|
|
int hoursTotal = minutesTotal / 60;
|
|
|
|
|
|
|
|
return Utils::String::VA("%02d:%02d:%02d", hoursTotal, minutes, seconds);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FormatBandwidth(size_t bytes, int milliseconds)
|
|
|
|
{
|
2020-12-09 14:13:34 -05:00
|
|
|
static const char* sizes[] =
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
"B",
|
|
|
|
"KB",
|
|
|
|
"MB",
|
|
|
|
"GB",
|
|
|
|
"TB"
|
|
|
|
};
|
|
|
|
|
2017-01-19 15:21:59 -05:00
|
|
|
if (!milliseconds) return "0.00 B/s";
|
|
|
|
|
2017-01-16 11:42:50 -05:00
|
|
|
double bytesPerSecond = (1000.0 / milliseconds) * bytes;
|
|
|
|
|
2017-01-20 16:41:03 -05:00
|
|
|
int i;
|
2017-01-27 08:43:52 -05:00
|
|
|
for (i = 0; bytesPerSecond > 1000 && i < ARRAYSIZE(sizes); ++i) // 1024 or 1000?
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
bytesPerSecond /= 1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Utils::String::VA("%.2f %s/s", static_cast<float>(bytesPerSecond), sizes[i]);
|
|
|
|
}
|
|
|
|
|
2017-01-27 08:43:52 -05:00
|
|
|
#ifdef ENABLE_BASE64
|
2017-01-16 11:42:50 -05:00
|
|
|
// Encodes a given string in Base64
|
2017-06-14 06:06:04 -04:00
|
|
|
std::string EncodeBase64(const char* input, const unsigned long inputSize)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
unsigned long outlen = long(inputSize + (inputSize / 3.0) + 16);
|
|
|
|
unsigned char* outbuf = new unsigned char[outlen]; //Reserve output memory
|
|
|
|
base64_encode(reinterpret_cast<unsigned char*>(const_cast<char*>(input)), inputSize, outbuf, &outlen);
|
2017-01-20 16:41:03 -05:00
|
|
|
std::string ret(reinterpret_cast<char*>(outbuf), outlen);
|
2017-01-16 11:42:50 -05:00
|
|
|
delete[] outbuf;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Encodes a given string in Base64
|
2017-06-14 06:06:04 -04:00
|
|
|
std::string EncodeBase64(const std::string& input)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
return EncodeBase64(input.data(), input.size());
|
|
|
|
}
|
2017-01-27 08:43:52 -05:00
|
|
|
#endif
|
2017-01-16 11:42:50 -05:00
|
|
|
|
2017-01-27 08:43:52 -05:00
|
|
|
#ifdef ENABLE_BASE128
|
2017-01-16 11:42:50 -05:00
|
|
|
// Encodes a given string in Base128
|
2017-06-14 06:06:04 -04:00
|
|
|
std::string EncodeBase128(const std::string& input)
|
2017-01-16 11:42:50 -05:00
|
|
|
{
|
|
|
|
base128 encoder;
|
|
|
|
|
|
|
|
void* inbuffer = const_cast<char*>(input.data());
|
|
|
|
char* buffer = encoder.encode(inbuffer, input.size());
|
|
|
|
/*
|
|
|
|
Interesting to see that the buffer returned by the encoder is not a standalone string copy
|
|
|
|
but instead is a pointer to the internal "encoded" field of the encoder. So if you deinitialize
|
|
|
|
the encoder that string will probably become garbage.
|
|
|
|
*/
|
|
|
|
std::string retval(buffer);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|