diff options
Diffstat (limited to 'base64.cpp')
-rw-r--r-- | base64.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/base64.cpp b/base64.cpp new file mode 100644 index 0000000..7de7ade --- /dev/null +++ b/base64.cpp @@ -0,0 +1,233 @@ +#include <string> +#include <cstdint> +#include <cstdlib> + +#include "base64.hpp" + +std::string base64_encode(const void *data, size_t len) +{ + static const char *b64c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + std::string ret; + size_t counter = 0; + uint8_t rem; + const uint8_t *u8d = (uint8_t*) data; + for (size_t i = 0; i < len; ++i) + { + ++counter; + if (counter == 3) counter = 0; + switch (counter) + { + case 0: + rem |= (u8d[i] >> 6); + ret.push_back(b64c[rem]); + ret.push_back(b64c[u8d[i] & 0b111111]); + break; + case 1: + ret.push_back(b64c[u8d[i] >> 2]); + rem = (u8d[i] & 0b11) << 4; + break; + case 2: + rem |= (u8d[i] >> 4); + ret.push_back(b64c[rem]); + rem = (u8d[i] & 0b1111) << 2; + break; + } + } + if (counter) + { + ret.push_back(b64c[rem]); + for (int i = 0; i < 3 - counter; ++i) + ret.push_back('='); + } + return ret; +} + +void* base64_decode(const std::string& s, size_t *rel) +{ + static const uint8_t b64v[] = { + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,62,65,65,65,63, + 52,53,54,55,56,57,58,59,60,61,65,65,65,64,65,65, + 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,65,65,65,65,65, + 65,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,65,65,65,65,65 + }; + size_t npadd = 0; + for (auto ri = s.rbegin(); ri != s.rend(); ++ri) + if (*ri == '=') + ++npadd; + else break; + *rel = (s.length() - npadd) / 4 * 3; + switch (npadd) + { + case 0: break; + case 1: *rel += 2; break; + case 2: *rel += 1; break; + default: + return nullptr; + } + uint8_t *ret = (uint8_t*)malloc(*rel); + uint8_t rem = 0; + uint8_t counter = 0; + uint8_t *rp = ret; + for (size_t i = 0; i < s.size(); ++i) + { + ++counter; + if (counter == 4) counter = 0; + if (s[i] == '=') break; + if (s[i] < 0 || b64v[s[i]] > 64) + return nullptr; + switch (counter) + { + case 0: + rem |= b64v[s[i]]; + *(rp++) = rem; + break; + case 1: + rem = b64v[s[i]] << 2; + break; + case 2: + rem |= b64v[s[i]] >> 4; + *(rp++) = rem; + rem = (b64v[s[i]] & 0b1111) << 4; + break; + case 3: + rem |= b64v[s[i]] >> 2; + *(rp++) = rem; + rem = (b64v[s[i]] & 0b11) << 6; + break; + } + } + if (rp - ret != *rel) + { + free(ret); + return nullptr; + } + return ret; +} + +const char *Base64Encoder::b64c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +Base64Encoder::Base64Encoder() : counter(0), rem(0), ret(std::string()) {} + +void Base64Encoder::encode_data(const void *data, size_t len) +{ + const uint8_t *u8d = (uint8_t*) data; + for (size_t i = 0; i < len; ++i) + { + ++counter; + if (counter == 3) counter = 0; + switch (counter) + { + case 0: + rem |= (u8d[i] >> 6); + ret.push_back(b64c[rem]); + ret.push_back(b64c[u8d[i] & 0b111111]); + break; + case 1: + ret.push_back(b64c[u8d[i] >> 2]); + rem = (u8d[i] & 0b11) << 4; + break; + case 2: + rem |= (u8d[i] >> 4); + ret.push_back(b64c[rem]); + rem = (u8d[i] & 0b1111) << 2; + break; + } + } +} + +std::string Base64Encoder::finalize() +{ + if (counter) + { + ret.push_back(b64c[rem]); + for (int i = 0; i < 3 - counter; ++i) + ret.push_back('='); + } + return ret; +} + +const uint8_t Base64Decoder::b64v[] = { + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,62,65,65,65,63, + 52,53,54,55,56,57,58,59,60,61,65,65,65,64,65,65, + 65, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, + 15,16,17,18,19,20,21,22,23,24,25,65,65,65,65,65, + 65,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, + 41,42,43,44,45,46,47,48,49,50,51,65,65,65,65,65 +}; + +Base64Decoder::Base64Decoder(std::string &&b) : + s(b), + invalid(false), + rem(0), + counter(0), + bp(0) +{ + size_t npadd = 0; + for (auto ri = s.rbegin(); ri != s.rend(); ++ri) + if (*ri == '=') + ++npadd; + else break; + dlen = (s.length() - npadd) / 4 * 3; + switch (npadd) + { + case 0: break; + case 1: dlen += 2; break; + case 2: dlen += 1; break; + default: + dlen = 0; + invalid = true; + } +} + +size_t Base64Decoder::decoded_length() +{ + return dlen; +} + +size_t Base64Decoder::decode_data(const void *data, size_t len) +{ + uint8_t *rp = (uint8_t*)data; + for (; bp < s.size(); ++bp) + { + ++counter; + if (counter == 4) counter = 0; + if (s[bp] == '=') break; + if (s[bp] < 0 || b64v[s[bp]] > 64) + { + invalid = true; + return 0; + } + switch (counter) + { + case 0: + rem |= b64v[s[bp]]; + *(rp++) = rem; + break; + case 1: + rem = b64v[s[bp]] << 2; + break; + case 2: + rem |= b64v[s[bp]] >> 4; + *(rp++) = rem; + rem = (b64v[s[bp]] & 0b1111) << 4; + break; + case 3: + rem |= b64v[s[bp]] >> 2; + *(rp++) = rem; + rem = (b64v[s[bp]] & 0b11) << 6; + break; + } + if (rp - (uint8_t*)data == len) + { + ++bp; + break; + } + } + return rp - (uint8_t*)data; +} |