blob: 259288757b67ef128204afadf9e2524fd101f4fb [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#include <base64.hpp>
2#include <cassert>
3
4namespace base64
5{
6bool base64_encode(const gsl::cstring_span<> &input, std::string &output)
7{
8 static const char encoding_data[] =
9 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
10
11 unsigned int input_length = input.size();
12
13 // allocate space for output string
14 output.clear();
15 output.reserve(((input_length + 2) / 3) * 4);
16
17 // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
18 // encode using
19 // encoding_data lookup table.
20 // if input do not contains enough chars to complete 3-byte sequence,use pad
21 // char '='
22 for (unsigned int i = 0; i < input_length; i++) {
23 int base64code0 = 0;
24 int base64code1 = 0;
25 int base64code2 = 0;
26 int base64code3 = 0;
27
28 base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
29 output += encoding_data[base64code0];
30 base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
31
32 if (++i < input_length) {
33 base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
34 output += encoding_data[base64code1];
35 base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
36
37 if (++i < input_length) {
38 base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
39 base64code3 = input[i] & 0x3f; // 3-byte 6 bits
40 output += encoding_data[base64code2];
41 output += encoding_data[base64code3];
42 } else {
43 output += encoding_data[base64code2];
44 output += '=';
45 }
46 } else {
47 output += encoding_data[base64code1];
48 output += '=';
49 output += '=';
50 }
51 }
52
53 return true;
54}
55
56
57bool base64_decode(const gsl::cstring_span<> &input, std::string &output)
58{
59 static const char nop = -1;
60 static const char decoding_data[] = {
61 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
62 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
63 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop,
64 nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop,
65 nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
66 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
67 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33,
68 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
69 49, 50, 51, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
70 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
71 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
72 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
73 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
74 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
75 nop, 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, nop,
77 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
78 nop};
79
80 unsigned int input_length = input.size();
81
82 // allocate space for output string
83 output.clear();
84 output.reserve(((input_length + 2) / 3) * 4);
85
86 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
87 // droping first two bits
88 // and regenerate into 3 8-bits sequence
89
90 for (unsigned int i = 0; i < input_length; i++) {
91 char base64code0;
92 char base64code1;
93 char base64code2 = 0; // initialized to 0 to suppress warnings
94 char base64code3;
95
96 base64code0 = decoding_data[static_cast<int>(input[i])];
97 if (base64code0 == nop) // non base64 character
98 return false;
99 if (!(++i < input_length)) // we need at least two input bytes for first
100 // byte output
101 return false;
102 base64code1 = decoding_data[static_cast<int>(input[i])];
103 if (base64code1 == nop) // non base64 character
104 return false;
105
106 output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
107
108 if (++i < input_length) {
109 char c = input[i];
110 if (c == '=') { // padding , end of input
111 assert((base64code1 & 0x0f) == 0);
112 return true;
113 }
114 base64code2 = decoding_data[static_cast<int>(input[i])];
115 if (base64code2 == nop) // non base64 character
116 return false;
117
118 output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f);
119 }
120
121 if (++i < input_length) {
122 char c = input[i];
123 if (c == '=') { // padding , end of input
124 assert((base64code2 & 0x03) == 0);
125 return true;
126 }
127 base64code3 = decoding_data[static_cast<int>(input[i])];
128 if (base64code3 == nop) // non base64 character
129 return false;
130
131 output += (((base64code2 << 6) & 0xc0) | base64code3);
132 }
133 }
134
135 return true;
136}
137
138}