• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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