blob: 0715a8e56c2ab54ba745690e6a4c173a1a0072f5 [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 {
Ed Tanous9b65f1f2017-03-07 15:17:13 -08005bool base64_encode(const std::string &input, std::string &output) {
Ed Tanous1ff48782017-04-18 12:45:08 -07006 static const char encoding_data[] =
7 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Ed Tanousf9273472017-02-28 16:05:13 -08008
Ed Tanous99923322017-03-03 14:21:24 -08009 unsigned int input_length = input.size();
Ed Tanousf9273472017-02-28 16:05:13 -080010
Ed Tanous99923322017-03-03 14:21:24 -080011 // allocate space for output string
12 output.clear();
13 output.reserve(((input_length + 2) / 3) * 4);
Ed Tanousf9273472017-02-28 16:05:13 -080014
Ed Tanous99923322017-03-03 14:21:24 -080015 // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
16 // encode using
17 // encoding_data lookup table.
18 // if input do not contains enough chars to complete 3-byte sequence,use pad
19 // char '='
20 for (unsigned int i = 0; i < input_length; i++) {
21 int base64code0 = 0;
22 int base64code1 = 0;
23 int base64code2 = 0;
24 int base64code3 = 0;
Ed Tanousf9273472017-02-28 16:05:13 -080025
Ed Tanous99923322017-03-03 14:21:24 -080026 base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
27 output += encoding_data[base64code0];
28 base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080029
Ed Tanous99923322017-03-03 14:21:24 -080030 if (++i < input_length) {
31 base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
32 output += encoding_data[base64code1];
33 base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
Ed Tanousf9273472017-02-28 16:05:13 -080034
Ed Tanous99923322017-03-03 14:21:24 -080035 if (++i < input_length) {
36 base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
37 base64code3 = input[i] & 0x3f; // 3-byte 6 bits
38 output += encoding_data[base64code2];
39 output += encoding_data[base64code3];
40 } else {
41 output += encoding_data[base64code2];
42 output += '=';
43 }
44 } else {
45 output += encoding_data[base64code1];
46 output += '=';
47 output += '=';
Ed Tanousf9273472017-02-28 16:05:13 -080048 }
Ed Tanous99923322017-03-03 14:21:24 -080049 }
Ed Tanousf9273472017-02-28 16:05:13 -080050
Ed Tanous99923322017-03-03 14:21:24 -080051 return true;
Ed Tanousf9273472017-02-28 16:05:13 -080052}
53
Ed Tanous9b65f1f2017-03-07 15:17:13 -080054bool base64_decode(const std::string &input, std::string &output) {
Ed Tanousf9273472017-02-28 16:05:13 -080055 static const char nop = -1;
56 static const char decoding_data[] = {
Ed Tanous1ff48782017-04-18 12:45:08 -070057 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
58 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
59 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop,
60 nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop,
61 nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
62 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
63 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33,
64 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
65 49, 50, 51, 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, nop, nop,
68 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
69 nop, nop, nop, 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};
Ed Tanousf9273472017-02-28 16:05:13 -080075
76 unsigned int input_length = input.size();
77
78 // allocate space for output string
79 output.clear();
80 output.reserve(((input_length + 2) / 3) * 4);
81
82 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
83 // droping first two bits
84 // and regenerate into 3 8-bits sequence
85
86 for (unsigned int i = 0; i < input_length; i++) {
87 char base64code0;
88 char base64code1;
Ed Tanous99923322017-03-03 14:21:24 -080089 char base64code2 = 0; // initialized to 0 to suppress warnings
Ed Tanousf9273472017-02-28 16:05:13 -080090 char base64code3;
91
92 base64code0 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -080093 if (base64code0 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -080094 return false;
Ed Tanous99923322017-03-03 14:21:24 -080095 if (!(++i < input_length)) // we need at least two input bytes for first
96 // byte output
Ed Tanousf9273472017-02-28 16:05:13 -080097 return false;
98 base64code1 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -080099 if (base64code1 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800100 return false;
101
102 output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
103
104 if (++i < input_length) {
105 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -0800106 if (c == '=') { // padding , end of input
Ed Tanousf9273472017-02-28 16:05:13 -0800107 assert((base64code1 & 0x0f) == 0);
108 return true;
109 }
110 base64code2 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -0800111 if (base64code2 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800112 return false;
113
114 output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f);
115 }
116
117 if (++i < input_length) {
118 char c = input[i];
Ed Tanous99923322017-03-03 14:21:24 -0800119 if (c == '=') { // padding , end of input
Ed Tanousf9273472017-02-28 16:05:13 -0800120 assert((base64code2 & 0x03) == 0);
121 return true;
122 }
123 base64code3 = decoding_data[static_cast<int>(input[i])];
Ed Tanous99923322017-03-03 14:21:24 -0800124 if (base64code3 == nop) // non base64 character
Ed Tanousf9273472017-02-28 16:05:13 -0800125 return false;
126
127 output += (((base64code2 << 6) & 0xc0) | base64code3);
128 }
129 }
130
131 return true;
132}
Ed Tanousf9273472017-02-28 16:05:13 -0800133}