| @@ -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; | ||||
| } | } | ||||