1 | // LAF Base Library |
2 | // Copyright (c) 2022 Igara Studio S.A. |
3 | // Copyright (c) 2015-2016 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifdef HAVE_CONFIG_H |
9 | #include "config.h" |
10 | #endif |
11 | |
12 | #include "base/base64.h" |
13 | #include "base/debug.h" |
14 | #include "base/ints.h" |
15 | |
16 | #include <cmath> |
17 | |
18 | namespace base { |
19 | |
20 | static const char base64Table[] = "ABCDEFGHIJKLMNOP" |
21 | "QRSTUVWXYZabcdef" |
22 | "ghijklmnopqrstuv" |
23 | "wxyz0123456789+/" ; |
24 | |
25 | static const int invBase64Table[] = { |
26 | // From 32 to 47 '+' '/' |
27 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,62, 0, 0, 0,63, |
28 | // From 48 to 63 '9' |
29 | 52,53,54,55,56,57,58,59,60,61, 0, 0, 0, 0, 0, 0, |
30 | // From 64 to 79 |
31 | 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, |
32 | // From 80 to 95 |
33 | 15,16,17,18,19,20,21,22,23,24,25, 0, 0, 0, 0, 0, |
34 | // From 96 to 111 'o' |
35 | 0,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, |
36 | // From 112 to 122 'z' |
37 | 41,42,43,44,45,46,47,48,49,50,51 }; |
38 | |
39 | static inline char base64Char(int index) |
40 | { |
41 | ASSERT(index >= 0 && index < 64); |
42 | return base64Table[index]; |
43 | } |
44 | |
45 | static inline int base64Inv(int asciiChar) |
46 | { |
47 | asciiChar -= 32; |
48 | if (asciiChar >= 0 && asciiChar < sizeof(invBase64Table)) |
49 | return invBase64Table[asciiChar]; |
50 | else |
51 | return 0; |
52 | } |
53 | |
54 | void encode_base64(const char* input, size_t n, std::string& output) |
55 | { |
56 | size_t size = 4*int(std::ceil(n/3.0)); // Estimate encoded string size |
57 | output.resize(size); |
58 | |
59 | auto outIt = output.begin(); |
60 | auto outEnd = output.end(); |
61 | uint8_t next = 0; |
62 | size_t i = 0; |
63 | size_t j = 0; |
64 | for (; i<n; ++i, ++input) { |
65 | auto inputValue = *input; |
66 | switch (j) { |
67 | case 0: |
68 | *outIt = base64Char((inputValue & 0b11111100) >> 2); |
69 | ++outIt; |
70 | next |= (inputValue & 0b00000011) << 4; |
71 | ++j; |
72 | break; |
73 | case 1: |
74 | *outIt = base64Char(((inputValue & 0b11110000) >> 4) | next); |
75 | ++outIt; |
76 | next = (inputValue & 0b00001111) << 2; |
77 | ++j; |
78 | break; |
79 | case 2: |
80 | *outIt = base64Char(((inputValue & 0b11000000) >> 6) | next); |
81 | ++outIt; |
82 | *outIt = base64Char(inputValue & 0b00111111); |
83 | ++outIt; |
84 | next = 0; |
85 | j = 0; |
86 | break; |
87 | } |
88 | } |
89 | |
90 | if (outIt != outEnd) { |
91 | if (next) { |
92 | *outIt = base64Char(next); |
93 | ++outIt; |
94 | } |
95 | for (; outIt!=outEnd; ++outIt) |
96 | *outIt = '='; // Padding |
97 | } |
98 | } |
99 | |
100 | void decode_base64(const char* input, size_t n, buffer& output) |
101 | { |
102 | size_t size = 3*int(std::ceil(n/4.0)); // Estimate decoded buffer size |
103 | output.resize(size); |
104 | |
105 | auto outIt = output.begin(); |
106 | auto outEnd = output.end(); |
107 | size_t i = 0; |
108 | for (; i+3<n; i+=4, input+=4) { |
109 | *outIt = (((base64Inv(input[0]) ) << 2) | |
110 | ((base64Inv(input[1]) & 0b110000) >> 4)); |
111 | ++outIt; |
112 | |
113 | if (input[2] == '=') { |
114 | size -= 2; |
115 | break; |
116 | } |
117 | |
118 | *outIt = (((base64Inv(input[1]) & 0b001111) << 4) | |
119 | ((base64Inv(input[2]) & 0b111100) >> 2)); |
120 | ++outIt; |
121 | |
122 | if (input[3] == '=') { |
123 | --size; |
124 | break; |
125 | } |
126 | |
127 | *outIt = (((base64Inv(input[2]) & 0b000011) << 6) | |
128 | ((base64Inv(input[3]) ))); |
129 | ++outIt; |
130 | } |
131 | |
132 | if (output.size() > size) |
133 | output.resize(size); |
134 | } |
135 | |
136 | void decode_base64(const char* input, size_t n, std::string& output) |
137 | { |
138 | buffer tmp; |
139 | decode_base64(input, n, tmp); |
140 | output = std::string((const char*)&tmp[0], tmp.size()); |
141 | } |
142 | |
143 | } // namespace base |
144 | |