Browse Source

Rewrite string::fromBase64() implementation.

tags/v2.0.0
Andrew Belt 4 years ago
parent
commit
6c35f3eb50
1 changed files with 41 additions and 50 deletions
  1. +41
    -50
      src/string.cpp

+ 41
- 50
src/string.cpp View File

@@ -187,62 +187,53 @@ std::string toBase64(const std::vector<uint8_t>& data) {




std::vector<uint8_t> fromBase64(const std::string& str) { std::vector<uint8_t> fromBase64(const std::string& str) {
size_t strLen = str.size();
if (strLen % 4 != 0)
throw std::runtime_error("String length not a factor of 4");

size_t numBlocks = strLen / 4;
size_t len = numBlocks * 3;
if (strLen >= 4) {
if (str[strLen - 1] == '=')
len--;
if (str[strLen - 2] == '=')
len--;
}
std::vector<uint8_t> data;
uint32_t block = 0;
int i = 0;
int padding = 0;


std::vector<uint8_t> data(len);
for (char c : str) {
uint8_t d = 0;


for (size_t b = 0; b < numBlocks; b++) {
// Encode block
uint32_t block = 0;
size_t i;
for (i = 0; i < 4; i++) {
uint8_t c = str[4 * b + i];
uint8_t d = 0;

if ('A' <= c && c <= 'Z') {
d = c - 'A';
}
else if ('a' <= c && c <= 'z') {
d = c - 'a' + 26;
}
else if ('0' <= c && c <= '9') {
d = c - '0' + 52;
}
else if (c == '+') {
d = 62;
}
else if (c == '/') {
d = 63;
}
else if (c == '=') {
// Padding ends block encoding
break;
}
else {
// Since we assumed the string was a factor of 4 bytes, fail if an invalid character, such as whitespace, was found.
throw std::runtime_error("String contains non-base64 character");
}

block |= uint32_t(d) << (6 * (3 - i));
if ('A' <= c && c <= 'Z') {
d = c - 'A';
}
else if ('a' <= c && c <= 'z') {
d = c - 'a' + 26;
}
else if ('0' <= c && c <= '9') {
d = c - '0' + 52;
}
else if (c == '+') {
d = 62;
}
else if (c == '/') {
d = 63;
}
else if (c == '=') {
padding++;
}
else {
// Ignore whitespace and non-base64 characters
continue;
} }


// Decode block
for (size_t k = 0; k < i - 1; k++) {
data[3 * b + k] = (block >> (8 * (2 - k))) & 0xff;
block |= uint32_t(d) << (6 * (3 - i));
i++;

if (i >= 4) {
// Decode block
data.push_back((block >> (8 * (2 - 0))) & 0xff);
if (padding < 2)
data.push_back((block >> (8 * (2 - 1))) & 0xff);
if (padding < 1)
data.push_back((block >> (8 * (2 - 2))) & 0xff);
// Reset block
block = 0;
i = 0;
padding = 0;
} }
} }

return data; return data;
} }




Loading…
Cancel
Save