1 #include "strings/escaping.h"
2
3 #include <cassert>
4
5 #include "android-base/logging.h"
6 #include "strings/ascii_ctype.h"
7
8 namespace dynamic_depth {
9
10 // ----------------------------------------------------------------------
11 // ptrdiff_t Base64Unescape() - base64 decoder
12 // ptrdiff_t Base64Escape() - base64 encoder
13 // ptrdiff_t WebSafeBase64Unescape() - Google's variation of base64 decoder
14 // ptrdiff_t WebSafeBase64Escape() - Google's variation of base64 encoder
15 //
16 // Check out
17 // http://tools.ietf.org/html/rfc2045 for formal description, but what we
18 // care about is that...
19 // Take the encoded stuff in groups of 4 characters and turn each
20 // character into a code 0 to 63 thus:
21 // A-Z map to 0 to 25
22 // a-z map to 26 to 51
23 // 0-9 map to 52 to 61
24 // +(- for WebSafe) maps to 62
25 // /(_ for WebSafe) maps to 63
26 // There will be four numbers, all less than 64 which can be represented
27 // by a 6 digit binary number (aaaaaa, bbbbbb, cccccc, dddddd respectively).
28 // Arrange the 6 digit binary numbers into three bytes as such:
29 // aaaaaabb bbbbcccc ccdddddd
30 // Equals signs (one or two) are used at the end of the encoded block to
31 // indicate that the text was not an integer multiple of three bytes long.
32 // ----------------------------------------------------------------------
33
Base64UnescapeInternal(const char * src_param,size_t szsrc,char * dest,size_t szdest,const signed char * unbase64,size_t * len)34 bool Base64UnescapeInternal(const char* src_param, size_t szsrc, char* dest,
35 size_t szdest, const signed char* unbase64,
36 size_t* len) {
37 static const char kPad64Equals = '=';
38 static const char kPad64Dot = '.';
39
40 size_t destidx = 0;
41 int decode = 0;
42 int state = 0;
43 unsigned int ch = 0;
44 unsigned int temp = 0;
45
46 // If "char" is signed by default, using *src as an array index results in
47 // accessing negative array elements. Treat the input as a pointer to
48 // unsigned char to avoid this.
49 const unsigned char* src = reinterpret_cast<const unsigned char*>(src_param);
50
51 // The GET_INPUT macro gets the next input character, skipping
52 // over any whitespace, and stopping when we reach the end of the
53 // string or when we read any non-data character. The arguments are
54 // an arbitrary identifier (used as a label for goto) and the number
55 // of data bytes that must remain in the input to avoid aborting the
56 // loop.
57 #define GET_INPUT(label, remain) \
58 label: \
59 --szsrc; \
60 ch = *src++; \
61 decode = unbase64[ch]; \
62 if (decode < 0) { \
63 if (ascii_isspace(ch) && szsrc >= remain) goto label; \
64 state = 4 - remain; \
65 break; \
66 }
67
68 // if dest is null, we're just checking to see if it's legal input
69 // rather than producing output. (I suspect this could just be done
70 // with a regexp...). We duplicate the loop so this test can be
71 // outside it instead of in every iteration.
72
73 if (dest) {
74 // This loop consumes 4 input bytes and produces 3 output bytes
75 // per iteration. We can't know at the start that there is enough
76 // data left in the string for a full iteration, so the loop may
77 // break out in the middle; if so 'state' will be set to the
78 // number of input bytes read.
79
80 while (szsrc >= 4) {
81 // We'll start by optimistically assuming that the next four
82 // bytes of the string (src[0..3]) are four good data bytes
83 // (that is, no nulls, whitespace, padding chars, or illegal
84 // chars). We need to test src[0..2] for nulls individually
85 // before constructing temp to preserve the property that we
86 // never read past a null in the string (no matter how long
87 // szsrc claims the string is).
88
89 if (!src[0] || !src[1] || !src[2] ||
90 ((temp = ((unsigned(unbase64[src[0]]) << 18) |
91 (unsigned(unbase64[src[1]]) << 12) |
92 (unsigned(unbase64[src[2]]) << 6) |
93 (unsigned(unbase64[src[3]])))) &
94 0x80000000)) {
95 // Iff any of those four characters was bad (null, illegal,
96 // whitespace, padding), then temp's high bit will be set
97 // (because unbase64[] is -1 for all bad characters).
98 //
99 // We'll back up and resort to the slower decoder, which knows
100 // how to handle those cases.
101
102 GET_INPUT(first, 4);
103 temp = decode;
104 GET_INPUT(second, 3);
105 temp = (temp << 6) | decode;
106 GET_INPUT(third, 2);
107 temp = (temp << 6) | decode;
108 GET_INPUT(fourth, 1);
109 temp = (temp << 6) | decode;
110 } else {
111 // We really did have four good data bytes, so advance four
112 // characters in the string.
113
114 szsrc -= 4;
115 src += 4;
116 decode = -1;
117 ch = '\0';
118 }
119
120 // temp has 24 bits of input, so write that out as three bytes.
121
122 if (destidx + 3 > szdest) return false;
123 dest[destidx + 2] = temp;
124 temp >>= 8;
125 dest[destidx + 1] = temp;
126 temp >>= 8;
127 dest[destidx] = temp;
128 destidx += 3;
129 }
130 } else {
131 while (szsrc >= 4) {
132 if (!src[0] || !src[1] || !src[2] ||
133 ((temp = ((unsigned(unbase64[src[0]]) << 18) |
134 (unsigned(unbase64[src[1]]) << 12) |
135 (unsigned(unbase64[src[2]]) << 6) |
136 (unsigned(unbase64[src[3]])))) &
137 0x80000000)) {
138 GET_INPUT(first_no_dest, 4);
139 GET_INPUT(second_no_dest, 3);
140 GET_INPUT(third_no_dest, 2);
141 GET_INPUT(fourth_no_dest, 1);
142 } else {
143 szsrc -= 4;
144 src += 4;
145 decode = -1;
146 ch = '\0';
147 }
148 destidx += 3;
149 }
150 }
151
152 #undef GET_INPUT
153
154 // if the loop terminated because we read a bad character, return
155 // now.
156 if (decode < 0 && ch != '\0' && ch != kPad64Equals && ch != kPad64Dot &&
157 !ascii_isspace(ch))
158 return false;
159
160 if (ch == kPad64Equals || ch == kPad64Dot) {
161 // if we stopped by hitting an '=' or '.', un-read that character -- we'll
162 // look at it again when we count to check for the proper number of
163 // equals signs at the end.
164 ++szsrc;
165 --src;
166 } else {
167 // This loop consumes 1 input byte per iteration. It's used to
168 // clean up the 0-3 input bytes remaining when the first, faster
169 // loop finishes. 'temp' contains the data from 'state' input
170 // characters read by the first loop.
171 while (szsrc > 0) {
172 --szsrc;
173 ch = *src++;
174 decode = unbase64[ch];
175 if (decode < 0) {
176 if (ascii_isspace(ch)) {
177 continue;
178 } else if (ch == '\0') {
179 break;
180 } else if (ch == kPad64Equals || ch == kPad64Dot) {
181 // back up one character; we'll read it again when we check
182 // for the correct number of pad characters at the end.
183 ++szsrc;
184 --src;
185 break;
186 } else {
187 return false;
188 }
189 }
190
191 // Each input character gives us six bits of output.
192 temp = (temp << 6) | decode;
193 ++state;
194 if (state == 4) {
195 // If we've accumulated 24 bits of output, write that out as
196 // three bytes.
197 if (dest) {
198 if (destidx + 3 > szdest) return false;
199 dest[destidx + 2] = temp;
200 temp >>= 8;
201 dest[destidx + 1] = temp;
202 temp >>= 8;
203 dest[destidx] = temp;
204 }
205 destidx += 3;
206 state = 0;
207 temp = 0;
208 }
209 }
210 }
211
212 // Process the leftover data contained in 'temp' at the end of the input.
213 int expected_equals = 0;
214 switch (state) {
215 case 0:
216 // Nothing left over; output is a multiple of 3 bytes.
217 break;
218
219 case 1:
220 // Bad input; we have 6 bits left over.
221 return false;
222
223 case 2:
224 // Produce one more output byte from the 12 input bits we have left.
225 if (dest) {
226 if (destidx + 1 > szdest) return false;
227 temp >>= 4;
228 dest[destidx] = temp;
229 }
230 ++destidx;
231 expected_equals = 2;
232 break;
233
234 case 3:
235 // Produce two more output bytes from the 18 input bits we have left.
236 if (dest) {
237 if (destidx + 2 > szdest) return false;
238 temp >>= 2;
239 dest[destidx + 1] = temp;
240 temp >>= 8;
241 dest[destidx] = temp;
242 }
243 destidx += 2;
244 expected_equals = 1;
245 break;
246
247 default:
248 // state should have no other values at this point.
249 LOG(FATAL) << "This can't happen; base64 decoder state = " << state;
250 }
251
252 // The remainder of the string should be all whitespace, mixed with
253 // exactly 0 equals signs, or exactly 'expected_equals' equals
254 // signs. (Always accepting 0 equals signs is a google extension
255 // not covered in the RFC, as is accepting dot as the pad character.)
256
257 int equals = 0;
258 while (szsrc > 0 && *src) {
259 if (*src == kPad64Equals || *src == kPad64Dot)
260 ++equals;
261 else if (!ascii_isspace(*src))
262 return false;
263 --szsrc;
264 ++src;
265 }
266
267 const bool ok = (equals == 0 || equals == expected_equals);
268 if (ok) *len = destidx;
269 return ok;
270 }
271
272 // The arrays below were generated by the following code
273 // #include <sys/time.h>
274 // #include <stdlib.h>
275 // #include <string.h>
276 // main()
277 // {
278 // static const char Base64[] =
279 // "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
280 // char* pos;
281 // int idx, i, j;
282 // printf(" ");
283 // for (i = 0; i < 255; i += 8) {
284 // for (j = i; j < i + 8; j++) {
285 // pos = strchr(Base64, j);
286 // if ((pos == NULL) || (j == 0))
287 // idx = -1;
288 // else
289 // idx = pos - Base64;
290 // if (idx == -1)
291 // printf(" %2d, ", idx);
292 // else
293 // printf(" %2d/*%c*/,", idx, j);
294 // }
295 // printf("\n ");
296 // }
297 // }
298 //
299 // where the value of "Base64[]" was replaced by one of the base-64 conversion
300 // tables from the functions below.
301 static const signed char kUnBase64[] = {
302 -1, -1, -1, -1, -1, -1, -1,
303 -1, -1, -1, -1, -1, -1, -1,
304 -1, -1, -1, -1, -1, -1, -1,
305 -1, -1, -1, -1, -1, -1, -1,
306 -1, -1, -1, -1, -1, -1, -1,
307 -1, -1, -1, -1, -1, -1, -1,
308 -1, 62 /*+*/, -1, -1, -1, 63 /*/ */, 52 /*0*/,
309 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/,
310 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1,
311 -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/,
312 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/,
313 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/,
314 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/,
315 -1, -1, -1, -1, -1, -1, 26 /*a*/,
316 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/,
317 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/,
318 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/,
319 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1,
320 -1, -1, -1, -1, -1, -1, -1,
321 -1, -1, -1, -1, -1, -1, -1,
322 -1, -1, -1, -1, -1, -1, -1,
323 -1, -1, -1, -1, -1, -1, -1,
324 -1, -1, -1, -1, -1, -1, -1,
325 -1, -1, -1, -1, -1, -1, -1,
326 -1, -1, -1, -1, -1, -1, -1,
327 -1, -1, -1, -1, -1, -1, -1,
328 -1, -1, -1, -1, -1, -1, -1,
329 -1, -1, -1, -1, -1, -1, -1,
330 -1, -1, -1, -1, -1, -1, -1,
331 -1, -1, -1, -1, -1, -1, -1,
332 -1, -1, -1, -1, -1, -1, -1,
333 -1, -1, -1, -1, -1, -1, -1,
334 -1, -1, -1, -1, -1, -1, -1,
335 -1, -1, -1, -1, -1, -1, -1,
336 -1, -1, -1, -1, -1, -1, -1,
337 -1, -1, -1, -1, -1, -1, -1,
338 -1, -1, -1, -1};
339 static const signed char kUnWebSafeBase64[] = {
340 -1, -1, -1, -1, -1, -1, -1,
341 -1, -1, -1, -1, -1, -1, -1,
342 -1, -1, -1, -1, -1, -1, -1,
343 -1, -1, -1, -1, -1, -1, -1,
344 -1, -1, -1, -1, -1, -1, -1,
345 -1, -1, -1, -1, -1, -1, -1,
346 -1, -1, -1, 62 /*-*/, -1, -1, 52 /*0*/,
347 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/,
348 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1,
349 -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/,
350 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/,
351 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/,
352 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/,
353 -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/,
354 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/,
355 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/,
356 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/,
357 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1,
358 -1, -1, -1, -1, -1, -1, -1,
359 -1, -1, -1, -1, -1, -1, -1,
360 -1, -1, -1, -1, -1, -1, -1,
361 -1, -1, -1, -1, -1, -1, -1,
362 -1, -1, -1, -1, -1, -1, -1,
363 -1, -1, -1, -1, -1, -1, -1,
364 -1, -1, -1, -1, -1, -1, -1,
365 -1, -1, -1, -1, -1, -1, -1,
366 -1, -1, -1, -1, -1, -1, -1,
367 -1, -1, -1, -1, -1, -1, -1,
368 -1, -1, -1, -1, -1, -1, -1,
369 -1, -1, -1, -1, -1, -1, -1,
370 -1, -1, -1, -1, -1, -1, -1,
371 -1, -1, -1, -1, -1, -1, -1,
372 -1, -1, -1, -1, -1, -1, -1,
373 -1, -1, -1, -1, -1, -1, -1,
374 -1, -1, -1, -1, -1, -1, -1,
375 -1, -1, -1, -1, -1, -1, -1,
376 -1, -1, -1, -1};
377
Base64UnescapeInternal(const char * src,size_t slen,string * dest,const signed char * unbase64)378 static bool Base64UnescapeInternal(const char* src, size_t slen, string* dest,
379 const signed char* unbase64) {
380 // Determine the size of the output string. Base64 encodes every 3 bytes into
381 // 4 characters. any leftover chars are added directly for good measure.
382 // This is documented in the base64 RFC: http://tools.ietf.org/html/rfc3548
383 const size_t dest_len = 3 * (slen / 4) + (slen % 4);
384
385 dest->resize(dest_len);
386
387 // We are getting the destination buffer by getting the beginning of the
388 // string and converting it into a char *.
389 size_t len;
390 const bool ok =
391 Base64UnescapeInternal(src, slen, dest->empty() ? NULL : &*dest->begin(),
392 dest_len, unbase64, &len);
393 if (!ok) {
394 dest->clear();
395 return false;
396 }
397
398 // could be shorter if there was padding
399 DCHECK_LE(len, dest_len);
400 dest->erase(len);
401
402 return true;
403 }
404
Base64Unescape(const string & src,string * dest)405 bool Base64Unescape(const string& src, string* dest) {
406 return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
407 }
408
WebSafeBase64Unescape(const string & src,string * dest)409 bool WebSafeBase64Unescape(const string& src, string* dest) {
410 return Base64UnescapeInternal(src.data(), src.size(), dest, kUnWebSafeBase64);
411 }
412
413 // Base64Escape
414 //
415 // NOTE: We have to use an unsigned type for src because code built
416 // in the the /google tree treats characters as signed unless
417 // otherwised specified.
Base64EscapeInternal(const unsigned char * src,int szsrc,char * dest,int szdest,const char * base64,bool do_padding)418 int Base64EscapeInternal(const unsigned char* src, int szsrc, char* dest,
419 int szdest, const char* base64, bool do_padding) {
420 static const char kPad64 = '=';
421
422 if (szsrc <= 0) return 0;
423
424 char* cur_dest = dest;
425 const unsigned char* cur_src = src;
426
427 // Three bytes of data encodes to four characters of cyphertext.
428 // So we can pump through three-byte chunks atomically.
429 while (szsrc > 2) { /* keep going until we have less than 24 bits */
430 if ((szdest -= 4) < 0) return 0;
431 cur_dest[0] = base64[cur_src[0] >> 2];
432 cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
433 cur_dest[2] = base64[((cur_src[1] & 0x0f) << 2) + (cur_src[2] >> 6)];
434 cur_dest[3] = base64[cur_src[2] & 0x3f];
435
436 cur_dest += 4;
437 cur_src += 3;
438 szsrc -= 3;
439 }
440
441 /* now deal with the tail (<=2 bytes) */
442 switch (szsrc) {
443 case 0:
444 // Nothing left; nothing more to do.
445 break;
446 case 1:
447 // One byte left: this encodes to two characters, and (optionally)
448 // two pad characters to round out the four-character cypherblock.
449 if ((szdest -= 2) < 0) return 0;
450 cur_dest[0] = base64[cur_src[0] >> 2];
451 cur_dest[1] = base64[(cur_src[0] & 0x03) << 4];
452 cur_dest += 2;
453 if (do_padding) {
454 if ((szdest -= 2) < 0) return 0;
455 cur_dest[0] = kPad64;
456 cur_dest[1] = kPad64;
457 cur_dest += 2;
458 }
459 break;
460 case 2:
461 // Two bytes left: this encodes to three characters, and (optionally)
462 // one pad character to round out the four-character cypherblock.
463 if ((szdest -= 3) < 0) return 0;
464 cur_dest[0] = base64[cur_src[0] >> 2];
465 cur_dest[1] = base64[((cur_src[0] & 0x03) << 4) + (cur_src[1] >> 4)];
466 cur_dest[2] = base64[(cur_src[1] & 0x0f) << 2];
467 cur_dest += 3;
468 if (do_padding) {
469 if ((szdest -= 1) < 0) return 0;
470 cur_dest[0] = kPad64;
471 cur_dest += 1;
472 }
473 break;
474 default:
475 // Should not be reached: blocks of 3 bytes are handled
476 // in the while loop before this switch statement.
477 CHECK(false) << "Logic problem? szsrc = " << szsrc;
478 break;
479 }
480 return (cur_dest - dest);
481 }
482
483 static const char kBase64Chars[] =
484 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
485
486 // Digit conversion.
487 static const char kHexTable[513] =
488 "000102030405060708090a0b0c0d0e0f"
489 "101112131415161718191a1b1c1d1e1f"
490 "202122232425262728292a2b2c2d2e2f"
491 "303132333435363738393a3b3c3d3e3f"
492 "404142434445464748494a4b4c4d4e4f"
493 "505152535455565758595a5b5c5d5e5f"
494 "606162636465666768696a6b6c6d6e6f"
495 "707172737475767778797a7b7c7d7e7f"
496 "808182838485868788898a8b8c8d8e8f"
497 "909192939495969798999a9b9c9d9e9f"
498 "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
499 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
500 "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
501 "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
502 "e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
503 "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
504
CalculateBase64EscapedLenInternal(size_t input_len,bool do_padding)505 size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
506 // Base64 encodes three bytes of input at a time. If the input is not
507 // divisible by three, we pad as appropriate.
508 //
509 // (from http://tools.ietf.org/html/rfc3548)
510 // Special processing is performed if fewer than 24 bits are available
511 // at the end of the data being encoded. A full encoding quantum is
512 // always completed at the end of a quantity. When fewer than 24 input
513 // bits are available in an input group, zero bits are added (on the
514 // right) to form an integral number of 6-bit groups. Padding at the
515 // end of the data is performed using the '=' character. Since all base
516 // 64 input is an integral number of octets, only the following cases
517 // can arise:
518
519 // Base64 encodes each three bytes of input into four bytes of output.
520 size_t len = (input_len / 3) * 4;
521
522 if (input_len % 3 == 0) {
523 // (from http://tools.ietf.org/html/rfc3548)
524 // (1) the final quantum of encoding input is an integral multiple of 24
525 // bits; here, the final unit of encoded output will be an integral
526 // multiple of 4 characters with no "=" padding,
527 } else if (input_len % 3 == 1) {
528 // (from http://tools.ietf.org/html/rfc3548)
529 // (2) the final quantum of encoding input is exactly 8 bits; here, the
530 // final unit of encoded output will be two characters followed by two
531 // "=" padding characters, or
532 len += 2;
533 if (do_padding) {
534 len += 2;
535 }
536 } else { // (input_len % 3 == 2)
537 // (from http://tools.ietf.org/html/rfc3548)
538 // (3) the final quantum of encoding input is exactly 16 bits; here, the
539 // final unit of encoded output will be three characters followed by one
540 // "=" padding character.
541 len += 3;
542 if (do_padding) {
543 len += 1;
544 }
545 }
546
547 assert(len >= input_len); // make sure we didn't overflow
548 return len;
549 }
550
Base64EscapeInternal(const unsigned char * src,size_t szsrc,string * dest,bool do_padding,const char * base64_chars)551 void Base64EscapeInternal(const unsigned char* src, size_t szsrc, string* dest,
552 bool do_padding, const char* base64_chars) {
553 const size_t calc_escaped_size =
554 CalculateBase64EscapedLenInternal(szsrc, do_padding);
555 dest->resize(calc_escaped_size);
556 const int escaped_len = Base64EscapeInternal(
557 src, static_cast<int>(szsrc), dest->empty() ? NULL : &*dest->begin(),
558 static_cast<int>(dest->size()), base64_chars, do_padding);
559 DCHECK_EQ(calc_escaped_size, escaped_len);
560 dest->erase(escaped_len);
561 }
562
Base64Escape(const unsigned char * src,ptrdiff_t szsrc,string * dest,bool do_padding)563 void Base64Escape(const unsigned char* src, ptrdiff_t szsrc, string* dest,
564 bool do_padding) {
565 if (szsrc < 0) return;
566 Base64EscapeInternal(src, szsrc, dest, do_padding, kBase64Chars);
567 }
568
569 // This is a templated function so that T can be either a char* or a string.
570 template <typename T>
b2a_hex_t(const unsigned char * src,T dest,ptrdiff_t num)571 static void b2a_hex_t(const unsigned char* src, T dest, ptrdiff_t num) {
572 auto dest_ptr = &dest[0];
573 for (auto src_ptr = src; src_ptr != (src + num); ++src_ptr, dest_ptr += 2) {
574 const char* hex_p = &kHexTable[*src_ptr * 2];
575 std::copy(hex_p, hex_p + 2, dest_ptr);
576 }
577 }
578
b2a_hex(const char * b,ptrdiff_t len)579 string b2a_hex(const char* b, ptrdiff_t len) {
580 string result;
581 result.resize(len << 1);
582 b2a_hex_t<string&>(reinterpret_cast<const unsigned char*>(b), result, len);
583 return result;
584 }
585
586 } // namespace dynamic_depth
587