All Classes Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
base64.hpp
1 // The MIT License (MIT)
2 
3 // Copyright (c) 2012-2014 Danny Y., Rapptz
4 
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal in
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 // the Software, and to permit persons to whom the Software is furnished to do so,
10 // subject to the following conditions:
11 
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
14 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef GEARS_UTILITY_BASE64_HPP
23 #define GEARS_UTILITY_BASE64_HPP
24 
25 #include <string>
26 #include <unordered_map>
27 #include <cstddef>
28 #include <exception>
29 
30 namespace gears {
31 namespace utility {
32 
37 class invalid_base64 : public std::exception {
38 public:
39  invalid_base64() = default;
40 
41  const char* what() const noexcept override {
42  return "base64 string provided is invalid";
43  }
44 };
45 
46 namespace base64 {
47 namespace detail {
48 const signed char npos = -1;
49 } // detail
50 
62 inline std::string encode(const std::string& str) {
63  size_t index = 0;
64  static auto read = [&index](const std::string& s) -> signed char {
65  if(index >= s.length() || s.empty()) {
66  return detail::npos;
67  }
68  signed char result = s[index++] & 0xFF;
69  return result;
70  };
71 
72  static const char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
73 
74  std::string result;
75  signed char buffer[3]; // 24 bits
76 
77  while(true) {
78  buffer[0] = read(str);
79  if(buffer[0] == detail::npos) {
80  break;
81  }
82 
83  buffer[1] = read(str);
84  buffer[2] = read(str);
85 
86  result += lookup[buffer[0] >> 2];
87  if(buffer[1] != detail::npos) {
88  result += lookup[((buffer[0] << 4) & 0x30) | (buffer[1] >> 4)];
89 
90  if(buffer[2] != detail::npos) {
91  result += lookup[((buffer[1] << 2) & 0x3C) | (buffer[2] >> 6)];
92  result += lookup[buffer[2] & 0x3F];
93  }
94  else {
95  result += lookup[(buffer[1] << 2) & 0x3C];
96  result += '=';
97  break;
98  }
99  }
100  else {
101  result += lookup[(buffer[0] << 4) & 0x30];
102  result += "==";
103  break;
104  }
105  }
106 
107  return result;
108 }
109 
121 inline std::string decode(const std::string& str) {
122  size_t index = 0;
123 
124  static std::unordered_map<char,int> lookup = {
125  {'A', 0}, {'B', 1}, {'C', 2}, {'D', 3}, {'E', 4}, {'F', 5}, {'G', 6}, {'H', 7}, {'I', 8},
126  {'J', 9}, {'K', 10}, {'L', 11}, {'M', 12}, {'N', 13}, {'O', 14}, {'P', 15}, {'Q', 16},
127  {'R', 17}, {'S', 18}, {'T', 19}, {'U', 20}, {'V', 21}, {'W', 22}, {'X', 23}, {'Y', 24},
128  {'Z', 25}, {'a', 26}, {'b', 27}, {'c', 28}, {'d', 29}, {'e', 30}, {'f', 31}, {'g', 32},
129  {'h', 33}, {'i', 34}, {'j', 35}, {'k', 36}, {'l', 37}, {'m', 38}, {'n', 39}, {'o', 40},
130  {'p', 41}, {'q', 42}, {'r', 43}, {'s', 44}, {'t', 45}, {'u', 46}, {'v', 47}, {'w', 48},
131  {'x', 49}, {'y', 50}, {'z', 51}, {'0', 52}, {'1', 53}, {'2', 54}, {'3', 55}, {'4', 56},
132  {'5', 57}, {'6', 58}, {'7', 59}, {'8', 60}, {'9', 61}, {'+', 62}, {'/', 63}
133  };
134 
135  static auto read = [&](const std::string& st) -> signed char {
136  if(st.empty()) {
137  return detail::npos;
138  }
139 
140  while(true) {
141  if(index > st.length()) {
142  return detail::npos;
143  }
144 
145  auto next = st[index];
146  ++index;
147  auto it = lookup.find(next);
148  if(it != lookup.end()) {
149  return it->second;
150  }
151  }
152  };
153 
154  char buffer[4];
155  std::string result;
156  while(true) {
157  buffer[0] = read(str);
158  if(buffer[0] == detail::npos) {
159  break;
160  }
161 
162  buffer[1] = read(str);
163  if(buffer[1] == detail::npos) {
164  break;
165  }
166 
167 
168  buffer[2] = read(str);
169  buffer[3] = read(str);
170  result += ((buffer[0] << 2) & 0xFF) | (buffer[1] >> 4);
171 
172  if(buffer[2] == detail::npos) {
173  break;
174  }
175 
176  result += ((buffer[1] << 4) & 0xFF) | (buffer[2] >> 2);
177 
178  if(buffer[3] == detail::npos) {
179  break;
180  }
181 
182  result += ((buffer[2] << 6) & 0xFF) | buffer[3];
183  }
184 
185  return result;
186 }
187 } // base64
188 } // utility
189 } // gears
190 
191 #endif // GEARS_UTILITY_BASE64_HPP