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
18namespace base {
19
20static const char base64Table[] = "ABCDEFGHIJKLMNOP"
21 "QRSTUVWXYZabcdef"
22 "ghijklmnopqrstuv"
23 "wxyz0123456789+/";
24
25static 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
39static inline char base64Char(int index)
40{
41 ASSERT(index >= 0 && index < 64);
42 return base64Table[index];
43}
44
45static 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
54void 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
100void 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
136void 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