blob: 001a4678991ae3ba43b6d8d038d8d54d080bf5d3 [file] [log] [blame]
Ed Tanousf9273472017-02-28 16:05:13 -08001#include <base64.hpp>
2#include <cassert>
3
Ed Tanous99923322017-03-03 14:21:24 -08004namespace base64 {
5bool base64_encode(const gsl::cstring_span<> &input, std::string &output) {
6 static const char encoding_data[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Ed Tanousf9273472017-02-28 16:05:13 -08007
Ed Tanous99923322017-03-03 14:21:24 -08008 unsigned int input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -08009
Ed Tanous99923322017-03-03 14:21:24 -080010 // allocate space for output string
11 output.clear();
12 output.reserve(((input_length + 2) / 3) * 4);
Ed Tanousf9273472017-02-28 16:05:13 -080013
Ed Tanous99923322017-03-03 14:21:24 -080014 // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
15 // encode using
16 // encoding_data lookup table.
17 // if input do not contains enough chars to complete 3-byte sequence,use pad
18 // char '='
19 for (unsigned int i = 0; i < input_length; i++) {
20 int base64code0 = 0;
21 int base64code1 = 0;
22 int base64code2 = 0;
23 int base64code3 = 0;
Ed Tanousf9273472017-02-28 16:05:13 -080024
Ed Tanous99923322017-03-03 14:21:24 -080025 base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
26 output += encoding_data[base64code0];
27 base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080028
Ed Tanous99923322017-03-03 14:21:24 -080029 if (++i < input_length) {
30 base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
31 output += encoding_data[base64code1];
32 base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080033
Ed Tanous99923322017-03-03 14:21:24 -080034 if (++i < input_length) {
35 base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
36 base64code3 = input[i] & 0x3f; // 3-byte 6 bits
37 output += encoding_data[base64code2];
38 output += encoding_data[base64code3];
39 } else {
40 output += encoding_data[base64code2];
41 output += '=';
42 }
43 } else {
44 output += encoding_data[base64code1];
45 output += '=';
46 output += '=';
Ed Tanousf9273472017-02-28 16:05:13 -080047 }
Ed Tanous99923322017-03-03 14:21:24 -080048 }
Ed Tanousf9273472017-02-28 16:05:13 -080049
Ed Tanous99923322017-03-03 14:21:24 -080050 return true;
Ed Tanousf9273472017-02-28 16:05:13 -080051}
52
Ed Tanous99923322017-03-03 14:21:24 -080053bool base64_decode(const gsl::cstring_span<> &input, std::string &output) {
Ed Tanousf9273472017-02-28 16:05:13 -080054 static const char nop = -1;
55 static const char decoding_data[] = {
Ed Tanous99923322017-03-03 14:21:24 -080056 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
57 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
58 nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
59 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
60 45, 46, 47, 48, 49, 50, 51, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
61 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 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, 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, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
64 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop};
Ed Tanousf9273472017-02-28 16:05:13 -080065
66 unsigned int input_length = input.size();
67
68 // allocate space for output string
69 output.clear();
70 output.reserve(((input_length + 2) / 3) * 4);
71
72 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
73 // droping first two bits
74 // and regenerate into 3 8-bits sequence
75
76 for (unsigned int i = 0; i < input_length; i++) {
77 char base64code0;
78 char base64code1;
Ed Tanous99923322017-03-03 14:21:24 -080079 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanousf9273472017-02-28 16:05:13 -080080 char base64code3;
81
82 base64code0 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -080083 if (base64code0 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -080084 return false;
Ed Tanous99923322017-03-03 14:21:24 -080085 if (!(++i < input_length)) // we need at least two input bytes for first
86 // byte output
Ed Tanousf9273472017-02-28 16:05:13 -080087 return false;
88 base64code1 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -080089 if (base64code1 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -080090 return false;
91
92 output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
93
94 if (++i < input_length) {
95 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -080096 if (c == '=') { // padding , end of input
Ed Tanousf9273472017-02-28 16:05:13 -080097 assert((base64code1 & 0x0f) == 0);
98 return true;
99 }
100 base64code2 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -0800101 if (base64code2 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800102 return false;
103
104 output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f);
105 }
106
107 if (++i < input_length) {
108 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -0800109 if (c == '=') { // padding , end of input
Ed Tanousf9273472017-02-28 16:05:13 -0800110 assert((base64code2 & 0x03) == 0);
111 return true;
112 }
113 base64code3 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -0800114 if (base64code3 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800115 return false;
116
117 output += (((base64code2 << 6) & 0xc0) | base64code3);
118 }
119 }
120
121 return true;
122}
Ed Tanousf9273472017-02-28 16:05:13 -0800123}