#pragma once #include #include class base64_t { public: constexpr base64_t(const char *charset, char terminator):_terminator(terminator) { for (int i = 0; i < 64; ++i) _charset[i] = charset[i]; for (char &c: _charmap) c=static_cast(-1); for (unsigned int i = 0; i < 64;++i) { int c = _charset[i]-32; _charmap[c] = static_cast(i); } } template constexpr OutIter encode(InIter beg, InIter end, OutIter out) const { unsigned int remain = 0; unsigned int accum = 0; while (beg != end) { accum = static_cast(*beg); ++beg; if (beg == end) { remain = 2; break; } accum = (accum << 8) | static_cast(*beg); ++beg; if (beg == end) { remain = 1; break; } accum = (accum << 8) | static_cast(*beg); ++beg; *out = _charset[accum >> 18]; ++out; *out = _charset[(accum >> 12) & 0x3F]; ++out; *out = _charset[(accum >> 6) & 0x3F]; ++out; *out = _charset[accum & 0x3F]; ++out; accum = 0; } switch (remain) { case 2: *out = _charset[accum >> 2]; ++out; *out = _charset[(accum << 4) & 0x3F]; ++out; if (_terminator) { *out = _terminator; ++out; *out = _terminator; ++out; } break; case 1: *out = _charset[accum >> 10]; ++out; *out = _charset[(accum >> 4) & 0x3F]; ++out; *out = _charset[(accum << 2) & 0x3F]; ++out; if (_terminator) { *out = _terminator; ++out; } break; default: break; } return out; } template constexpr OutIter decode(InIter beg, InIter end, OutIter out) const { unsigned int accum = 0; unsigned int remain = 0; char c = 0; auto load_next = [&]() { do { if (beg == end || *beg == _terminator) return false; auto val = static_cast(*beg)-32; ++beg; if (val < 96) { c = _charmap[val]; if (c != -1) return true; } //skip invalid characters } while (true); }; while (load_next()) { accum = c; if (!load_next()) { remain = 3; break; } accum = (accum << 6) | c; if (!load_next()) { remain = 2; break; } accum = (accum << 6) | c; if (!load_next()) { remain = 1; break; } accum = (accum << 6) | c; *out = static_cast(accum >> 16); ++out; *out = static_cast((accum >> 8) & 0xFF); ++out; *out = static_cast(accum & 0xFF); ++out; } switch (remain) { default: break; case 2: *out = static_cast(accum >> 4); ++out; break; case 1:*out = static_cast(accum >> 10); ++out; *out = static_cast((accum >> 2) & 0xFF); ++out; break; } return out; } protected: char _charset[64] = {}; char _charmap[96] = {}; char _terminator; }; inline constexpr auto base64 = base64_t{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",'='}; inline constexpr auto base64url = base64_t{"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",'\0'}; template class binary_data { public: static constexpr std::size_t buff_size = (N+3)*3/4; constexpr binary_data(const char *txt) { auto res =base64.decode(txt, txt+N, data); sz = res - data; } constexpr operator std::basic_string_view() const { return {data, sz}; } operator std::string_view() const { return {reinterpret_cast(data), sz}; } constexpr auto begin() const {return data;} constexpr auto end() const {return data+sz;} constexpr std::size_t size() const {return sz;} protected: std::size_t sz = 0; unsigned char data[buff_size]= {}; }; template binary_data(const char (&)[N]) -> binary_data;