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