3 #ifndef CPP_UTILITIES_NO_THREAD_LOCAL
4 #include "resources/features.h"
6 #define CPP_UTILITIES_THREAD_LOCAL
19 #ifdef PLATFORM_WINDOWS
30 size_t operator()(
size_t value)
36 size_t operator()(
size_t value)
42 size_t operator()(
size_t value)
50 size_t operator()(
size_t value)
52 return static_cast<size_t>(value * factor);
57 template <
class OutputSizeH
int>
class ConversionDescriptor {
59 ConversionDescriptor(
const char *fromCharset,
const char *toCharset)
60 : m_ptr(iconv_open(toCharset, fromCharset))
61 , m_outputSizeHint(OutputSizeHint())
63 if (m_ptr == reinterpret_cast<iconv_t>(-1)) {
64 throw ConversionException(
"Unable to allocate descriptor for character set conversion.");
68 ConversionDescriptor(
const char *fromCharset,
const char *toCharset, OutputSizeHint outputSizeHint)
69 : m_ptr(iconv_open(toCharset, fromCharset))
70 , m_outputSizeHint(outputSizeHint)
72 if (m_ptr == reinterpret_cast<iconv_t>(-1)) {
73 throw ConversionException(
"Unable to allocate descriptor for character set conversion.");
77 ~ConversionDescriptor()
86 size_t inputBytesLeft = inputBufferSize;
87 size_t outputSize = m_outputSizeHint(inputBufferSize);
88 size_t outputBytesLeft = outputSize;
89 char *outputBuffer = reinterpret_cast<char *>(malloc(outputSize));
92 char *currentOutputOffset = outputBuffer;
93 for (;; currentOutputOffset = outputBuffer + bytesWritten) {
94 bytesWritten = iconv(m_ptr, const_cast<char **>(&inputBuffer), &inputBytesLeft, ¤tOutputOffset, &outputBytesLeft);
95 if (bytesWritten == static_cast<size_t>(-1)) {
96 if (errno == EINVAL) {
98 bytesWritten = static_cast<size_t>(currentOutputOffset - outputBuffer);
100 }
else if (errno == E2BIG) {
102 bytesWritten = static_cast<size_t>(currentOutputOffset - outputBuffer);
103 outputBytesLeft = (outputSize += m_outputSizeHint(inputBytesLeft)) - bytesWritten;
104 outputBuffer = reinterpret_cast<char *>(realloc(outputBuffer, outputSize));
108 throw ConversionException(
"Invalid multibyte sequence in the input.");
115 return StringData(std::unique_ptr<
char[], StringDataDeleter>(outputBuffer), currentOutputOffset - outputBuffer);
120 OutputSizeHint m_outputSizeHint;
135 const char *fromCharset,
const char *toCharset,
const char *inputBuffer, std::size_t inputBufferSize,
float outputBufferSizeFactor)
137 return ConversionDescriptor<Factor>(fromCharset, toCharset, outputBufferSizeFactor).convertString(inputBuffer, inputBufferSize);
145 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Double> descriptor(
"UTF-8",
"UTF-16LE");
146 return descriptor.convertString(inputBuffer, inputBufferSize);
154 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Half> descriptor(
"UTF-16LE",
"UTF-8");
155 return descriptor.convertString(inputBuffer, inputBufferSize);
163 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Double> descriptor(
"UTF-8",
"UTF-16BE");
164 return descriptor.convertString(inputBuffer, inputBufferSize);
172 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Half> descriptor(
"UTF-16BE",
"UTF-8");
173 return descriptor.convertString(inputBuffer, inputBufferSize);
181 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Keep> descriptor(
"ISO-8859-1",
"UTF-8");
182 return descriptor.convertString(inputBuffer, inputBufferSize);
190 CPP_UTILITIES_THREAD_LOCAL ConversionDescriptor<Keep> descriptor(
"UTF-8",
"ISO-8859-1");
191 return descriptor.convertString(inputBuffer, inputBufferSize);
194 #ifdef PLATFORM_WINDOWS
201 WideStringData convertMultiByteToWide(
const char *inputBuffer,
int inputBufferSize)
204 WideStringData widePath;
205 widePath.second = MultiByteToWideChar(CP_UTF8, 0, inputBuffer, inputBufferSize,
nullptr, 0);
206 if (widePath.second <= 0) {
210 widePath.first = make_unique<wchar_t[]>(static_cast<size_t>(widePath.second));
211 widePath.second = MultiByteToWideChar(CP_UTF8, 0, inputBuffer, inputBufferSize, widePath.first.get(), widePath.second);
212 if (widePath.second <= 0) {
213 widePath.first.reset();
222 WideStringData convertMultiByteToWide(
const std::string &inputBuffer)
224 return convertMultiByteToWide(
225 inputBuffer.data(), inputBuffer.size() < (
numeric_limits<int>::max() - 1) ? static_cast<int>(inputBuffer.size() + 1) : -1);
235 string::size_type firstNullByte = str.find(terminationChar);
236 if (firstNullByte != string::npos) {
237 str.resize(firstNullByte);
248 stringstream res(stringstream::in | stringstream::out);
249 res.setf(ios::fixed, ios::floatfield);
250 res << setprecision(2);
251 if (sizeInByte < 1024LL) {
252 res << sizeInByte <<
" bytes";
253 }
else if (sizeInByte < 1048576LL) {
254 res << (static_cast<double>(sizeInByte) / 1024.0) <<
" KiB";
255 }
else if (sizeInByte < 1073741824LL) {
256 res << (static_cast<double>(sizeInByte) / 1048576.0) <<
" MiB";
257 }
else if (sizeInByte < 1099511627776LL) {
258 res << (static_cast<double>(sizeInByte) / 1073741824.0) <<
" GiB";
260 res << (static_cast<double>(sizeInByte) / 1099511627776.0) <<
" TiB";
262 if (includeByte && sizeInByte > 1024LL) {
263 res <<
' ' <<
'(' << sizeInByte <<
" byte)";
280 stringstream res(stringstream::in | stringstream::out);
281 res << setprecision(3);
282 if (std::isnan(bitrateInKbitsPerSecond)) {
283 res <<
"indeterminable";
284 }
else if (useIecBinaryPrefixes) {
285 if (bitrateInKbitsPerSecond < 8.0) {
286 res << (bitrateInKbitsPerSecond * 125.0) <<
" byte/s";
287 }
else if (bitrateInKbitsPerSecond < 8000.0) {
288 res << (bitrateInKbitsPerSecond * 0.125) <<
" KiB/s";
289 }
else if (bitrateInKbitsPerSecond < 8000000.0) {
290 res << (bitrateInKbitsPerSecond * 0.000125) <<
" MiB/s";
292 res << (bitrateInKbitsPerSecond * 0.000000125) <<
" GiB/s";
295 if (bitrateInKbitsPerSecond < 1.0) {
296 res << (bitrateInKbitsPerSecond * 1000.0) <<
" bit/s";
297 }
else if (bitrateInKbitsPerSecond < 1000.0) {
298 res << (bitrateInKbitsPerSecond) <<
" kbit/s";
299 }
else if (bitrateInKbitsPerSecond < 1000000.0) {
300 res << (bitrateInKbitsPerSecond * 0.001) <<
" Mbit/s";
302 res << (bitrateInKbitsPerSecond * 0.000001) <<
" Gbit/s";
309 const char *
const base64Chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
310 const char base64Pad =
'=';
320 std::uint8_t mod = dataSize % 3;
321 encoded.reserve(((dataSize / 3) + (mod > 0)) * 4);
323 for (
const std::uint8_t *end = --data + dataSize - mod; data != end;) {
324 temp = *++data << 16;
325 temp |= *++data << 8;
327 encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
328 encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
329 encoded.push_back(base64Chars[(temp & 0x00000FC0) >> 6]);
330 encoded.push_back(base64Chars[(temp & 0x0000003F)]);
334 temp = *++data << 16;
335 encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
336 encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
337 encoded.push_back(base64Pad);
338 encoded.push_back(base64Pad);
341 temp = *++data << 16;
342 temp |= *++data << 8;
343 encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
344 encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
345 encoded.push_back(base64Chars[(temp & 0x00000FC0) >> 6]);
346 encoded.push_back(base64Pad);
357 pair<unique_ptr<std::uint8_t[]>, std::uint32_t>
decodeBase64(
const char *encodedStr,
const std::uint32_t strSize)
362 std::uint32_t decodedSize = (strSize / 4) * 3;
363 const char *
const end = encodedStr + strSize;
365 if (*(end - 1) == base64Pad) {
368 if (*(end - 2) == base64Pad) {
372 auto buffer = make_unique<std::uint8_t[]>(decodedSize);
373 auto *iter = buffer.get() - 1;
374 while (encodedStr < end) {
375 std::int32_t temp = 0;
376 for (std::uint8_t quantumPos = 0; quantumPos < 4; ++quantumPos, ++encodedStr) {
378 if (*encodedStr >=
'A' && *encodedStr <=
'Z') {
379 temp |= *encodedStr -
'A';
380 }
else if (*encodedStr >=
'a' && *encodedStr <=
'z') {
381 temp |= *encodedStr -
'a' + 26;
382 }
else if (*encodedStr >=
'0' && *encodedStr <=
'9') {
383 temp |= *encodedStr -
'0' + 2 * 26;
384 }
else if (*encodedStr ==
'+') {
386 }
else if (*encodedStr ==
'/') {
387 temp |= 2 * 26 + 10 + 1;
388 }
else if (*encodedStr == base64Pad) {
389 switch (end - encodedStr) {
391 *++iter = (temp >> 16) & 0xFF;
392 *++iter = (temp >> 8) & 0xFF;
393 return make_pair(move(buffer), decodedSize);
395 *++iter = (temp >> 10) & 0xFF;
396 return make_pair(move(buffer), decodedSize);
404 *++iter = (temp >> 16) & 0xFF;
405 *++iter = (temp >> 8) & 0xFF;
406 *++iter = (temp)&0xFF;
408 return make_pair(move(buffer), decodedSize);