-
Notifications
You must be signed in to change notification settings - Fork 0
/
base64_encoder.cc
131 lines (111 loc) · 3.73 KB
/
base64_encoder.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "base64_encoder.h"
#include <assert.h>
#include "file_util.h"
using namespace uc;
/* Construct a map: {base64 index -> printable ascii code} */
static char base64_apphabet[64];
static int generate_base64_alphabet() noexcept {
int cur = 0;
for (int i = 0; i < 26; ++i)
base64_apphabet[cur++] = 'A' + i;
for (int i = 0; i < 26; ++i)
base64_apphabet[cur++] = 'a' + i;
for (int i = 0; i < 10; ++i)
base64_apphabet[cur++] = '0' + i;
base64_apphabet[cur++] = '+';
base64_apphabet[cur++] = '/';
assert(cur == sizeof base64_apphabet);
return 0;
}
static char GetBase64Char(unsigned char index) noexcept {
assert(index < 64 && index >= 0);
static int dummy = generate_base64_alphabet();
return base64_apphabet[index];
}
/*
* | char 1 | char 2 | char 3 |
* | ****** ** | **** **** | ** ****** |
* | | | | |
*/
static inline unsigned char GetBase64Index1(unsigned char const *raw) noexcept {
return raw[0] >> 2;
}
static inline unsigned char GetBase64Index2(unsigned char const *raw) noexcept {
return ((0x03 & raw[0]) << 4) + (raw[1] >> 4);
}
static inline unsigned char GetBase64Index3(unsigned char const *raw) noexcept {
return ((0x0f & raw[1]) << 2) + (raw[2] >> 6);
}
static inline unsigned char GetBase64Index4(unsigned char const *raw) noexcept {
return 0x3f & raw[2];
}
static inline unsigned char GetBase64IndexPadding1(unsigned char const *raw) noexcept {
return (0x0f & raw[1]) << 2;
}
static inline unsigned char GetBase64IndexPadding2(unsigned char const *raw) noexcept {
return (0x03 & raw[0]) << 4;
}
void Base64Encoder::Encode(void const *raw_data, size_t len, std::string &text, bool newline) {
size_t written = 0;
unsigned char const *binary = (unsigned char const*)raw_data;
auto final_size = size_t((len * 4) / 3.0);
text.reserve(final_size + (newline ?
(final_size / 64 + ((final_size & 63) == 0 ? 0 : 1)) : 0));
size_t i = 0;
/* Avoid underflow
* Not len - i >= 3 */
for (; len >= 3 + i; ) {
text.push_back(GetBase64Char(GetBase64Index1(binary)));
text.push_back(GetBase64Char(GetBase64Index2(binary)));
text.push_back(GetBase64Char(GetBase64Index3(binary)));
text.push_back(GetBase64Char(GetBase64Index4(binary)));
binary += 3;
i += 3;
written += 4;
if (newline && ((written & 63) == 0))
text.push_back('\n');
}
/* | x..x | xx |
* | 3n i len |
* padding = 3 - left = 3 - (len - i) */
int padding = 3 - (len - i);
assert(padding >= 0 && padding <= 3);
if (padding == 1) {
text.push_back(GetBase64Char(GetBase64Index1(binary)));
text.push_back(GetBase64Char(GetBase64Index2(binary)));
text.push_back(GetBase64Char(GetBase64IndexPadding1(binary)));
text.push_back('=');
} else if (padding == 2) {
text.push_back(GetBase64Char(GetBase64Index1(binary)));
text.push_back(GetBase64Char(GetBase64IndexPadding2(binary)));
text.push_back('=');
text.push_back('=');
}
// The last new line don't put only when
// the new line has been put, i.e.,
// the old written % 64 == 0, and the data is empty
if (newline && len > 0 && ((written & 63) != 0))
text.push_back('\n');
}
/** Must be the multipiler of 3 */
static constexpr size_t BUFSIZE = 1024 * 3;
void Base64Encoder::EncodeFromFile(char const *filename, std::string &text, bool newline) {
FILE *fp = fopen(filename, "r");
if (!fp) return;
DeferFclose df(fp);
char buf[BUFSIZE];
size_t count = 0;
for (;;) {
count = fread(buf, 1, sizeof buf, fp);
if (count < sizeof buf) {
if (feof(fp)) {
Encode(buf, count, text, newline);
break;
} else if (ferror(fp)) {
return;
}
}
assert(count == sizeof buf);
Encode(buf, count, text, newline);
}
}