blob: 2e64bfa2f6db1f75f1b6445d2721a4486488192f [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{
Ed Tanousf7929c32019-10-23 11:46:55 -07007 // As is, this array is 64 bytes long, which should be greater than the max
8 // of 0b00111111 when indexed NOLINT calls below are to silence clang-tidy
9 // warnings about this
10 constexpr std::array<char, 64> encoding_data = {
11 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
12 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
13 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
14 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
15 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
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{
Ed Tanousf7929c32019-10-23 11:46:55 -070072 constexpr char nop = -1;
Ed Tanous1abe55e2018-09-05 08:30:59 -070073 // See note on encoding_data[] in above function
Ed Tanousf7929c32019-10-23 11:46:55 -070074 constexpr std::array<char, 256> decoding_data = {
Ed Tanous1abe55e2018-09-05 08:30:59 -070075 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 Tanousf7929c32019-10-23 11:46:55 -0700112 base64code0 = decoding_data[static_cast<size_t>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700113 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 }
Ed Tanousf7929c32019-10-23 11:46:55 -0700122 base64code1 = decoding_data[static_cast<size_t>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700123 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 }
Ed Tanousf7929c32019-10-23 11:46:55 -0700137 base64code2 =
138 decoding_data[static_cast<size_t>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700139 if (base64code2 == nop)
140 { // non base64 character
141 return false;
142 }
143 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
144 ((base64code2 >> 2) & 0x0f));
145 }
146
147 if (++i < input_length)
148 {
149 char c = input[i];
150 if (c == '=')
151 { // padding , end of input
152 return (base64code2 & 0x03) == 0;
153 }
Ed Tanousf7929c32019-10-23 11:46:55 -0700154 base64code3 =
155 decoding_data[static_cast<size_t>(input[i])]; // NOLINT
Ed Tanous1abe55e2018-09-05 08:30:59 -0700156 if (base64code3 == nop)
157 { // non base64 character
158 return false;
159 }
160 output +=
161 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
162 }
Ed Tanousf9273472017-02-28 16:05:13 -0800163 }
164
Ed Tanous1abe55e2018-09-05 08:30:59 -0700165 return true;
Ed Tanousf9273472017-02-28 16:05:13 -0800166}
Ed Tanous1abe55e2018-09-05 08:30:59 -0700167} // namespace base64