Apache Mesos
base64.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_BASE64_HPP__
14 #define __STOUT_BASE64_HPP__
15 
16 #include <cctype>
17 #include <functional>
18 #include <string>
19 
20 #include <stout/foreach.hpp>
21 #include <stout/stringify.hpp>
22 #include <stout/try.hpp>
23 
24 namespace base64 {
25 
26 namespace internal {
27 
28 // This slightly modified base64 implementation from
29 // cplusplus.com answer by modoran can be found at:
30 // http://www.cplusplus.com/forum/beginner/51572/
31 
32 constexpr char STANDARD_CHARS[] =
33  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
34  "abcdefghijklmnopqrstuvwxyz"
35  "0123456789+/";
36 
37 constexpr char URL_SAFE_CHARS[] =
38  "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
39  "abcdefghijklmnopqrstuvwxyz"
40  "0123456789-_";
41 
42 
43 inline std::string encode(
44  const std::string& s,
45  const std::string& chars,
46  bool padding)
47 {
48  std::string result;
49  int i = 0;
50  int j = 0;
51  unsigned char array3[3];
52  unsigned char array4[4];
53  const char* bytesToEncode = s.c_str();
54  size_t length = s.size();
55 
56  while (length--) {
57  array3[i++] = *(bytesToEncode++);
58  if (i == 3) {
59  array4[0] = (array3[0] & 0xfc) >> 2;
60  array4[1] = ((array3[0] & 0x03) << 4) + ((array3[1] & 0xf0) >> 4);
61  array4[2] = ((array3[1] & 0x0f) << 2) + ((array3[2] & 0xc0) >> 6);
62  array4[3] = array3[2] & 0x3f;
63  for (i = 0; i < 4; i++) {
64  result += chars[array4[i]];
65  }
66  i = 0;
67  }
68  }
69 
70  if (i != 0) {
71  for (j = i; j < 3; j++) {
72  array3[j] = '\0';
73  }
74  array4[0] = (array3[0] & 0xfc) >> 2;
75  array4[1] = ((array3[0] & 0x03) << 4) + ((array3[1] & 0xf0) >> 4);
76  array4[2] = ((array3[1] & 0x0f) << 2) + ((array3[2] & 0xc0) >> 6);
77  array4[3] = array3[2] & 0x3f;
78  for (j = 0; j < i + 1; j++) {
79  result += chars[array4[j]];
80  }
81  if (padding) {
82  while (i++ < 3) {
83  result += '=';
84  }
85  }
86  }
87 
88  return result;
89 }
90 
91 
92 inline Try<std::string> decode(const std::string& s, const std::string& chars)
93 {
94  auto isBase64 = [&chars](unsigned char c) -> bool {
95  return (isalnum(c) || (c == chars[62]) || (c == chars[63]));
96  };
97 
98  size_t i = 0;
99  unsigned char array3[3];
100  unsigned char array4[4];
101  std::string result;
102 
103  foreach (unsigned char c, s) {
104  if (c == '=') {
105  // TODO(bmahler): Note that this does not validate that
106  // there are the correct number of '=' characters!
107  break; // Reached the padding.
108  }
109 
110  // The base RFC (https://tools.ietf.org/html/rfc4648#section-3.3) explicitly
111  // asks to reject non-alphabet characters including newlines and
112  // whitespaces. However, other specifications like MIME simply ignore
113  // characters outside the base alphabet ("be liberal in what you accept").
114  // Further, most implementation ignore whiltespace characters when
115  // processing encoded data. This allows tools to delimit encoded with
116  // newlines or other whitespace characters for better readability, etc.
117  if (isspace(c)) {
118  continue;
119  }
120 
121  if (!isBase64(c)) {
122  return Error("Invalid character '" + stringify(c) + "'");
123  }
124 
125  array4[i++] = c;
126 
127  if (i == 4) {
128  for (i = 0; i < 4; i++) {
129  array4[i] = static_cast<unsigned char>(chars.find(array4[i]));
130  }
131  array3[0] = (array4[0] << 2) + ((array4[1] & 0x30) >> 4);
132  array3[1] = ((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2);
133  array3[2] = ((array4[2] & 0x3) << 6) + array4[3];
134  for (i = 0; i < 3; i++) {
135  result += array3[i];
136  }
137  i = 0;
138  }
139  }
140 
141  if (i != 0) {
142  size_t j;
143 
144  for (j = i; j < 4; j++) {
145  array4[j] = 0;
146  }
147  for (j = 0; j < 4; j++) {
148  array4[j] = static_cast<unsigned char>(chars.find(array4[j]));
149  }
150  array3[0] = (array4[0] << 2) + ((array4[1] & 0x30) >> 4);
151  array3[1] = ((array4[1] & 0xf) << 4) + ((array4[2] & 0x3c) >> 2);
152  array3[2] = ((array4[2] & 0x3) << 6) + array4[3];
153  for (j = 0; (j < i - 1); j++) {
154  result += array3[j];
155  }
156  }
157 
158  return result;
159 }
160 
161 } // namespace internal {
162 
163 
170 inline std::string encode(const std::string& s)
171 {
173 }
174 
175 
183 inline Try<std::string> decode(const std::string& s)
184 {
186 }
187 
188 
196 inline std::string encode_url_safe(const std::string& s, bool padding = true)
197 {
198  return internal::encode(s, internal::URL_SAFE_CHARS, padding);
199 }
200 
201 
209 inline Try<std::string> decode_url_safe(const std::string& s)
210 {
212 }
213 
214 } // namespace base64 {
215 
216 #endif // __STOUT_BASE64_HPP__
Definition: errorbase.hpp:36
Definition: check.hpp:33
std::string encode(const std::string &s, const std::string &chars, bool padding)
Definition: base64.hpp:43
constexpr char URL_SAFE_CHARS[]
Definition: base64.hpp:37
std::string encode_url_safe(const std::string &s, bool padding=true)
Encode a string to Base64 with a URL and filename safe alphabet.
Definition: base64.hpp:196
Definition: attributes.hpp:24
Try< std::string > decode_url_safe(const std::string &s)
Decode a string that is Base64-encoded with a URL and filename safe alphabet.
Definition: base64.hpp:209
std::string stringify(int flags)
Definition: base64.hpp:24
constexpr char STANDARD_CHARS[]
Definition: base64.hpp:32
Try< std::string > decode(const std::string &s, const std::string &chars)
Definition: base64.hpp:92