improved encode-/decodeBase64
This commit is contained in:
parent
6f5546200c
commit
8e27b97d47
|
@ -1,5 +1,7 @@
|
|||
#include "stringconversion.h"
|
||||
|
||||
#include "../misc/memory.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
|
@ -85,101 +87,103 @@ string bitrateToString(double bitrateInKbitsPerSecond, bool useIecBinaryPrefixes
|
|||
return res.str();
|
||||
}
|
||||
|
||||
const char *base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const char *const base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const char base64Pad = '=';
|
||||
|
||||
/*!
|
||||
* \brief Encodes the specified data to a base64 string.
|
||||
* \brief Encodes the specified \a data to Base64.
|
||||
*/
|
||||
LIB_EXPORT string encodeBase64(const vector<char> &bytes)
|
||||
LIB_EXPORT string encodeBase64(const byte *data, uint32 dataSize)
|
||||
{
|
||||
string encoded;
|
||||
encoded.reserve(((bytes.size() / 3) + (bytes.size() % 3 > 0)) * 4);
|
||||
byte mod = dataSize % 3;
|
||||
encoded.reserve(((dataSize / 3) + (mod > 0)) * 4);
|
||||
uint32 temp;
|
||||
auto iterator = bytes.cbegin();
|
||||
for(uint32 index = 0, maxIndex = bytes.size() / 3; index < maxIndex; ++iterator, ++index) {
|
||||
temp = (*iterator) << 16;
|
||||
temp += (*++iterator) << 8;
|
||||
temp += (*++iterator);
|
||||
encoded.append(1, base64Chars[(temp & 0x00FC0000) >> 18]);
|
||||
encoded.append(1, base64Chars[(temp & 0x0003F000) >> 12]);
|
||||
encoded.append(1, base64Chars[(temp & 0x00000FC0) >> 6 ]);
|
||||
encoded.append(1, base64Chars[(temp & 0x0000003F) ]);
|
||||
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) ]);
|
||||
}
|
||||
switch(bytes.size() % 3) {
|
||||
switch(mod) {
|
||||
case 1:
|
||||
temp = (*++iterator) << 16;
|
||||
encoded.append(1, base64Chars[(temp & 0x00FC0000) >> 18]);
|
||||
encoded.append(1, base64Chars[(temp & 0x0003F000) >> 12]);
|
||||
encoded.append(2, base64Pad);
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
temp = (*++iterator) << 16;
|
||||
temp += (*++iterator) << 8;
|
||||
encoded.append(1, base64Chars[(temp & 0x00FC0000) >> 18]);
|
||||
encoded.append(1, base64Chars[(temp & 0x0003F000) >> 12]);
|
||||
encoded.append(1, base64Chars[(temp & 0x00000FC0) >> 6 ]);
|
||||
encoded.append(1, base64Pad);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Decodes the specified base64 encoded string.
|
||||
* \throw Throws a std::runtime_error if the specified string is no valid base64.
|
||||
* \brief Decodes the specified Base64 encoded string.
|
||||
* \throw Throws a ConversionException if the specified string is no valid Base64.
|
||||
*/
|
||||
LIB_EXPORT vector<char> decodeBase64(const string &encoded)
|
||||
LIB_EXPORT pair<unique_ptr<byte[]>, uint32> decodeBase64(const char *encodedStr, const uint32 strSize)
|
||||
{
|
||||
string::size_type len = encoded.length();
|
||||
if(len % 4) {
|
||||
throw runtime_error("invalid size of base64");
|
||||
if(strSize % 4) {
|
||||
throw ConversionException("invalid size of base64");
|
||||
}
|
||||
string::size_type pad = 0;
|
||||
if(len >= 1 && encoded[len - 1] == base64Pad) {
|
||||
++pad;
|
||||
uint32 decodedSize = (strSize / 4) * 3;
|
||||
const char *const end = encodedStr + strSize;
|
||||
if(strSize) {
|
||||
if(*(end - 1) == base64Pad) {
|
||||
--decodedSize;
|
||||
}
|
||||
if(*(end - 2) == base64Pad) {
|
||||
--decodedSize;
|
||||
}
|
||||
}
|
||||
if(len >= 2 && encoded[len - 2] == base64Pad) {
|
||||
++pad;
|
||||
}
|
||||
vector<char> decoded;
|
||||
decoded.reserve(((len / 4) * 3) - pad);
|
||||
uint32 temp = 0;
|
||||
auto iterator = encoded.cbegin(), end = encoded.cend();
|
||||
while(iterator < end) {
|
||||
for(uint32 quantumPos = 0; quantumPos < 4; ++quantumPos, ++iterator) {
|
||||
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) {
|
||||
temp <<= 6;
|
||||
if(*iterator >= 'A' && *iterator <= 'Z') {
|
||||
temp |= *iterator - 'A';
|
||||
} else if(*iterator >= 'a' && *iterator <= 'z') {
|
||||
temp |= *iterator - 'a';
|
||||
} else if(*iterator >= '0' && *iterator <= '9') {
|
||||
temp |= *iterator - '0';
|
||||
} else if(*iterator == '+') {
|
||||
temp |= '>';
|
||||
} else if(*iterator == '/') {
|
||||
temp |= '?';
|
||||
} else if(*iterator == base64Pad) {
|
||||
switch(end - iterator) {
|
||||
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) {
|
||||
case 1:
|
||||
decoded.push_back((temp >> 16) & 0x000000FF);
|
||||
decoded.push_back((temp >> 8 ) & 0x000000FF);
|
||||
return decoded;
|
||||
*++iter = (temp >> 16) & 0xFF;
|
||||
*++iter = (temp >> 8) & 0xFF;
|
||||
return make_pair(move(buffer), decodedSize);
|
||||
case 2:
|
||||
decoded.push_back((temp >> 10) & 0x000000FF);
|
||||
return decoded;
|
||||
*++iter = (temp >> 10) & 0xFF;
|
||||
return make_pair(move(buffer), decodedSize);
|
||||
default:
|
||||
throw runtime_error("invalid padding in base64");
|
||||
throw ConversionException("invalid padding in base64");
|
||||
}
|
||||
} else {
|
||||
throw runtime_error("invalid character in base64");
|
||||
throw ConversionException("invalid character in base64");
|
||||
}
|
||||
}
|
||||
decoded.push_back((temp >> 16) & 0x000000FF);
|
||||
decoded.push_back((temp >> 8 ) & 0x000000FF);
|
||||
decoded.push_back((temp ) & 0x000000FF);
|
||||
*++iter = (temp >> 16) & 0xFF;
|
||||
*++iter = (temp >> 8) & 0xFF;
|
||||
*++iter = (temp ) & 0xFF;
|
||||
}
|
||||
return decoded;
|
||||
return make_pair(move(buffer), decodedSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -196,8 +196,8 @@ template <typename T> LIB_EXPORT std::string interpretIntegerAsString(T integer,
|
|||
|
||||
LIB_EXPORT std::string dataSizeToString(uint64 sizeInByte, bool includeByte = false);
|
||||
LIB_EXPORT std::string bitrateToString(double speedInKbitsPerSecond, bool useByteInsteadOfBits = false);
|
||||
LIB_EXPORT std::string encodeBase64(const std::vector<char> &bytes);
|
||||
LIB_EXPORT std::vector<char> decodeBase64(const std::string &encoded);
|
||||
LIB_EXPORT std::string encodeBase64(const byte *data, uint32 dataSize);
|
||||
LIB_EXPORT std::pair<std::unique_ptr<byte[]>, uint32> decodeBase64(const char *encodedStr, const uint32 strSize);
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue