blob: 851ef72a42ad5864731f7c5b5277fc462d59ec72 [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#include <base64.hpp>
Ed Tanousf9273472017-02-28 16:05:13 -08002
Ed Tanous1abe55e2018-09-05 08:30:59 -07003namespace base64
4{
5bool base64_encode(const std::string &input, std::string &output)
6{
7 // This is left as a raw array (and not a range checked std::array) under
8 // the suspicion that the optimizer is not smart enough to remove the range
9 // checks that would be done below if at were called. As is, this array is
10 // 64 bytes long, which should be greater than the max of 0b00111111 when
11 // indexed NOLINT calls below are to silence clang-tidy about this
12 // TODO(ed) this requires further investigation if a more safe method could
13 // be used without performance impact.
14 static const char encoding_data[] =
15 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Ed Tanousf9273472017-02-28 16:05:13 -080016
Ed Tanous1abe55e2018-09-05 08:30:59 -070017 size_t input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -080018
Ed Tanous1abe55e2018-09-05 08:30:59 -070019 // allocate space for output string
20 output.clear();
21 output.reserve(((input_length + 2) / 3) * 4);
Ed Tanousf9273472017-02-28 16:05:13 -080022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023 // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
24 // encode using
25 // encoding_data lookup table.
26 // if input do not contains enough chars to complete 3-byte sequence,use pad
27 // char '='
28 for (size_t i = 0; i < input_length; i++)
29 {
30 int base64code0 = 0;
31 int base64code1 = 0;
32 int base64code2 = 0;
33 int base64code3 = 0;
Ed Tanousf9273472017-02-28 16:05:13 -080034
Ed Tanous1abe55e2018-09-05 08:30:59 -070035 base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
Ed Tanous911ac312017-08-15 09:37:42 -070036
Ed Tanous1abe55e2018-09-05 08:30:59 -070037 output += encoding_data[base64code0]; // NOLINT
38 base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080039
Ed Tanous1abe55e2018-09-05 08:30:59 -070040 if (++i < input_length)
41 {
42 base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
43 output += encoding_data[base64code1]; // NOLINT
44 base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080045
Ed Tanous1abe55e2018-09-05 08:30:59 -070046 if (++i < input_length)
47 {
48 base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
49 base64code3 = input[i] & 0x3f; // 3-byte 6 bits
50 output += encoding_data[base64code2]; // NOLINT
51 output += encoding_data[base64code3]; // NOLINT
52 }
53 else
54 {
55 output += encoding_data[base64code2]; // NOLINT
56 output += '=';
57 }
58 }
59 else
60 {
61 output += encoding_data[base64code1]; // NOLINT
62 output += '=';
63 output += '=';
64 }
Ed Tanousf9273472017-02-28 16:05:13 -080065 }
66
Ed Tanous1abe55e2018-09-05 08:30:59 -070067 return true;
Ed Tanousf9273472017-02-28 16:05:13 -080068}
69
Ed Tanous1abe55e2018-09-05 08:30:59 -070070bool base64_decode(const std::string &input, std::string &output)
71{
72 static const char nop = -1;
73 // See note on encoding_data[] in above function
74 static const char decoding_data[] = {
75 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
76 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
77 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
78 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
79 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
80 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
81 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
82 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
83 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
84 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
85 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
86 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
87 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
88 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
89 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
90 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
91 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
92 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
93 nop, nop, nop, nop};
Ed Tanousf9273472017-02-28 16:05:13 -080094
Ed Tanous1abe55e2018-09-05 08:30:59 -070095 size_t input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -080096
Ed Tanous1abe55e2018-09-05 08:30:59 -070097 // allocate space for output string
98 output.clear();
99 output.reserve(((input_length + 2) / 3) * 4);
Ed Tanousf9273472017-02-28 16:05:13 -0800100
Ed Tanous1abe55e2018-09-05 08:30:59 -0700101 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
102 // droping first two bits
103 // and regenerate into 3 8-bits sequences
Ed Tanousf9273472017-02-28 16:05:13 -0800104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105 for (size_t i = 0; i < input_length; i++)
106 {
107 char base64code0;
108 char base64code1;
109 char base64code2 = 0; // initialized to 0 to suppress warnings
110 char base64code3;
Ed Tanousf9273472017-02-28 16:05:13 -0800111
Ed Tanous1abe55e2018-09-05 08:30:59 -0700112 base64code0 = decoding_data[static_cast<int>(input[i])]; // NOLINT
113 if (base64code0 == nop)
114 { // non base64 character
115 return false;
116 }
117 if (!(++i < input_length))
118 { // we need at least two input bytes for first
119 // byte output
120 return false;
121 }
122 base64code1 = decoding_data[static_cast<int>(input[i])]; // NOLINT
123 if (base64code1 == nop)
124 { // non base64 character
125 return false;
126 }
127 output +=
128 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Ed Tanousf9273472017-02-28 16:05:13 -0800129
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 if (++i < input_length)
131 {
132 char c = input[i];
133 if (c == '=')
134 { // padding , end of input
135 return (base64code1 & 0x0f) == 0;
136 }
137 base64code2 = decoding_data[static_cast<int>(input[i])]; // NOLINT
138 if (base64code2 == nop)
139 { // non base64 character
140 return false;
141 }
142 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
143 ((base64code2 >> 2) & 0x0f));
144 }
145
146 if (++i < input_length)
147 {
148 char c = input[i];
149 if (c == '=')
150 { // padding , end of input
151 return (base64code2 & 0x03) == 0;
152 }
153 base64code3 = decoding_data[static_cast<int>(input[i])]; // NOLINT
154 if (base64code3 == nop)
155 { // non base64 character
156 return false;
157 }
158 output +=
159 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
160 }
Ed Tanousf9273472017-02-28 16:05:13 -0800161 }
162
Ed Tanous1abe55e2018-09-05 08:30:59 -0700163 return true;
Ed Tanousf9273472017-02-28 16:05:13 -0800164}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165} // namespace base64