rendered paste body#include <iostream>#include <cassert>// api:/// \return exact size of encoded data/// \param size the size of datasize_t get_encoded_size(size_t size);/// \return maximum size of decoded data, not exact value!/// \param size the size of encoded datasize_t get_decoded_size(size_t size);/// ecode data with standard base64 alphabet/// \param begin start iterator for input data/// \param end iterator after the last for input data/// \param output iterator for storing output datatemplate<class I, class O>void encode(I begin, I end, O output);/// ecode data with standard base64 alphabet or with fileasfe alphabet/// \param begin start iterator for input data/// \param end iterator after the last for input data/// \param output iterator for storing output data/// \param use_filesafe_alphabet if true - filesafe alphabet will be usedtemplate<class I, class O>void encode(I begin, I end, O output, bool use_filesafe_alphabet);/// decode data encoded with standard base64 alphabet/// \param begin start iterator for input data/// \param end iterator after the last for input data/// \param output iterator for storing output datatemplate<class I, class O>void decode(I begin, I end, O output);/// decode data encoded with standard base64 alphabet or with filesafe alphabet/// \param begin start iterator for input data/// \param end iterator after the last for input data/// \param output iterator for storing output data/// \param use_filesafe_alphabet if true - filesafe alphabet will be usedtemplate<class I, class O>void decode(I begin, I end, O output, bool use_filesafe_alphabet);namespace{const char tail_padding = '=';const char standard_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";const char filesafe_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789-_"; const char standard_alphabet_reverse_table[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };const char filesafe_alphabet_reverse_table[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };charencodeChar(const char* alphabet, const unsigned char* data, size_t index){ assert(index <= 3); if (index == 0) return alphabet[(data[0] & 0xFC) >> 2]; else if (index == 1) return alphabet[((data[0] & 0x03) << 4) + ((data[1] & 0xF0) >> 4)]; else if (index == 2) return alphabet[((data[1] & 0x0F) << 2) + ((data[2] & 0xC0) >> 6)]; // 3 return alphabet[data[2] & 0x3F];}unsigned chardecodeChar(const char* indexes, size_t index){ assert(index <= 2); if (index == 0) return (indexes[0] << 2) + ((indexes[1] & 0x30) >> 4); else if (index == 1) return ((indexes[1] & 0x0F) << 4) + ((indexes[2] & 0x3C) >> 2); // 2 return ((indexes[2] & 0x03) << 6) + indexes[3];}#if 0// helper function, generates reverse table by given alphabetstd::stringgenerateReverseTable(const char* alphabet){ std::string alphabet_str = alphabet; std::ostringstream result; result << "const unsigned char reverse_table[] = {\n\t"; size_t inserted = 0; for (unsigned char i = 0; i < 255; ++i) { size_t pos = alphabet_str.find(i); if (pos != std::string::npos) result << "0x" << std::hex << std::setw(2) << std::setfill('0') << std::uppercase << pos << std::dec << ", "; else result << "0xFF, "; if (++inserted == 20) { inserted = 0; result << "\n\t"; } } result << "0xFF };"; return result.str();}#endif}size_tget_encoded_size(size_t size){ return (2 + size - ((size + 2) % 3)) * 4 / 3;}size_tget_decoded_size(size_t size){ return size * 3 / 4;}template<class I, class O>voidencode(I begin, I end, O output){ encode(begin, end, output, false);}template<class I, class O>voidencode(I begin, I end, O output, bool use_filesafe_alphabet){ const char* alphabet = use_filesafe_alphabet ? filesafe_alphabet : standard_alphabet; size_t tail_size = 0; unsigned char tail[3]; for (; begin != end; ++begin) { tail[tail_size++] = *begin; if (tail_size == 3) { for (size_t i = 0; i != 4; ++i, ++output) *output = encodeChar(alphabet, tail, i); tail_size = 0; } } if (tail_size) { for (size_t i = tail_size; i != 3; ++i) tail[i] = 0; for (size_t i = 0; i != tail_size + 1; ++i, ++output) *output = encodeChar(alphabet, tail, i); for (size_t i = tail_size + 1; i != 4; ++i, ++output) *output = tail_padding; }}template<class I, class O>voiddecode(I begin, I end, O output){ decode(begin, end, output, false);}template<class I, class O>voiddecode(I begin, I end, O output, bool use_filesafe_alphabet) { const char* table = use_filesafe_alphabet ? filesafe_alphabet_reverse_table : standard_alphabet_reverse_table; size_t tail_size = 0; char tail[4]; for (; begin != end && *begin != tail_padding; ++begin) { tail[tail_size++] = *begin; if (tail_size == 4) { for (size_t i = 0; i != 4; ++i) { tail[i] = table[size_t(tail[i])]; assert(tail[i] != 0xFF); } for (size_t i = 0; i != 3; ++i, ++output) *output = decodeChar(tail, i); tail_size = 0; } } if (tail_size) { for (size_t i = tail_size; i != 4; ++i) tail[i] = 0; for (size_t i = 0; i != 4; ++i) { tail[i] = table[size_t(tail[i])]; assert(tail[i] != 0xFF); } for (size_t i = 0; i != tail_size - 1; ++i, ++output) *output = decodeChar(tail, i); }}int main(){ const char* tests[][2] = { { "leasure.", "bGVhc3VyZS4=" }, { "easure.", "ZWFzdXJlLg==" }, { "asure.", "YXN1cmUu" }, { "sure.", "c3VyZS4="} }; for (size_t i = 0; i != sizeof(tests) / sizeof(*tests); ++i) { std::string str(tests[i][0]); std::string b64; encode(str.begin(), str.end(), std::back_inserter(b64)); assert(b64 == tests[i][1]); assert(b64.size() == get_encoded_size(str.size())); std::string str2; decode(b64.begin(), b64.end(), std::back_inserter(str2)); assert(str2 == str); assert(str2.size() <= get_decoded_size(b64.size())); } return 0;}