blob: 0013c28ac3ce82b9aae9e633a45e2a4080141ab1 [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#include <base64.hpp>
Ed Tanousf9273472017-02-28 16:05:13 -08002
Ed Tanous99923322017-03-03 14:21:24 -08003namespace base64 {
Ed Tanous9b65f1f2017-03-07 15:17:13 -08004bool base64_encode(const std::string &input, std::string &output) {
Ed Tanous911ac312017-08-15 09:37:42 -07005 // This is left as a raw array (and not a range checked std::array) under the
6 // suspicion that the optimizer is not smart enough to remove the range checks
7 // that would be done below if at were called. As is, this array is 64 bytes
8 // long, which should be greater than the max of 0b00111111 when indexed
9 // NOLINT calls below are to silence clang-tidy about this
10 // TODO(ed) this requires further investigation if a more safe method could be
11 // used without performance impact.
Ed Tanous1ff48782017-04-18 12:45:08 -070012 static const char encoding_data[] =
13 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Ed Tanousf9273472017-02-28 16:05:13 -080014
Ed Tanous911ac312017-08-15 09:37:42 -070015 size_t input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -080016
Ed Tanous99923322017-03-03 14:21:24 -080017 // allocate space for output string
18 output.clear();
19 output.reserve(((input_length + 2) / 3) * 4);
Ed Tanousf9273472017-02-28 16:05:13 -080020
Ed Tanous99923322017-03-03 14:21:24 -080021 // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
22 // encode using
23 // encoding_data lookup table.
24 // if input do not contains enough chars to complete 3-byte sequence,use pad
25 // char '='
Ed Tanous911ac312017-08-15 09:37:42 -070026 for (size_t i = 0; i < input_length; i++) {
Ed Tanous99923322017-03-03 14:21:24 -080027 int base64code0 = 0;
28 int base64code1 = 0;
29 int base64code2 = 0;
30 int base64code3 = 0;
Ed Tanousf9273472017-02-28 16:05:13 -080031
Ed Tanous99923322017-03-03 14:21:24 -080032 base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
Ed Tanous911ac312017-08-15 09:37:42 -070033
34 output += encoding_data[base64code0]; // NOLINT
Ed Tanous99923322017-03-03 14:21:24 -080035 base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080036
Ed Tanous99923322017-03-03 14:21:24 -080037 if (++i < input_length) {
38 base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
Ed Tanous911ac312017-08-15 09:37:42 -070039 output += encoding_data[base64code1]; // NOLINT
40 base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080041
Ed Tanous99923322017-03-03 14:21:24 -080042 if (++i < input_length) {
43 base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
44 base64code3 = input[i] & 0x3f; // 3-byte 6 bits
Ed Tanous911ac312017-08-15 09:37:42 -070045 output += encoding_data[base64code2]; // NOLINT
46 output += encoding_data[base64code3]; // NOLINT
Ed Tanous99923322017-03-03 14:21:24 -080047 } else {
Ed Tanous911ac312017-08-15 09:37:42 -070048 output += encoding_data[base64code2]; // NOLINT
Ed Tanous99923322017-03-03 14:21:24 -080049 output += '=';
50 }
51 } else {
Ed Tanous911ac312017-08-15 09:37:42 -070052 output += encoding_data[base64code1]; // NOLINT
Ed Tanous99923322017-03-03 14:21:24 -080053 output += '=';
54 output += '=';
Ed Tanousf9273472017-02-28 16:05:13 -080055 }
Ed Tanous99923322017-03-03 14:21:24 -080056 }
Ed Tanousf9273472017-02-28 16:05:13 -080057
Ed Tanous99923322017-03-03 14:21:24 -080058 return true;
Ed Tanousf9273472017-02-28 16:05:13 -080059}
60
Ed Tanous9b65f1f2017-03-07 15:17:13 -080061bool base64_decode(const std::string &input, std::string &output) {
Ed Tanousf9273472017-02-28 16:05:13 -080062 static const char nop = -1;
Ed Tanous911ac312017-08-15 09:37:42 -070063 // See note on encoding_data[] in above function
Ed Tanousf9273472017-02-28 16:05:13 -080064 static const char decoding_data[] = {
Ed Tanous1ff48782017-04-18 12:45:08 -070065 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
66 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
67 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop,
68 nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop,
69 nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
70 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
71 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33,
72 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
73 49, 50, 51, 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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
79 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
80 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
81 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
82 nop};
Ed Tanousf9273472017-02-28 16:05:13 -080083
Ed Tanous911ac312017-08-15 09:37:42 -070084 size_t input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -080085
86 // allocate space for output string
87 output.clear();
88 output.reserve(((input_length + 2) / 3) * 4);
89
90 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
91 // droping first two bits
Ed Tanous911ac312017-08-15 09:37:42 -070092 // and regenerate into 3 8-bits sequences
Ed Tanousf9273472017-02-28 16:05:13 -080093
Ed Tanous911ac312017-08-15 09:37:42 -070094 for (size_t i = 0; i < input_length; i++) {
Ed Tanousf9273472017-02-28 16:05:13 -080095 char base64code0;
96 char base64code1;
Ed Tanous99923322017-03-03 14:21:24 -080097 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanousf9273472017-02-28 16:05:13 -080098 char base64code3;
99
Ed Tanous911ac312017-08-15 09:37:42 -0700100 base64code0 = decoding_data[static_cast<int>(input[i])]; // NOLINT
101 if (base64code0 == nop) { // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800102 return false;
Ed Tanous911ac312017-08-15 09:37:42 -0700103 }
104 if (!(++i < input_length)) { // we need at least two input bytes for first
105 // byte output
Ed Tanousf9273472017-02-28 16:05:13 -0800106 return false;
Ed Tanous911ac312017-08-15 09:37:42 -0700107 }
108 base64code1 = decoding_data[static_cast<int>(input[i])]; // NOLINT
109 if (base64code1 == nop) { // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800110 return false;
Ed Tanous911ac312017-08-15 09:37:42 -0700111 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700112 output +=
113 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Ed Tanousf9273472017-02-28 16:05:13 -0800114
115 if (++i < input_length) {
116 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -0800117 if (c == '=') { // padding , end of input
Ed Tanous911ac312017-08-15 09:37:42 -0700118 return (base64code1 & 0x0f) == 0;
Ed Tanousf9273472017-02-28 16:05:13 -0800119 }
Ed Tanous911ac312017-08-15 09:37:42 -0700120 base64code2 = decoding_data[static_cast<int>(input[i])]; // NOLINT
121 if (base64code2 == nop) { // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800122 return false;
Ed Tanous911ac312017-08-15 09:37:42 -0700123 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700124 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
125 ((base64code2 >> 2) & 0x0f));
Ed Tanousf9273472017-02-28 16:05:13 -0800126 }
127
128 if (++i < input_length) {
129 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -0800130 if (c == '=') { // padding , end of input
Ed Tanous911ac312017-08-15 09:37:42 -0700131 return (base64code2 & 0x03) == 0;
Ed Tanousf9273472017-02-28 16:05:13 -0800132 }
Ed Tanous911ac312017-08-15 09:37:42 -0700133 base64code3 = decoding_data[static_cast<int>(input[i])]; // NOLINT
134 if (base64code3 == nop) { // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800135 return false;
Ed Tanous911ac312017-08-15 09:37:42 -0700136 }
137 output += static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
Ed Tanousf9273472017-02-28 16:05:13 -0800138 }
139 }
140
141 return true;
142}
Ed Tanous911ac312017-08-15 09:37:42 -0700143} // namespace base64