|  | 
|  | 1 | +#ifndef SRC_BASE64_H_ | 
|  | 2 | +#define SRC_BASE64_H_ | 
|  | 3 | + | 
|  | 4 | +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | 
|  | 5 | + | 
|  | 6 | +#include "util.h" | 
|  | 7 | + | 
|  | 8 | +#include <stddef.h> | 
|  | 9 | + | 
|  | 10 | +namespace node { | 
|  | 11 | +//// Base 64 //// | 
|  | 12 | +#define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4) | 
|  | 13 | + | 
|  | 14 | + | 
|  | 15 | +// Doesn't check for padding at the end.  Can be 1-2 bytes over. | 
|  | 16 | +static inline size_t base64_decoded_size_fast(size_t size) { | 
|  | 17 | +  size_t remainder = size % 4; | 
|  | 18 | + | 
|  | 19 | +  size = (size / 4) * 3; | 
|  | 20 | +  if (remainder) { | 
|  | 21 | +    if (size == 0 && remainder == 1) { | 
|  | 22 | +      // special case: 1-byte input cannot be decoded | 
|  | 23 | +      size = 0; | 
|  | 24 | +    } else { | 
|  | 25 | +      // non-padded input, add 1 or 2 extra bytes | 
|  | 26 | +      size += 1 + (remainder == 3); | 
|  | 27 | +    } | 
|  | 28 | +  } | 
|  | 29 | + | 
|  | 30 | +  return size; | 
|  | 31 | +} | 
|  | 32 | + | 
|  | 33 | +template <typename TypeName> | 
|  | 34 | +size_t base64_decoded_size(const TypeName* src, size_t size) { | 
|  | 35 | +  if (size == 0) | 
|  | 36 | +    return 0; | 
|  | 37 | + | 
|  | 38 | +  if (src[size - 1] == '=') | 
|  | 39 | +    size--; | 
|  | 40 | +  if (size > 0 && src[size - 1] == '=') | 
|  | 41 | +    size--; | 
|  | 42 | + | 
|  | 43 | +  return base64_decoded_size_fast(size); | 
|  | 44 | +} | 
|  | 45 | + | 
|  | 46 | + | 
|  | 47 | +extern const int8_t unbase64_table[256]; | 
|  | 48 | + | 
|  | 49 | + | 
|  | 50 | +#define unbase64(x)                                                           \ | 
|  | 51 | +  static_cast<uint8_t>(unbase64_table[static_cast<uint8_t>(x)]) | 
|  | 52 | + | 
|  | 53 | + | 
|  | 54 | +template <typename TypeName> | 
|  | 55 | +size_t base64_decode_slow(char* dst, size_t dstlen, | 
|  | 56 | +                          const TypeName* src, size_t srclen) { | 
|  | 57 | +  uint8_t hi; | 
|  | 58 | +  uint8_t lo; | 
|  | 59 | +  size_t i = 0; | 
|  | 60 | +  size_t k = 0; | 
|  | 61 | +  for (;;) { | 
|  | 62 | +#define V(expr)                                                               \ | 
|  | 63 | +    while (i < srclen) {                                                      \ | 
|  | 64 | +      const uint8_t c = src[i];                                               \ | 
|  | 65 | +      lo = unbase64(c);                                                       \ | 
|  | 66 | +      i += 1;                                                                 \ | 
|  | 67 | +      if (lo < 64)                                                            \ | 
|  | 68 | +        break;  /* Legal character. */                                        \ | 
|  | 69 | +      if (c == '=')                                                           \ | 
|  | 70 | +        return k;                                                             \ | 
|  | 71 | +    }                                                                         \ | 
|  | 72 | +    expr;                                                                     \ | 
|  | 73 | +    if (i >= srclen)                                                          \ | 
|  | 74 | +      return k;                                                               \ | 
|  | 75 | +    if (k >= dstlen)                                                          \ | 
|  | 76 | +      return k;                                                               \ | 
|  | 77 | +    hi = lo; | 
|  | 78 | +    V(/* Nothing. */); | 
|  | 79 | +    V(dst[k++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4)); | 
|  | 80 | +    V(dst[k++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2)); | 
|  | 81 | +    V(dst[k++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0)); | 
|  | 82 | +#undef V | 
|  | 83 | +  } | 
|  | 84 | +  UNREACHABLE(); | 
|  | 85 | +} | 
|  | 86 | + | 
|  | 87 | + | 
|  | 88 | +template <typename TypeName> | 
|  | 89 | +size_t base64_decode_fast(char* const dst, const size_t dstlen, | 
|  | 90 | +                          const TypeName* const src, const size_t srclen, | 
|  | 91 | +                          const size_t decoded_size) { | 
|  | 92 | +  const size_t available = dstlen < decoded_size ? dstlen : decoded_size; | 
|  | 93 | +  const size_t max_i = srclen / 4 * 4; | 
|  | 94 | +  const size_t max_k = available / 3 * 3; | 
|  | 95 | +  size_t i = 0; | 
|  | 96 | +  size_t k = 0; | 
|  | 97 | +  while (i < max_i && k < max_k) { | 
|  | 98 | +    const uint32_t v = | 
|  | 99 | +        unbase64(src[i + 0]) << 24 | | 
|  | 100 | +        unbase64(src[i + 1]) << 16 | | 
|  | 101 | +        unbase64(src[i + 2]) << 8 | | 
|  | 102 | +        unbase64(src[i + 3]); | 
|  | 103 | +    // If MSB is set, input contains whitespace or is not valid base64. | 
|  | 104 | +    if (v & 0x80808080) { | 
|  | 105 | +      break; | 
|  | 106 | +    } | 
|  | 107 | +    dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03); | 
|  | 108 | +    dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F); | 
|  | 109 | +    dst[k + 2] = ((v >>  2) & 0xC0) | ((v >>  0) & 0x3F); | 
|  | 110 | +    i += 4; | 
|  | 111 | +    k += 3; | 
|  | 112 | +  } | 
|  | 113 | +  if (i < srclen && k < dstlen) { | 
|  | 114 | +    return k + base64_decode_slow(dst + k, dstlen - k, src + i, srclen - i); | 
|  | 115 | +  } | 
|  | 116 | +  return k; | 
|  | 117 | +} | 
|  | 118 | + | 
|  | 119 | + | 
|  | 120 | +template <typename TypeName> | 
|  | 121 | +size_t base64_decode(char* const dst, const size_t dstlen, | 
|  | 122 | +                     const TypeName* const src, const size_t srclen) { | 
|  | 123 | +  const size_t decoded_size = base64_decoded_size(src, srclen); | 
|  | 124 | +  return base64_decode_fast(dst, dstlen, src, srclen, decoded_size); | 
|  | 125 | +} | 
|  | 126 | + | 
|  | 127 | +static size_t base64_encode(const char* src, | 
|  | 128 | +                            size_t slen, | 
|  | 129 | +                            char* dst, | 
|  | 130 | +                            size_t dlen) { | 
|  | 131 | +  // We know how much we'll write, just make sure that there's space. | 
|  | 132 | +  CHECK(dlen >= base64_encoded_size(slen) && | 
|  | 133 | +        "not enough space provided for base64 encode"); | 
|  | 134 | + | 
|  | 135 | +  dlen = base64_encoded_size(slen); | 
|  | 136 | + | 
|  | 137 | +  unsigned a; | 
|  | 138 | +  unsigned b; | 
|  | 139 | +  unsigned c; | 
|  | 140 | +  unsigned i; | 
|  | 141 | +  unsigned k; | 
|  | 142 | +  unsigned n; | 
|  | 143 | + | 
|  | 144 | +  static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | 
|  | 145 | +                              "abcdefghijklmnopqrstuvwxyz" | 
|  | 146 | +                              "0123456789+/"; | 
|  | 147 | + | 
|  | 148 | +  i = 0; | 
|  | 149 | +  k = 0; | 
|  | 150 | +  n = slen / 3 * 3; | 
|  | 151 | + | 
|  | 152 | +  while (i < n) { | 
|  | 153 | +    a = src[i + 0] & 0xff; | 
|  | 154 | +    b = src[i + 1] & 0xff; | 
|  | 155 | +    c = src[i + 2] & 0xff; | 
|  | 156 | + | 
|  | 157 | +    dst[k + 0] = table[a >> 2]; | 
|  | 158 | +    dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; | 
|  | 159 | +    dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)]; | 
|  | 160 | +    dst[k + 3] = table[c & 0x3f]; | 
|  | 161 | + | 
|  | 162 | +    i += 3; | 
|  | 163 | +    k += 4; | 
|  | 164 | +  } | 
|  | 165 | + | 
|  | 166 | +  if (n != slen) { | 
|  | 167 | +    switch (slen - n) { | 
|  | 168 | +      case 1: | 
|  | 169 | +        a = src[i + 0] & 0xff; | 
|  | 170 | +        dst[k + 0] = table[a >> 2]; | 
|  | 171 | +        dst[k + 1] = table[(a & 3) << 4]; | 
|  | 172 | +        dst[k + 2] = '='; | 
|  | 173 | +        dst[k + 3] = '='; | 
|  | 174 | +        break; | 
|  | 175 | + | 
|  | 176 | +      case 2: | 
|  | 177 | +        a = src[i + 0] & 0xff; | 
|  | 178 | +        b = src[i + 1] & 0xff; | 
|  | 179 | +        dst[k + 0] = table[a >> 2]; | 
|  | 180 | +        dst[k + 1] = table[((a & 3) << 4) | (b >> 4)]; | 
|  | 181 | +        dst[k + 2] = table[(b & 0x0f) << 2]; | 
|  | 182 | +        dst[k + 3] = '='; | 
|  | 183 | +        break; | 
|  | 184 | +    } | 
|  | 185 | +  } | 
|  | 186 | + | 
|  | 187 | +  return dlen; | 
|  | 188 | +} | 
|  | 189 | +}  // namespace node | 
|  | 190 | + | 
|  | 191 | + | 
|  | 192 | +#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS | 
|  | 193 | + | 
|  | 194 | +#endif  // SRC_BASE64_H_ | 
0 commit comments