diff --git a/conversion/stringconversion.cpp b/conversion/stringconversion.cpp index cedf330..0926fc3 100644 --- a/conversion/stringconversion.cpp +++ b/conversion/stringconversion.cpp @@ -1,5 +1,7 @@ #include "stringconversion.h" +#include "../misc/memory.h" + #include #include @@ -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 &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 decodeBase64(const string &encoded) +LIB_EXPORT pair, 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 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(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); } } diff --git a/conversion/stringconversion.h b/conversion/stringconversion.h index 4f76c5d..46c86e1 100644 --- a/conversion/stringconversion.h +++ b/conversion/stringconversion.h @@ -196,8 +196,8 @@ template 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 &bytes); -LIB_EXPORT std::vector decodeBase64(const std::string &encoded); +LIB_EXPORT std::string encodeBase64(const byte *data, uint32 dataSize); +LIB_EXPORT std::pair, uint32> decodeBase64(const char *encodedStr, const uint32 strSize); }