| 22 | "0123456789+/"; |
| 23 | |
| 24 | std::string encode(const BinaryArray &data) { |
| 25 | std::string ret; |
| 26 | const uint8_t *const buf = data.data(); |
| 27 | const size_t buf_len = data.size(); |
| 28 | // Calculate how many bytes that needs to be added to get a multiple of 3 |
| 29 | size_t missing = 0; |
| 30 | size_t ret_size = buf_len; |
| 31 | while ((ret_size % 3) != 0) { |
| 32 | ++ret_size; |
| 33 | ++missing; |
| 34 | } |
| 35 | |
| 36 | // Expand the return string size to a multiple of 4 |
| 37 | ret_size = 4 * ret_size / 3; |
| 38 | |
| 39 | ret.reserve(ret_size); |
| 40 | |
| 41 | for (size_t i = 0; i < ret_size / 4; ++i) { |
| 42 | // Read a group of three bytes (avoid buffer overrun by replacing with 0) |
| 43 | const size_t index = i * 3; |
| 44 | const uint8_t b3_0 = (index + 0 < buf_len) ? buf[index + 0] : uint8_t(0); |
| 45 | const uint8_t b3_1 = (index + 1 < buf_len) ? buf[index + 1] : uint8_t(0); |
| 46 | const uint8_t b3_2 = (index + 2 < buf_len) ? buf[index + 2] : uint8_t(0); |
| 47 | |
| 48 | // Transform into four base 64 characters |
| 49 | const uint8_t b4_0 = ((b3_0 & 0xfc) >> 2); |
| 50 | const uint8_t b4_1 = ((b3_0 & 0x03) << 4) + ((b3_1 & 0xf0) >> 4); |
| 51 | const uint8_t b4_2 = ((b3_1 & 0x0f) << 2) + ((b3_2 & 0xc0) >> 6); |
| 52 | const uint8_t b4_3 = ((b3_2 & 0x3f) << 0); |
| 53 | |
| 54 | // Add the base 64 characters to the return value |
| 55 | ret.push_back(to_base64[b4_0]); |
| 56 | ret.push_back(to_base64[b4_1]); |
| 57 | ret.push_back(to_base64[b4_2]); |
| 58 | ret.push_back(to_base64[b4_3]); |
| 59 | } |
| 60 | |
| 61 | // Replace data that is invalid (always as many as there are missing bytes) |
| 62 | for (size_t i = 0; i != missing; ++i) |
| 63 | ret[ret_size - i - 1] = '='; |
| 64 | return ret; |
| 65 | } |
| 66 | |
| 67 | bool decode(const std::string &in, BinaryArray *ret) { |
| 68 | // Make sure the *intended* string length is a multiple of 4 |