Home | History | Annotate | Download | only in strings
      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 
     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 
    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 
    405 bool Base64Unescape(const string& src, string* dest) {
    406   return Base64UnescapeInternal(src.data(), src.size(), dest, kUnBase64);
    407 }
    408 
    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.
    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 
    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 
    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 
    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>
    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 
    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