base64.cpp
Go to the documentation of this file.
1 #include <stdexcept>
2 
4 
5 namespace foxglove {
6 
7 // Adapted from:
8 // https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594
9 // https://github.com/protocolbuffers/protobuf/blob/01fe22219a0/src/google/protobuf/compiler/csharp/csharp_helpers.cc#L346
10 std::string base64Encode(const std::string_view& input) {
11  constexpr const char ALPHABET[] =
12  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13  std::string result;
14  // Every 3 bytes of data yields 4 bytes of output
15  result.reserve((input.size() + (3 - 1 /* round up */)) / 3 * 4);
16 
17  // Unsigned values are required for bit-shifts below to work properly
18  const unsigned char* data = reinterpret_cast<const unsigned char*>(input.data());
19 
20  size_t i = 0;
21  for (; i + 2 < input.size(); i += 3) {
22  result.push_back(ALPHABET[data[i] >> 2]);
23  result.push_back(ALPHABET[((data[i] & 0b11) << 4) | (data[i + 1] >> 4)]);
24  result.push_back(ALPHABET[((data[i + 1] & 0b1111) << 2) | (data[i + 2] >> 6)]);
25  result.push_back(ALPHABET[data[i + 2] & 0b111111]);
26  }
27  switch (input.size() - i) {
28  case 2:
29  result.push_back(ALPHABET[data[i] >> 2]);
30  result.push_back(ALPHABET[((data[i] & 0b11) << 4) | (data[i + 1] >> 4)]);
31  result.push_back(ALPHABET[(data[i + 1] & 0b1111) << 2]);
32  result.push_back('=');
33  break;
34  case 1:
35  result.push_back(ALPHABET[data[i] >> 2]);
36  result.push_back(ALPHABET[(data[i] & 0b11) << 4]);
37  result.push_back('=');
38  result.push_back('=');
39  break;
40  }
41 
42  return result;
43 }
44 
45 // Adapted from:
46 // https://github.com/mvorbrodt/blog/blob/cd46051e180/src/base64.hpp#L55-L110
47 std::vector<unsigned char> base64Decode(const std::string& input) {
48  if (input.length() % 4) {
49  throw std::runtime_error("Invalid base64 length!");
50  }
51 
52  constexpr char kPadCharacter = '=';
53 
54  std::size_t padding{};
55 
56  if (input.length()) {
57  if (input[input.length() - 1] == kPadCharacter) padding++;
58  if (input[input.length() - 2] == kPadCharacter) padding++;
59  }
60 
61  std::vector<unsigned char> decoded;
62  decoded.reserve(((input.length() / 4) * 3) - padding);
63 
64  std::uint32_t temp{};
65  auto it = input.begin();
66 
67  while (it < input.end()) {
68  for (std::size_t i = 0; i < 4; ++i) {
69  temp <<= 6;
70  if (*it >= 0x41 && *it <= 0x5A)
71  temp |= *it - 0x41;
72  else if (*it >= 0x61 && *it <= 0x7A)
73  temp |= *it - 0x47;
74  else if (*it >= 0x30 && *it <= 0x39)
75  temp |= *it + 0x04;
76  else if (*it == 0x2B)
77  temp |= 0x3E;
78  else if (*it == 0x2F)
79  temp |= 0x3F;
80  else if (*it == kPadCharacter) {
81  switch (input.end() - it) {
82  case 1:
83  decoded.push_back((temp >> 16) & 0x000000FF);
84  decoded.push_back((temp >> 8) & 0x000000FF);
85  return decoded;
86  case 2:
87  decoded.push_back((temp >> 10) & 0x000000FF);
88  return decoded;
89  default:
90  throw std::runtime_error("Invalid padding in base64!");
91  }
92  } else
93  throw std::runtime_error("Invalid character in base64!");
94 
95  ++it;
96  }
97 
98  decoded.push_back((temp >> 16) & 0x000000FF);
99  decoded.push_back((temp >> 8) & 0x000000FF);
100  decoded.push_back((temp)&0x000000FF);
101  }
102 
103  return decoded;
104 }
105 
106 } // namespace foxglove
std::string base64Encode(const std::string_view &input)
Definition: base64.cpp:10
std::vector< unsigned char > base64Decode(const std::string &input)
Definition: base64.cpp:47


foxglove_bridge
Author(s): Foxglove
autogenerated on Mon Jul 3 2023 02:12:22