cpp-utilities/conversion/stringconversion.cpp

191 lines
6.6 KiB
C++
Raw Normal View History

2015-09-06 20:19:09 +02:00
#include "./stringconversion.h"
2015-04-22 18:36:40 +02:00
2015-09-06 20:19:09 +02:00
#include "../misc/memory.h"
2015-08-16 23:44:38 +02:00
2015-04-22 18:36:40 +02:00
#include <sstream>
#include <iomanip>
using namespace std;
namespace ConversionUtilities
{
/*!
* \brief Truncates all characters after the first occurrence of the
2016-01-18 23:41:30 +01:00
* specified \a terminationChar and the termination character as well.
2015-04-22 18:36:40 +02:00
*/
void truncateString(string &str, char terminationChar)
{
string::size_type firstNullByte = str.find(terminationChar);
if(firstNullByte != string::npos) {
str.resize(firstNullByte);
}
}
/*!
* \brief Converts the specified data size in byte to its equivalent std::string representation.
*
2015-07-18 01:11:12 +02:00
* The unit with appropriate binary prefix will be appended.
2015-04-22 18:36:40 +02:00
*/
string dataSizeToString(uint64 sizeInByte, bool includeByte)
2015-04-22 18:36:40 +02:00
{
stringstream res(stringstream::in | stringstream::out);
res.setf(ios::fixed, ios::floatfield);
res << setprecision(2);
if (sizeInByte < 1024LL) {
res << sizeInByte << " bytes";
} else if (sizeInByte < 1048576LL) {
2015-07-18 01:11:12 +02:00
res << (static_cast<double>(sizeInByte) / 1024.0) << " KiB";
2015-04-22 18:36:40 +02:00
} else if (sizeInByte < 1073741824LL) {
2015-07-18 01:11:12 +02:00
res << (static_cast<double>(sizeInByte) / 1048576.0) << " MiB";
2015-04-22 18:36:40 +02:00
} else if (sizeInByte < 1099511627776LL) {
2015-07-18 01:11:12 +02:00
res << (static_cast<double>(sizeInByte) / 1073741824.0) << " GiB";
2015-04-22 18:36:40 +02:00
} else {
2015-07-18 01:11:12 +02:00
res << (static_cast<double>(sizeInByte) / 1099511627776.0) << " TiB";
2015-04-22 18:36:40 +02:00
}
if(includeByte && sizeInByte > 1024LL) {
res << ' ' << '(' << sizeInByte << " byte)";
}
2015-04-22 18:36:40 +02:00
return res.str();
}
/*!
* \brief Converts the specified bitrate in kbit/s to its equivalent std::string representation.
*
2015-07-18 01:11:12 +02:00
* The unit with appropriate binary prefix will be appended.
2015-04-22 18:36:40 +02:00
*
2015-07-18 01:11:12 +02:00
* \param bitrateInKbitsPerSecond Specifies the bitrate in kbit/s.
* \param useIecBinaryPrefixes Indicates whether IEC binary prefixes should be used (eg. KiB/s).
2015-04-22 18:36:40 +02:00
*
* \sa <a href="http://en.wikipedia.org/wiki/Binary_prefix">Binary prefix - Wikipedia</a>
*/
string bitrateToString(double bitrateInKbitsPerSecond, bool useIecBinaryPrefixes)
{
stringstream res(stringstream::in | stringstream::out);
res << setprecision(3);
if (useIecBinaryPrefixes) {
if (bitrateInKbitsPerSecond < 8.0) {
res << (bitrateInKbitsPerSecond * 125.0) << " byte/s";
} else if (bitrateInKbitsPerSecond < 8000.0) {
res << (bitrateInKbitsPerSecond * 0.125) << " KiB/s";
} else if (bitrateInKbitsPerSecond < 8000000.0) {
res << (bitrateInKbitsPerSecond * 0.000125) << " MiB/s";
} else {
res << (bitrateInKbitsPerSecond * 0.000000125) << " GiB/s";
}
} else {
if (bitrateInKbitsPerSecond < 1.0) {
res << (bitrateInKbitsPerSecond * 1000.0) << " bit/s";
} else if (bitrateInKbitsPerSecond < 1000.0) {
res << (bitrateInKbitsPerSecond) << " kbit/s";
} else if (bitrateInKbitsPerSecond < 1000000.0) {
res << (bitrateInKbitsPerSecond * 0.001) << " Mbit/s";
} else {
res << (bitrateInKbitsPerSecond * 0.000001) << " Gbit/s";
}
}
return res.str();
}
2015-08-16 23:44:38 +02:00
const char *const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2015-07-18 01:11:12 +02:00
const char base64Pad = '=';
2015-04-22 18:36:40 +02:00
/*!
2015-08-16 23:44:38 +02:00
* \brief Encodes the specified \a data to Base64.
2015-04-22 18:36:40 +02:00
*/
2015-08-16 23:44:38 +02:00
LIB_EXPORT string encodeBase64(const byte *data, uint32 dataSize)
2015-04-22 18:36:40 +02:00
{
string encoded;
2015-08-16 23:44:38 +02:00
byte mod = dataSize % 3;
encoded.reserve(((dataSize / 3) + (mod > 0)) * 4);
2015-04-22 18:36:40 +02:00
uint32 temp;
2015-08-16 23:44:38 +02:00
for(const byte *end = --data + dataSize - mod; data != end; ) {
temp = *++data << 16;
temp |= *++data << 8;
temp |= *++data;
encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
encoded.push_back(base64Chars[(temp & 0x00000FC0) >> 6 ]);
encoded.push_back(base64Chars[(temp & 0x0000003F) ]);
2015-04-22 18:36:40 +02:00
}
2015-08-16 23:44:38 +02:00
switch(mod) {
2015-04-22 18:36:40 +02:00
case 1:
2015-08-16 23:44:38 +02:00
temp = *++data << 16;
encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
encoded.push_back(base64Pad);
encoded.push_back(base64Pad);
2015-04-22 18:36:40 +02:00
break;
case 2:
2015-08-16 23:44:38 +02:00
temp = *++data << 16;
temp |= *++data << 8;
encoded.push_back(base64Chars[(temp & 0x00FC0000) >> 18]);
encoded.push_back(base64Chars[(temp & 0x0003F000) >> 12]);
encoded.push_back(base64Chars[(temp & 0x00000FC0) >> 6 ]);
encoded.push_back(base64Pad);
2015-04-22 18:36:40 +02:00
break;
}
return encoded;
}
/*!
2015-08-16 23:44:38 +02:00
* \brief Decodes the specified Base64 encoded string.
* \throw Throws a ConversionException if the specified string is no valid Base64.
2015-04-22 18:36:40 +02:00
*/
2015-08-16 23:44:38 +02:00
LIB_EXPORT pair<unique_ptr<byte[]>, uint32> decodeBase64(const char *encodedStr, const uint32 strSize)
2015-04-22 18:36:40 +02:00
{
2015-08-16 23:44:38 +02:00
if(strSize % 4) {
throw ConversionException("invalid size of base64");
2015-04-22 18:36:40 +02:00
}
2015-08-16 23:44:38 +02:00
uint32 decodedSize = (strSize / 4) * 3;
const char *const end = encodedStr + strSize;
if(strSize) {
if(*(end - 1) == base64Pad) {
--decodedSize;
}
if(*(end - 2) == base64Pad) {
--decodedSize;
}
2015-04-22 18:36:40 +02:00
}
2015-08-16 23:44:38 +02:00
auto buffer = make_unique<byte[]>(decodedSize);
auto *iter = buffer.get() - 1;
while(encodedStr < end) {
uint32 temp = 0;
for(byte quantumPos = 0; quantumPos < 4; ++quantumPos, ++encodedStr) {
2015-04-22 18:36:40 +02:00
temp <<= 6;
2015-08-16 23:44:38 +02:00
if(*encodedStr >= 'A' && *encodedStr <= 'Z') {
temp |= *encodedStr - 'A';
} else if(*encodedStr >= 'a' && *encodedStr <= 'z') {
temp |= *encodedStr - 'a' + 26;
} else if(*encodedStr >= '0' && *encodedStr <= '9') {
temp |= *encodedStr - '0' + 2 * 26;
} else if(*encodedStr == '+') {
temp |= 2 * 26 + 10;
} else if(*encodedStr == '/') {
temp |= 2 * 26 + 10 + 1;
} else if(*encodedStr == base64Pad) {
switch(end - encodedStr) {
2015-04-22 18:36:40 +02:00
case 1:
2015-08-16 23:44:38 +02:00
*++iter = (temp >> 16) & 0xFF;
*++iter = (temp >> 8) & 0xFF;
return make_pair(move(buffer), decodedSize);
2015-04-22 18:36:40 +02:00
case 2:
2015-08-16 23:44:38 +02:00
*++iter = (temp >> 10) & 0xFF;
return make_pair(move(buffer), decodedSize);
2015-04-22 18:36:40 +02:00
default:
2015-08-16 23:44:38 +02:00
throw ConversionException("invalid padding in base64");
2015-04-22 18:36:40 +02:00
}
} else {
2015-08-16 23:44:38 +02:00
throw ConversionException("invalid character in base64");
2015-04-22 18:36:40 +02:00
}
}
2015-08-16 23:44:38 +02:00
*++iter = (temp >> 16) & 0xFF;
*++iter = (temp >> 8) & 0xFF;
*++iter = (temp ) & 0xFF;
2015-04-22 18:36:40 +02:00
}
2015-08-16 23:44:38 +02:00
return make_pair(move(buffer), decodedSize);
2015-04-22 18:36:40 +02:00
}
}