11cb0ef41Sopenharmony_ci#ifndef SRC_BASE64_INL_H_
21cb0ef41Sopenharmony_ci#define SRC_BASE64_INL_H_
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#include "base64.h"
71cb0ef41Sopenharmony_ci#include "libbase64.h"
81cb0ef41Sopenharmony_ci#include "util.h"
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_cinamespace node {
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cistatic constexpr char base64_table_url[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
131cb0ef41Sopenharmony_ci                                           "abcdefghijklmnopqrstuvwxyz"
141cb0ef41Sopenharmony_ci                                           "0123456789-_";
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciextern const int8_t unbase64_table[256];
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciinline static int8_t unbase64(uint8_t x) {
201cb0ef41Sopenharmony_ci  return unbase64_table[x];
211cb0ef41Sopenharmony_ci}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciinline uint32_t ReadUint32BE(const unsigned char* p) {
251cb0ef41Sopenharmony_ci  return static_cast<uint32_t>(p[0] << 24U) |
261cb0ef41Sopenharmony_ci         static_cast<uint32_t>(p[1] << 16U) |
271cb0ef41Sopenharmony_ci         static_cast<uint32_t>(p[2] << 8U) |
281cb0ef41Sopenharmony_ci         static_cast<uint32_t>(p[3]);
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci#ifdef _MSC_VER
321cb0ef41Sopenharmony_ci#pragma warning(push)
331cb0ef41Sopenharmony_ci// MSVC C4003: not enough actual parameters for macro 'identifier'
341cb0ef41Sopenharmony_ci#pragma warning(disable : 4003)
351cb0ef41Sopenharmony_ci#endif
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_citemplate <typename TypeName>
381cb0ef41Sopenharmony_cibool base64_decode_group_slow(char* const dst, const size_t dstlen,
391cb0ef41Sopenharmony_ci                              const TypeName* const src, const size_t srclen,
401cb0ef41Sopenharmony_ci                              size_t* const i, size_t* const k) {
411cb0ef41Sopenharmony_ci  uint8_t hi;
421cb0ef41Sopenharmony_ci  uint8_t lo;
431cb0ef41Sopenharmony_ci#define V(expr)                                                                \
441cb0ef41Sopenharmony_ci  for (;;) {                                                                   \
451cb0ef41Sopenharmony_ci    const uint8_t c = static_cast<uint8_t>(src[*i]);                           \
461cb0ef41Sopenharmony_ci    lo = unbase64(c);                                                          \
471cb0ef41Sopenharmony_ci    *i += 1;                                                                   \
481cb0ef41Sopenharmony_ci    if (lo < 64) break;                         /* Legal character. */         \
491cb0ef41Sopenharmony_ci    if (c == '=' || *i >= srclen) return false; /* Stop decoding. */           \
501cb0ef41Sopenharmony_ci  }                                                                            \
511cb0ef41Sopenharmony_ci  expr;                                                                        \
521cb0ef41Sopenharmony_ci  if (*i >= srclen) return false;                                              \
531cb0ef41Sopenharmony_ci  if (*k >= dstlen) return false;                                              \
541cb0ef41Sopenharmony_ci  hi = lo;
551cb0ef41Sopenharmony_ci  V(/* Nothing. */);
561cb0ef41Sopenharmony_ci  V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
571cb0ef41Sopenharmony_ci  V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
581cb0ef41Sopenharmony_ci  V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
591cb0ef41Sopenharmony_ci#undef V
601cb0ef41Sopenharmony_ci  return true;  // Continue decoding.
611cb0ef41Sopenharmony_ci}
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci#ifdef _MSC_VER
641cb0ef41Sopenharmony_ci#pragma warning(pop)
651cb0ef41Sopenharmony_ci#endif
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_citemplate <typename TypeName>
681cb0ef41Sopenharmony_cisize_t base64_decode_fast(char* const dst, const size_t dstlen,
691cb0ef41Sopenharmony_ci                          const TypeName* const src, const size_t srclen,
701cb0ef41Sopenharmony_ci                          const size_t decoded_size) {
711cb0ef41Sopenharmony_ci  const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
721cb0ef41Sopenharmony_ci  const size_t max_k = available / 3 * 3;
731cb0ef41Sopenharmony_ci  size_t max_i = srclen / 4 * 4;
741cb0ef41Sopenharmony_ci  size_t i = 0;
751cb0ef41Sopenharmony_ci  size_t k = 0;
761cb0ef41Sopenharmony_ci  while (i < max_i && k < max_k) {
771cb0ef41Sopenharmony_ci    const unsigned char txt[] = {
781cb0ef41Sopenharmony_ci        static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 0]))),
791cb0ef41Sopenharmony_ci        static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 1]))),
801cb0ef41Sopenharmony_ci        static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 2]))),
811cb0ef41Sopenharmony_ci        static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 3]))),
821cb0ef41Sopenharmony_ci    };
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci    const uint32_t v = ReadUint32BE(txt);
851cb0ef41Sopenharmony_ci    // If MSB is set, input contains whitespace or is not valid base64.
861cb0ef41Sopenharmony_ci    if (v & 0x80808080) {
871cb0ef41Sopenharmony_ci      if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k))
881cb0ef41Sopenharmony_ci        return k;
891cb0ef41Sopenharmony_ci      max_i = i + (srclen - i) / 4 * 4;  // Align max_i again.
901cb0ef41Sopenharmony_ci    } else {
911cb0ef41Sopenharmony_ci      dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
921cb0ef41Sopenharmony_ci      dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
931cb0ef41Sopenharmony_ci      dst[k + 2] = ((v >>  2) & 0xC0) | ((v >>  0) & 0x3F);
941cb0ef41Sopenharmony_ci      i += 4;
951cb0ef41Sopenharmony_ci      k += 3;
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci  if (i < srclen && k < dstlen) {
991cb0ef41Sopenharmony_ci    base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k);
1001cb0ef41Sopenharmony_ci  }
1011cb0ef41Sopenharmony_ci  return k;
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_citemplate <typename TypeName>
1061cb0ef41Sopenharmony_cisize_t base64_decoded_size(const TypeName* src, size_t size) {
1071cb0ef41Sopenharmony_ci  // 1-byte input cannot be decoded
1081cb0ef41Sopenharmony_ci  if (size < 2)
1091cb0ef41Sopenharmony_ci    return 0;
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci  if (src[size - 1] == '=') {
1121cb0ef41Sopenharmony_ci    size--;
1131cb0ef41Sopenharmony_ci    if (src[size - 1] == '=')
1141cb0ef41Sopenharmony_ci      size--;
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci  return base64_decoded_size_fast(size);
1171cb0ef41Sopenharmony_ci}
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_citemplate <typename TypeName>
1211cb0ef41Sopenharmony_cisize_t base64_decode(char* const dst, const size_t dstlen,
1221cb0ef41Sopenharmony_ci                     const TypeName* const src, const size_t srclen) {
1231cb0ef41Sopenharmony_ci  const size_t decoded_size = base64_decoded_size(src, srclen);
1241cb0ef41Sopenharmony_ci  return base64_decode_fast(dst, dstlen, src, srclen, decoded_size);
1251cb0ef41Sopenharmony_ci}
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ciinline size_t base64_encode(const char* src,
1291cb0ef41Sopenharmony_ci                            size_t slen,
1301cb0ef41Sopenharmony_ci                            char* dst,
1311cb0ef41Sopenharmony_ci                            size_t dlen,
1321cb0ef41Sopenharmony_ci                            Base64Mode mode) {
1331cb0ef41Sopenharmony_ci  // We know how much we'll write, just make sure that there's space.
1341cb0ef41Sopenharmony_ci  CHECK(dlen >= base64_encoded_size(slen, mode) &&
1351cb0ef41Sopenharmony_ci        "not enough space provided for base64 encode");
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  dlen = base64_encoded_size(slen, mode);
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  if (mode == Base64Mode::NORMAL) {
1401cb0ef41Sopenharmony_ci    ::base64_encode(src, slen, dst, &dlen, 0);
1411cb0ef41Sopenharmony_ci    return dlen;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  unsigned a;
1451cb0ef41Sopenharmony_ci  unsigned b;
1461cb0ef41Sopenharmony_ci  unsigned c;
1471cb0ef41Sopenharmony_ci  unsigned i;
1481cb0ef41Sopenharmony_ci  unsigned k;
1491cb0ef41Sopenharmony_ci  unsigned n;
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci  const char* table = base64_table_url;
1521cb0ef41Sopenharmony_ci
1531cb0ef41Sopenharmony_ci  i = 0;
1541cb0ef41Sopenharmony_ci  k = 0;
1551cb0ef41Sopenharmony_ci  n = slen / 3 * 3;
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_ci  while (i < n) {
1581cb0ef41Sopenharmony_ci    a = src[i + 0] & 0xff;
1591cb0ef41Sopenharmony_ci    b = src[i + 1] & 0xff;
1601cb0ef41Sopenharmony_ci    c = src[i + 2] & 0xff;
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci    dst[k + 0] = table[a >> 2];
1631cb0ef41Sopenharmony_ci    dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
1641cb0ef41Sopenharmony_ci    dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
1651cb0ef41Sopenharmony_ci    dst[k + 3] = table[c & 0x3f];
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci    i += 3;
1681cb0ef41Sopenharmony_ci    k += 4;
1691cb0ef41Sopenharmony_ci  }
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci  switch (slen - n) {
1721cb0ef41Sopenharmony_ci    case 1:
1731cb0ef41Sopenharmony_ci      a = src[i + 0] & 0xff;
1741cb0ef41Sopenharmony_ci      dst[k + 0] = table[a >> 2];
1751cb0ef41Sopenharmony_ci      dst[k + 1] = table[(a & 3) << 4];
1761cb0ef41Sopenharmony_ci      break;
1771cb0ef41Sopenharmony_ci    case 2:
1781cb0ef41Sopenharmony_ci      a = src[i + 0] & 0xff;
1791cb0ef41Sopenharmony_ci      b = src[i + 1] & 0xff;
1801cb0ef41Sopenharmony_ci      dst[k + 0] = table[a >> 2];
1811cb0ef41Sopenharmony_ci      dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
1821cb0ef41Sopenharmony_ci      dst[k + 2] = table[(b & 0x0f) << 2];
1831cb0ef41Sopenharmony_ci      break;
1841cb0ef41Sopenharmony_ci  }
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci  return dlen;
1871cb0ef41Sopenharmony_ci}
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci}  // namespace node
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci#endif  // SRC_BASE64_INL_H_
194