Line data Source code
1 :
2 : //*********************************************************************
3 : //* Base64 - a simple base64 encoder and decoder.
4 : //*
5 : //* Copyright (c) 1999, Bob Withers - bwit@pobox.com
6 : //*
7 : //* This code may be freely used for any purpose, either personal
8 : //* or commercial, provided the authors copyright notice remains
9 : //* intact.
10 : //*
11 : //* Enhancements by Stanley Yamane:
12 : //* o reverse lookup table for the decode function
13 : //* o reserve string buffer space in advance
14 : //*
15 : //*********************************************************************
16 :
17 : #include "webrtc/base/base64.h"
18 :
19 : #include <string.h>
20 :
21 : #include "webrtc/base/checks.h"
22 :
23 : using std::vector;
24 :
25 : namespace rtc {
26 :
27 : static const char kPad = '=';
28 : static const unsigned char pd = 0xFD; // Padding
29 : static const unsigned char sp = 0xFE; // Whitespace
30 : static const unsigned char il = 0xFF; // Illegal base64 character
31 :
32 : const char Base64::Base64Table[] =
33 : // 0000000000111111111122222222223333333333444444444455555555556666
34 : // 0123456789012345678901234567890123456789012345678901234567890123
35 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
36 :
37 : // Decode Table gives the index of any valid base64 character in the
38 : // Base64 table
39 : // 65 == A, 97 == a, 48 == 0, 43 == +, 47 == /
40 :
41 : const unsigned char Base64::DecodeTable[] = {
42 : // 0 1 2 3 4 5 6 7 8 9
43 : il, il, il, il, il, il, il, il, il, sp, // 0 - 9
44 : sp, sp, sp, sp, il, il, il, il, il, il, // 10 - 19
45 : il, il, il, il, il, il, il, il, il, il, // 20 - 29
46 : il, il, sp, il, il, il, il, il, il, il, // 30 - 39
47 : il, il, il, 62, il, il, il, 63, 52, 53, // 40 - 49
48 : 54, 55, 56, 57, 58, 59, 60, 61, il, il, // 50 - 59
49 : il, pd, il, il, il, 0, 1, 2, 3, 4, // 60 - 69
50 : 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 70 - 79
51 : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 80 - 89
52 : 25, il, il, il, il, il, il, 26, 27, 28, // 90 - 99
53 : 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // 100 - 109
54 : 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, // 110 - 119
55 : 49, 50, 51, il, il, il, il, il, il, il, // 120 - 129
56 : il, il, il, il, il, il, il, il, il, il, // 130 - 139
57 : il, il, il, il, il, il, il, il, il, il, // 140 - 149
58 : il, il, il, il, il, il, il, il, il, il, // 150 - 159
59 : il, il, il, il, il, il, il, il, il, il, // 160 - 169
60 : il, il, il, il, il, il, il, il, il, il, // 170 - 179
61 : il, il, il, il, il, il, il, il, il, il, // 180 - 189
62 : il, il, il, il, il, il, il, il, il, il, // 190 - 199
63 : il, il, il, il, il, il, il, il, il, il, // 200 - 209
64 : il, il, il, il, il, il, il, il, il, il, // 210 - 219
65 : il, il, il, il, il, il, il, il, il, il, // 220 - 229
66 : il, il, il, il, il, il, il, il, il, il, // 230 - 239
67 : il, il, il, il, il, il, il, il, il, il, // 240 - 249
68 : il, il, il, il, il, il // 250 - 255
69 : };
70 :
71 0 : bool Base64::IsBase64Char(char ch) {
72 0 : return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z')) ||
73 0 : (('0' <= ch) && (ch <= '9')) || (ch == '+') || (ch == '/');
74 : }
75 :
76 0 : bool Base64::GetNextBase64Char(char ch, char* next_ch) {
77 0 : if (next_ch == NULL) {
78 0 : return false;
79 : }
80 0 : const char* p = strchr(Base64Table, ch);
81 0 : if (!p)
82 0 : return false;
83 0 : ++p;
84 0 : *next_ch = (*p) ? *p : Base64Table[0];
85 0 : return true;
86 : }
87 :
88 0 : bool Base64::IsBase64Encoded(const std::string& str) {
89 0 : for (size_t i = 0; i < str.size(); ++i) {
90 0 : if (!IsBase64Char(str.at(i)))
91 0 : return false;
92 : }
93 0 : return true;
94 : }
95 :
96 0 : void Base64::EncodeFromArray(const void* data,
97 : size_t len,
98 : std::string* result) {
99 0 : RTC_DCHECK(NULL != result);
100 0 : result->clear();
101 0 : result->resize(((len + 2) / 3) * 4);
102 0 : const unsigned char* byte_data = static_cast<const unsigned char*>(data);
103 :
104 : unsigned char c;
105 0 : size_t i = 0;
106 0 : size_t dest_ix = 0;
107 0 : while (i < len) {
108 0 : c = (byte_data[i] >> 2) & 0x3f;
109 0 : (*result)[dest_ix++] = Base64Table[c];
110 :
111 0 : c = (byte_data[i] << 4) & 0x3f;
112 0 : if (++i < len) {
113 0 : c |= (byte_data[i] >> 4) & 0x0f;
114 : }
115 0 : (*result)[dest_ix++] = Base64Table[c];
116 :
117 0 : if (i < len) {
118 0 : c = (byte_data[i] << 2) & 0x3f;
119 0 : if (++i < len) {
120 0 : c |= (byte_data[i] >> 6) & 0x03;
121 : }
122 0 : (*result)[dest_ix++] = Base64Table[c];
123 : } else {
124 0 : (*result)[dest_ix++] = kPad;
125 : }
126 :
127 0 : if (i < len) {
128 0 : c = byte_data[i] & 0x3f;
129 0 : (*result)[dest_ix++] = Base64Table[c];
130 0 : ++i;
131 : } else {
132 0 : (*result)[dest_ix++] = kPad;
133 : }
134 : }
135 0 : }
136 :
137 0 : size_t Base64::GetNextQuantum(DecodeFlags parse_flags,
138 : bool illegal_pads,
139 : const char* data,
140 : size_t len,
141 : size_t* dpos,
142 : unsigned char qbuf[4],
143 : bool* padded) {
144 0 : size_t byte_len = 0, pad_len = 0, pad_start = 0;
145 0 : for (; (byte_len < 4) && (*dpos < len); ++*dpos) {
146 0 : qbuf[byte_len] = DecodeTable[static_cast<unsigned char>(data[*dpos])];
147 0 : if ((il == qbuf[byte_len]) || (illegal_pads && (pd == qbuf[byte_len]))) {
148 0 : if (parse_flags != DO_PARSE_ANY)
149 0 : break;
150 : // Ignore illegal characters
151 0 : } else if (sp == qbuf[byte_len]) {
152 0 : if (parse_flags == DO_PARSE_STRICT)
153 0 : break;
154 : // Ignore spaces
155 0 : } else if (pd == qbuf[byte_len]) {
156 0 : if (byte_len < 2) {
157 0 : if (parse_flags != DO_PARSE_ANY)
158 0 : break;
159 : // Ignore unexpected padding
160 0 : } else if (byte_len + pad_len >= 4) {
161 0 : if (parse_flags != DO_PARSE_ANY)
162 0 : break;
163 : // Ignore extra pads
164 : } else {
165 0 : if (1 == ++pad_len) {
166 0 : pad_start = *dpos;
167 : }
168 : }
169 : } else {
170 0 : if (pad_len > 0) {
171 0 : if (parse_flags != DO_PARSE_ANY)
172 0 : break;
173 : // Ignore pads which are followed by data
174 0 : pad_len = 0;
175 : }
176 0 : ++byte_len;
177 : }
178 : }
179 0 : for (size_t i = byte_len; i < 4; ++i) {
180 0 : qbuf[i] = 0;
181 : }
182 0 : if (4 == byte_len + pad_len) {
183 0 : *padded = true;
184 : } else {
185 0 : *padded = false;
186 0 : if (pad_len) {
187 : // Roll back illegal padding
188 0 : *dpos = pad_start;
189 : }
190 : }
191 0 : return byte_len;
192 : }
193 :
194 0 : bool Base64::DecodeFromArray(const char* data,
195 : size_t len,
196 : DecodeFlags flags,
197 : std::string* result,
198 : size_t* data_used) {
199 : return DecodeFromArrayTemplate<std::string>(data, len, flags, result,
200 0 : data_used);
201 : }
202 :
203 0 : bool Base64::DecodeFromArray(const char* data,
204 : size_t len,
205 : DecodeFlags flags,
206 : vector<char>* result,
207 : size_t* data_used) {
208 : return DecodeFromArrayTemplate<vector<char>>(data, len, flags, result,
209 0 : data_used);
210 : }
211 :
212 0 : bool Base64::DecodeFromArray(const char* data,
213 : size_t len,
214 : DecodeFlags flags,
215 : vector<uint8_t>* result,
216 : size_t* data_used) {
217 : return DecodeFromArrayTemplate<vector<uint8_t>>(data, len, flags, result,
218 0 : data_used);
219 : }
220 :
221 : template <typename T>
222 0 : bool Base64::DecodeFromArrayTemplate(const char* data,
223 : size_t len,
224 : DecodeFlags flags,
225 : T* result,
226 : size_t* data_used) {
227 0 : RTC_DCHECK(NULL != result);
228 0 : RTC_DCHECK(flags <= (DO_PARSE_MASK | DO_PAD_MASK | DO_TERM_MASK));
229 :
230 0 : const DecodeFlags parse_flags = flags & DO_PARSE_MASK;
231 0 : const DecodeFlags pad_flags = flags & DO_PAD_MASK;
232 0 : const DecodeFlags term_flags = flags & DO_TERM_MASK;
233 0 : RTC_DCHECK(0 != parse_flags);
234 0 : RTC_DCHECK(0 != pad_flags);
235 0 : RTC_DCHECK(0 != term_flags);
236 :
237 0 : result->clear();
238 0 : result->reserve(len);
239 :
240 0 : size_t dpos = 0;
241 0 : bool success = true, padded;
242 : unsigned char c, qbuf[4];
243 0 : while (dpos < len) {
244 0 : size_t qlen = GetNextQuantum(parse_flags, (DO_PAD_NO == pad_flags), data,
245 0 : len, &dpos, qbuf, &padded);
246 0 : c = (qbuf[0] << 2) | ((qbuf[1] >> 4) & 0x3);
247 0 : if (qlen >= 2) {
248 0 : result->push_back(c);
249 0 : c = ((qbuf[1] << 4) & 0xf0) | ((qbuf[2] >> 2) & 0xf);
250 0 : if (qlen >= 3) {
251 0 : result->push_back(c);
252 0 : c = ((qbuf[2] << 6) & 0xc0) | qbuf[3];
253 0 : if (qlen >= 4) {
254 0 : result->push_back(c);
255 0 : c = 0;
256 : }
257 : }
258 : }
259 0 : if (qlen < 4) {
260 0 : if ((DO_TERM_ANY != term_flags) && (0 != c)) {
261 0 : success = false; // unused bits
262 : }
263 0 : if ((DO_PAD_YES == pad_flags) && !padded) {
264 0 : success = false; // expected padding
265 : }
266 0 : break;
267 : }
268 : }
269 0 : if ((DO_TERM_BUFFER == term_flags) && (dpos != len)) {
270 0 : success = false; // unused chars
271 : }
272 0 : if (data_used) {
273 0 : *data_used = dpos;
274 : }
275 0 : return success;
276 : }
277 :
278 : } // namespace rtc
|