Euphoria
base64.cc
Go to the documentation of this file.
1 #include "core/base64.h"
2 
3 #include "assert/assert.h"
4 #include "base/cint.h"
5 #include "base/stringbuilder.h"
6 
7 #include <string_view>
8 #include <array>
9 
10 // source: https://en.wikipedia.org/wiki/Base64
11 
13 {
14  namespace
15  {
16  constexpr std::string_view codes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
17  }
18 
19  std::string
20  encode(std::shared_ptr<MemoryChunk> memory)
21  {
22  MemoryChunk& input = *memory;
23  auto out = StringBuilder{};
24 
25  for(int input_index = 0; input_index < input.get_size(); input_index += 3)
26  {
27  int b = (input[input_index] & 0xFC) >> 2;
28  out.add_char(codes[b]);
29  b = (input[input_index] & 0x03) << 4;
30  if(input_index + 1 < input.get_size())
31  {
32  b |= (input[input_index + 1] & 0xF0) >> 4;
33  out.add_char(codes[b]);
34  b = (input[input_index + 1] & 0x0F) << 2;
35  if(input_index + 2 < input.get_size())
36  {
37  b |= (input[input_index + 2] & 0xC0) >> 6;
38  out.add_char(codes[b]);
39  b = input[input_index + 2] & 0x3F;
40  out.add_char(codes[b]);
41  }
42  else
43  {
44  out.add_char(codes[b]);
45  out.add_char('=');
46  }
47  }
48  else
49  {
50  out.add_char(codes[b]);
51  out.add_view("==");
52  }
53  }
54 
55  return out.to_string();
56  }
57 
58  std::shared_ptr<MemoryChunk>
59  decode(const std::string& input)
60  {
61  if(input.length() % 4 == 0)
62  {
63  ASSERT(!input.empty());
64  auto asize = (input.length() * 3) / 4;
65  auto found = input.find('=') != std::string::npos;
66  auto bsize = found ? (input.length() - input.find('=')) : 0;
67  int size = c_sizet_to_int(asize) - c_sizet_to_int(bsize);
68 
69  ASSERT(size > 0);
70 
71  auto ret = MemoryChunk::allocate(size);
72  MemoryChunk& decoded = *ret;
73  int decoded_index = 0;
74  for(int input_index = 0; input_index < c_sizet_to_int(input.size()); input_index += 4)
75  {
76  // This could be made faster (but more complicated) by precomputing these index locations.
77  const auto b = std::array<size_t, 4>
78  {
79  codes.find(input[c_int_to_sizet(input_index)]),
80  codes.find(input[c_int_to_sizet(input_index + 1)]),
81  codes.find(input[c_int_to_sizet(input_index + 2)]),
82  codes.find(input[c_int_to_sizet(input_index + 3)])
83  };
84  decoded[decoded_index++] = static_cast<char>((b[0] << 2) | (b[1] >> 4));
85  if(b[2] < 64)
86  {
87  decoded[decoded_index++] = static_cast<char>((b[1] << 4) | (b[2] >> 2));
88  if(b[3] < 64)
89  {
90  decoded[decoded_index++] = static_cast<char>((b[2] << 6) | b[3]);
91  }
92  }
93  }
94  return ret;
95  }
96  else
97  {
98  return MemoryChunk::create_null();
99  }
100  }
101 }
#define ASSERT(x)
Definition: assert.h:29
std::string encode(std::shared_ptr< MemoryChunk > memory)
Definition: base64.cc:20
std::shared_ptr< MemoryChunk > decode(const std::string &input)
Definition: base64.cc:59
int c_sizet_to_int(size_t t)
Definition: cint.cc:11
size_t c_int_to_sizet(int i)
Definition: cint.cc:35
static std::shared_ptr< MemoryChunk > allocate(int size)
Definition: memorychunk.cc:40
int get_size() const
Definition: memorychunk.cc:24
static std::shared_ptr< MemoryChunk > create_null()
Definition: memorychunk.cc:47