All pastes #1723492 Raw Edit

base63 encode/decode

public cpp v1 · immutable
#1723492 ·published 2009-12-22 09:59 UTC
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;}