src, deps: add nbytes library
Projects that seek to implement Node.js compatible APIs end up needed to reproduce various bits of functionality internally in order to faithfully replicate the Node.js behaviors. This is particularly true for things like byte manipulation, base64 and hex encoding, and other low-level operations. This change proposes moving much of this low-level byte manipulation code out of nodejs/src and into a new `nbytes` library. Initially this new library will exist in the `deps` directory but the intent is to spin out a new separate repository to be its home in the future. Doing so will allow other projects to use the nbytes library with exactly the same implementation as Node.js. This commit moves only the byte swapping and legacy base64 handling code. Additional commits will move additional byte manipulation logic into the library. PR-URL: https://github.com/nodejs/node/pull/53507 Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io> Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
This commit is contained in:
parent
fbdfe9399c
commit
d335487e3f
2
Makefile
2
Makefile
@ -174,7 +174,7 @@ with-code-cache test-code-cache:
|
||||
|
||||
out/Makefile: config.gypi common.gypi node.gyp \
|
||||
deps/uv/uv.gyp deps/llhttp/llhttp.gyp deps/zlib/zlib.gyp \
|
||||
deps/simdutf/simdutf.gyp deps/ada/ada.gyp \
|
||||
deps/simdutf/simdutf.gyp deps/ada/ada.gyp deps/nbytes/nbytes.gyp \
|
||||
tools/v8_gypfiles/toolchain.gypi tools/v8_gypfiles/features.gypi \
|
||||
tools/v8_gypfiles/inspector.gypi tools/v8_gypfiles/v8.gyp
|
||||
$(PYTHON) tools/gyp_node.py -f make
|
||||
|
5
deps/nbytes/README.md
vendored
Normal file
5
deps/nbytes/README.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Node.js bytes (nbytes) library
|
||||
|
||||
The `nbytes` library extracts certain Node.js specific byte manipulation
|
||||
functions from the core of Node.js itself and makes them available for
|
||||
use in other projects that need to emulate Node.js' behavior.
|
251
deps/nbytes/nbytes.cpp
vendored
Normal file
251
deps/nbytes/nbytes.cpp
vendored
Normal file
@ -0,0 +1,251 @@
|
||||
#include "nbytes.h"
|
||||
#include <string.h>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
|
||||
namespace nbytes {
|
||||
|
||||
// ============================================================================
|
||||
// Byte Swapping
|
||||
|
||||
namespace {
|
||||
// These are defined by <sys/byteorder.h> or <netinet/in.h> on some systems.
|
||||
// To avoid warnings, undefine them before redefining them.
|
||||
#ifdef BSWAP_2
|
||||
# undef BSWAP_2
|
||||
#endif
|
||||
#ifdef BSWAP_4
|
||||
# undef BSWAP_4
|
||||
#endif
|
||||
#ifdef BSWAP_8
|
||||
# undef BSWAP_8
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#define BSWAP_2(x) _byteswap_ushort(x)
|
||||
#define BSWAP_4(x) _byteswap_ulong(x)
|
||||
#define BSWAP_8(x) _byteswap_uint64(x)
|
||||
#else
|
||||
#define BSWAP_2(x) ((x) << 8) | ((x) >> 8)
|
||||
#define BSWAP_4(x) \
|
||||
(((x) & 0xFF) << 24) | \
|
||||
(((x) & 0xFF00) << 8) | \
|
||||
(((x) >> 8) & 0xFF00) | \
|
||||
(((x) >> 24) & 0xFF)
|
||||
#define BSWAP_8(x) \
|
||||
(((x) & 0xFF00000000000000ull) >> 56) | \
|
||||
(((x) & 0x00FF000000000000ull) >> 40) | \
|
||||
(((x) & 0x0000FF0000000000ull) >> 24) | \
|
||||
(((x) & 0x000000FF00000000ull) >> 8) | \
|
||||
(((x) & 0x00000000FF000000ull) << 8) | \
|
||||
(((x) & 0x0000000000FF0000ull) << 24) | \
|
||||
(((x) & 0x000000000000FF00ull) << 40) | \
|
||||
(((x) & 0x00000000000000FFull) << 56)
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
bool SwapBytes16(void* data, size_t nbytes) {
|
||||
if (nbytes % sizeof(uint16_t) != 0) return false;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (AlignUp(data, sizeof(uint16_t)) == data) {
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
|
||||
size_t len16 = nbytes / sizeof(uint16_t);
|
||||
for (size_t i = 0; i < len16; i++) {
|
||||
data16[i] = BSWAP_2(data16[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t temp;
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(uint16_t)) {
|
||||
memcpy(&temp, &ptr[i], sizeof(uint16_t));
|
||||
temp = BSWAP_2(temp);
|
||||
memcpy(&ptr[i], &temp, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwapBytes32(void* data, size_t nbytes) {
|
||||
if (nbytes % sizeof(uint32_t) != 0) return false;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
if (AlignUp(data, sizeof(uint32_t)) == data) {
|
||||
uint32_t* data32 = reinterpret_cast<uint32_t*>(data);
|
||||
size_t len32 = nbytes / sizeof(uint32_t);
|
||||
for (size_t i = 0; i < len32; i++) {
|
||||
data32[i] = BSWAP_4(data32[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t temp = 0;
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(uint32_t)) {
|
||||
memcpy(&temp, &ptr[i], sizeof(uint32_t));
|
||||
temp = BSWAP_4(temp);
|
||||
memcpy(&ptr[i], &temp, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwapBytes64(void* data, size_t nbytes) {
|
||||
if (nbytes % sizeof(uint64_t) != 0) return false;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (AlignUp(data, sizeof(uint64_t)) == data) {
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
uint64_t* data64 = reinterpret_cast<uint64_t*>(data);
|
||||
size_t len64 = nbytes / sizeof(uint64_t);
|
||||
for (size_t i = 0; i < len64; i++) {
|
||||
data64[i] = BSWAP_8(data64[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t temp = 0;
|
||||
uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(uint64_t)) {
|
||||
memcpy(&temp, &ptr[i], sizeof(uint64_t));
|
||||
temp = BSWAP_8(temp);
|
||||
memcpy(&ptr[i], &temp, sizeof(uint64_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Base64 (legacy)
|
||||
|
||||
// supports regular and URL-safe base64
|
||||
const int8_t unbase64_table[256] =
|
||||
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Hex
|
||||
|
||||
const int8_t unhex_table[256] =
|
||||
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
size_t HexEncode(
|
||||
const char* src,
|
||||
size_t slen,
|
||||
char* dst,
|
||||
size_t dlen) {
|
||||
// We know how much we'll write, just make sure that there's space.
|
||||
NBYTES_ASSERT_TRUE(
|
||||
dlen >= MultiplyWithOverflowCheck<size_t>(slen, 2u) &&
|
||||
"not enough space provided for hex encode");
|
||||
|
||||
dlen = slen * 2;
|
||||
for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
uint8_t val = static_cast<uint8_t>(src[i]);
|
||||
dst[k + 0] = hex[val >> 4];
|
||||
dst[k + 1] = hex[val & 15];
|
||||
}
|
||||
|
||||
return dlen;
|
||||
}
|
||||
|
||||
std::string HexEncode(const char* src, size_t slen) {
|
||||
size_t dlen = slen * 2;
|
||||
std::string dst(dlen, '\0');
|
||||
HexEncode(src, slen, dst.data(), dlen);
|
||||
return dst;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
void ForceAsciiSlow(const char* src, char* dst, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
dst[i] = src[i] & 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
void ForceAscii(const char* src, char* dst, size_t len) {
|
||||
if (len < 16) {
|
||||
ForceAsciiSlow(src, dst, len);
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned bytes_per_word = sizeof(uintptr_t);
|
||||
const unsigned align_mask = bytes_per_word - 1;
|
||||
const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
|
||||
const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
|
||||
|
||||
if (src_unalign > 0) {
|
||||
if (src_unalign == dst_unalign) {
|
||||
const unsigned unalign = bytes_per_word - src_unalign;
|
||||
ForceAsciiSlow(src, dst, unalign);
|
||||
src += unalign;
|
||||
dst += unalign;
|
||||
len -= src_unalign;
|
||||
} else {
|
||||
ForceAsciiSlow(src, dst, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN64) || defined(_LP64)
|
||||
const uintptr_t mask = ~0x8080808080808080ll;
|
||||
#else
|
||||
const uintptr_t mask = ~0x80808080l;
|
||||
#endif
|
||||
|
||||
const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
|
||||
uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
|
||||
|
||||
for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
|
||||
dstw[i] = srcw[i] & mask;
|
||||
}
|
||||
|
||||
const unsigned remainder = len & align_mask;
|
||||
if (remainder > 0) {
|
||||
const size_t offset = len - remainder;
|
||||
ForceAsciiSlow(src + offset, dst + offset, remainder);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace nbytes
|
16
deps/nbytes/nbytes.gyp
vendored
Normal file
16
deps/nbytes/nbytes.gyp
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
'variables': {
|
||||
'nbytes_sources': [ 'nbytes.cpp' ],
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'nbytes',
|
||||
'type': 'static_library',
|
||||
'include_dirs': ['.'],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': ['.'],
|
||||
},
|
||||
'sources': [ '<@(nbytes_sources)' ]
|
||||
},
|
||||
]
|
||||
}
|
318
src/string_search.h → deps/nbytes/nbytes.h
vendored
318
src/string_search.h → deps/nbytes/nbytes.h
vendored
@ -1,18 +1,260 @@
|
||||
// Copyright 2011 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
#pragma once
|
||||
|
||||
#ifndef SRC_STRING_SEARCH_H_
|
||||
#define SRC_STRING_SEARCH_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
namespace nbytes {
|
||||
|
||||
#if NBYTES_DEVELOPMENT_CHECKS
|
||||
#define NBYTES_STR(x) #x
|
||||
#define NBYTES_REQUIRE(EXPR) \
|
||||
{ \
|
||||
if (!(EXPR) { abort(); }) }
|
||||
|
||||
#define NBYTES_FAIL(MESSAGE) \
|
||||
do { \
|
||||
std::cerr << "FAIL: " << (MESSAGE) << std::endl; \
|
||||
abort(); \
|
||||
} while (0);
|
||||
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE) \
|
||||
do { \
|
||||
if (LHS != RHS) { \
|
||||
std::cerr << "Mismatch: '" << LHS << "' - '" << RHS << "'" << std::endl; \
|
||||
NBYTES_FAIL(MESSAGE); \
|
||||
} \
|
||||
} while (0);
|
||||
#define NBYTES_ASSERT_TRUE(COND) \
|
||||
do { \
|
||||
if (!(COND)) { \
|
||||
std::cerr << "Assert at line " << __LINE__ << " of file " << __FILE__ \
|
||||
<< std::endl; \
|
||||
NBYTES_FAIL(NBYTES_STR(COND)); \
|
||||
} \
|
||||
} while (0);
|
||||
#else
|
||||
#define NBYTES_FAIL(MESSAGE)
|
||||
#define NBYTES_ASSERT_EQUAL(LHS, RHS, MESSAGE)
|
||||
#define NBYTES_ASSERT_TRUE(COND)
|
||||
#endif
|
||||
|
||||
[[noreturn]] inline void unreachable() {
|
||||
#ifdef __GNUC__
|
||||
__builtin_unreachable();
|
||||
#elif defined(_MSC_VER)
|
||||
__assume(false);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
// The nbytes (short for "node bytes") is a set of utility helpers for
|
||||
// working with bytes that are extracted from Node.js' internals. The
|
||||
// motivation for extracting these into a separate library is to make it
|
||||
// easier for other projects to implement functionality that is compatible
|
||||
// with Node.js' implementation of various byte manipulation functions.
|
||||
|
||||
// Round up a to the next highest multiple of b.
|
||||
template <typename T>
|
||||
constexpr T RoundUp(T a, T b) {
|
||||
return a % b != 0 ? a + b - (a % b) : a;
|
||||
}
|
||||
|
||||
// Align ptr to an `alignment`-bytes boundary.
|
||||
template <typename T, typename U>
|
||||
constexpr T* AlignUp(T* ptr, U alignment) {
|
||||
return reinterpret_cast<T*>(
|
||||
RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline T AlignDown(T value, U alignment) {
|
||||
return reinterpret_cast<T>(
|
||||
(reinterpret_cast<uintptr_t>(value) & ~(alignment - 1)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T MultiplyWithOverflowCheck(T a, T b) {
|
||||
auto ret = a * b;
|
||||
if (a != 0) {
|
||||
NBYTES_ASSERT_TRUE(b == ret / a);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ForceAsciiSlow(const char* src, char* dst, size_t len);
|
||||
void ForceAscii(const char* src, char* dst, size_t len);
|
||||
|
||||
// ============================================================================
|
||||
// Byte Swapping
|
||||
|
||||
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
|
||||
// multiple of the word size (checked by function).
|
||||
bool SwapBytes16(void* data, size_t nbytes);
|
||||
bool SwapBytes32(void* data, size_t nbytes);
|
||||
bool SwapBytes64(void* data, size_t nbytes);
|
||||
|
||||
// ============================================================================
|
||||
// Base64 (legacy)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
// MSVC C4003: not enough actual parameters for macro 'identifier'
|
||||
#pragma warning(disable : 4003)
|
||||
#endif
|
||||
|
||||
extern const int8_t unbase64_table[256];
|
||||
|
||||
template <typename TypeName>
|
||||
bool Base64DecodeGroupSlow(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen,
|
||||
size_t* const i, size_t* const k) {
|
||||
uint8_t hi;
|
||||
uint8_t lo;
|
||||
#define V(expr) \
|
||||
for (;;) { \
|
||||
const uint8_t c = static_cast<uint8_t>(src[*i]); \
|
||||
lo = unbase64_table[c]; \
|
||||
*i += 1; \
|
||||
if (lo < 64) break; /* Legal character. */ \
|
||||
if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \
|
||||
} \
|
||||
expr; \
|
||||
if (*i >= srclen) return false; \
|
||||
if (*k >= dstlen) return false; \
|
||||
hi = lo;
|
||||
V(/* Nothing. */);
|
||||
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
|
||||
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
|
||||
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
|
||||
#undef V
|
||||
return true; // Continue decoding.
|
||||
}
|
||||
|
||||
enum class Base64Mode {
|
||||
NORMAL,
|
||||
URL
|
||||
};
|
||||
|
||||
inline constexpr size_t Base64EncodedSize(
|
||||
size_t size,
|
||||
Base64Mode mode = Base64Mode::NORMAL) {
|
||||
return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4)
|
||||
: static_cast<size_t>(std::ceil(
|
||||
static_cast<double>(size * 4) / 3));
|
||||
}
|
||||
|
||||
// Doesn't check for padding at the end. Can be 1-2 bytes over.
|
||||
inline constexpr size_t Base64DecodedSizeFast(size_t size) {
|
||||
// 1-byte input cannot be decoded
|
||||
return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0;
|
||||
}
|
||||
|
||||
inline uint32_t ReadUint32BE(const unsigned char* p) {
|
||||
return static_cast<uint32_t>(p[0] << 24U) |
|
||||
static_cast<uint32_t>(p[1] << 16U) |
|
||||
static_cast<uint32_t>(p[2] << 8U) |
|
||||
static_cast<uint32_t>(p[3]);
|
||||
}
|
||||
|
||||
template <typename TypeName>
|
||||
size_t Base64DecodedSize(const TypeName* src, size_t size) {
|
||||
// 1-byte input cannot be decoded
|
||||
if (size < 2)
|
||||
return 0;
|
||||
|
||||
if (src[size - 1] == '=') {
|
||||
size--;
|
||||
if (src[size - 1] == '=')
|
||||
size--;
|
||||
}
|
||||
return Base64DecodedSizeFast(size);
|
||||
}
|
||||
|
||||
template <typename TypeName>
|
||||
size_t Base64DecodeFast(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen,
|
||||
const size_t decoded_size) {
|
||||
const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
|
||||
const size_t max_k = available / 3 * 3;
|
||||
size_t max_i = srclen / 4 * 4;
|
||||
size_t i = 0;
|
||||
size_t k = 0;
|
||||
while (i < max_i && k < max_k) {
|
||||
const unsigned char txt[] = {
|
||||
static_cast<unsigned char>(unbase64_table[static_cast<uint8_t>(src[i + 0])]),
|
||||
static_cast<unsigned char>(unbase64_table[static_cast<uint8_t>(src[i + 1])]),
|
||||
static_cast<unsigned char>(unbase64_table[static_cast<uint8_t>(src[i + 2])]),
|
||||
static_cast<unsigned char>(unbase64_table[static_cast<uint8_t>(src[i + 3])]),
|
||||
};
|
||||
|
||||
const uint32_t v = ReadUint32BE(txt);
|
||||
// If MSB is set, input contains whitespace or is not valid base64.
|
||||
if (v & 0x80808080) {
|
||||
if (!Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k))
|
||||
return k;
|
||||
max_i = i + (srclen - i) / 4 * 4; // Align max_i again.
|
||||
} else {
|
||||
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
|
||||
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
|
||||
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
|
||||
i += 4;
|
||||
k += 3;
|
||||
}
|
||||
}
|
||||
if (i < srclen && k < dstlen) {
|
||||
Base64DecodeGroupSlow(dst, dstlen, src, srclen, &i, &k);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
template <typename TypeName>
|
||||
size_t Base64Decode(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen) {
|
||||
const size_t decoded_size = Base64DecodedSize(src, srclen);
|
||||
return Base64DecodeFast(dst, dstlen, src, srclen, decoded_size);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
// Hex (legacy)
|
||||
|
||||
extern const int8_t unhex_table[256];
|
||||
|
||||
template <typename TypeName>
|
||||
static size_t HexDecode(char* buf,
|
||||
size_t len,
|
||||
const TypeName* src,
|
||||
const size_t srcLen) {
|
||||
size_t i;
|
||||
for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
|
||||
unsigned a = unhex_table[static_cast<uint8_t>(src[i * 2 + 0])];
|
||||
unsigned b = unhex_table[static_cast<uint8_t>(src[i * 2 + 1])];
|
||||
if (!~a || !~b)
|
||||
return i;
|
||||
buf[i] = (a << 4) | b;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t HexEncode(
|
||||
const char* src,
|
||||
size_t slen,
|
||||
char* dst,
|
||||
size_t dlen);
|
||||
|
||||
std::string HexEncode(const char* src, size_t slen);
|
||||
|
||||
// ============================================================================
|
||||
// StringSearch
|
||||
|
||||
namespace node {
|
||||
namespace stringsearch {
|
||||
|
||||
template <typename T>
|
||||
@ -36,7 +278,7 @@ class Vector {
|
||||
|
||||
// Access individual vector elements - checks bounds in debug mode.
|
||||
T& operator[](size_t index) const {
|
||||
DCHECK_LT(index, length_);
|
||||
NBYTES_ASSERT_TRUE(index < length_);
|
||||
return start_[is_forward_ ? index : (length_ - index - 1)];
|
||||
}
|
||||
|
||||
@ -46,7 +288,6 @@ class Vector {
|
||||
bool is_forward_;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// String Search object.
|
||||
//---------------------------------------------------------------------
|
||||
@ -97,7 +338,7 @@ class StringSearch : private StringSearchBase {
|
||||
}
|
||||
|
||||
size_t pattern_length = pattern_.length();
|
||||
CHECK_GT(pattern_length, 0);
|
||||
NBYTES_ASSERT_TRUE(pattern_length > 0);
|
||||
if (pattern_length < kBMMinPatternLength) {
|
||||
if (pattern_length == 1) {
|
||||
strategy_ = SearchStrategy::kSingleChar;
|
||||
@ -122,7 +363,7 @@ class StringSearch : private StringSearchBase {
|
||||
case kSingleChar:
|
||||
return SingleCharSearch(subject, index);
|
||||
}
|
||||
UNREACHABLE();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
static inline int AlphabetSize() {
|
||||
@ -176,23 +417,13 @@ class StringSearch : private StringSearchBase {
|
||||
size_t start_;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename U>
|
||||
inline T AlignDown(T value, U alignment) {
|
||||
return reinterpret_cast<T>(
|
||||
(reinterpret_cast<uintptr_t>(value) & ~(alignment - 1)));
|
||||
}
|
||||
|
||||
|
||||
inline uint8_t GetHighestValueByte(uint16_t character) {
|
||||
return std::max(static_cast<uint8_t>(character & 0xFF),
|
||||
static_cast<uint8_t>(character >> 8));
|
||||
}
|
||||
|
||||
|
||||
inline uint8_t GetHighestValueByte(uint8_t character) { return character; }
|
||||
|
||||
|
||||
// Searches for a byte value in a memory buffer, back to front.
|
||||
// Uses memrchr(3) on systems which support it, for speed.
|
||||
// Falls back to a vanilla for loop on non-GNU systems such as Windows.
|
||||
@ -211,7 +442,6 @@ inline const void* MemrchrFill(const void* haystack, uint8_t needle,
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Finds the first occurrence of *two-byte* character pattern[0] in the string
|
||||
// `subject`. Does not check that the whole pattern matches.
|
||||
template <typename Char>
|
||||
@ -229,12 +459,12 @@ inline size_t FindFirstCharacter(Vector<const Char> pattern,
|
||||
const void* void_pos;
|
||||
if (subject.forward()) {
|
||||
// Assert that bytes_to_search won't overflow
|
||||
CHECK_LE(pos, max_n);
|
||||
CHECK_LE(max_n - pos, SIZE_MAX / sizeof(Char));
|
||||
NBYTES_ASSERT_TRUE(pos <= max_n);
|
||||
NBYTES_ASSERT_TRUE(max_n - pos <= SIZE_MAX / sizeof(Char));
|
||||
void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search);
|
||||
} else {
|
||||
CHECK_LE(pos, subject.length());
|
||||
CHECK_LE(subject.length() - pos, SIZE_MAX / sizeof(Char));
|
||||
NBYTES_ASSERT_TRUE(pos <= subject.length());
|
||||
NBYTES_ASSERT_TRUE(subject.length() - pos <= SIZE_MAX / sizeof(Char));
|
||||
void_pos = MemrchrFill(subject.start() + pattern.length() - 1,
|
||||
search_byte,
|
||||
bytes_to_search);
|
||||
@ -257,7 +487,6 @@ inline size_t FindFirstCharacter(Vector<const Char> pattern,
|
||||
return subject.length();
|
||||
}
|
||||
|
||||
|
||||
// Finds the first occurrence of the byte pattern[0] in string `subject`.
|
||||
// Does not verify that the whole pattern matches.
|
||||
template <>
|
||||
@ -293,7 +522,7 @@ template <typename Char>
|
||||
size_t StringSearch<Char>::SingleCharSearch(
|
||||
Vector subject,
|
||||
size_t index) {
|
||||
CHECK_EQ(1, pattern_.length());
|
||||
NBYTES_ASSERT_TRUE(1 == pattern_.length());
|
||||
return FindFirstCharacter(pattern_, subject, index);
|
||||
}
|
||||
|
||||
@ -306,13 +535,13 @@ template <typename Char>
|
||||
size_t StringSearch<Char>::LinearSearch(
|
||||
Vector subject,
|
||||
size_t index) {
|
||||
CHECK_GT(pattern_.length(), 1);
|
||||
NBYTES_ASSERT_TRUE(pattern_.length() > 1);
|
||||
const size_t n = subject.length() - pattern_.length();
|
||||
for (size_t i = index; i <= n; i++) {
|
||||
i = FindFirstCharacter(pattern_, subject, i);
|
||||
if (i == subject.length())
|
||||
return subject.length();
|
||||
CHECK_LE(i, n);
|
||||
NBYTES_ASSERT_TRUE(i <= n);
|
||||
|
||||
bool matches = true;
|
||||
for (size_t j = 1; j < pattern_.length(); j++) {
|
||||
@ -553,7 +782,7 @@ size_t StringSearch<Char>::InitialSearch(
|
||||
i = FindFirstCharacter(pattern_, subject, i);
|
||||
if (i == subject.length())
|
||||
return subject.length();
|
||||
CHECK_LE(i, n);
|
||||
NBYTES_ASSERT_TRUE(i <= n);
|
||||
size_t j = 1;
|
||||
do {
|
||||
if (pattern_[j] != subject[i + j]) {
|
||||
@ -586,9 +815,6 @@ size_t SearchString(Vector<const Char> subject,
|
||||
return search.Search(subject, start_index);
|
||||
}
|
||||
} // namespace stringsearch
|
||||
} // namespace node
|
||||
|
||||
namespace node {
|
||||
|
||||
template <typename Char>
|
||||
size_t SearchString(const Char* haystack,
|
||||
@ -614,7 +840,7 @@ size_t SearchString(const Char* haystack,
|
||||
} else {
|
||||
relative_start_index = diff - start_index;
|
||||
}
|
||||
size_t pos = node::stringsearch::SearchString(
|
||||
size_t pos = stringsearch::SearchString(
|
||||
v_haystack, v_needle, relative_start_index);
|
||||
if (pos == haystack_length) {
|
||||
// not found
|
||||
@ -631,8 +857,14 @@ size_t SearchString(const char* haystack, size_t haystack_length,
|
||||
reinterpret_cast<const uint8_t*>(needle), N - 1, 0, true);
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
// ============================================================================
|
||||
// Version metadata
|
||||
#define NBYTES_VERSION "0.0.1"
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
enum {
|
||||
NBYTES_VERSION_MAJOR = 0,
|
||||
NBYTES_VERSION_MINOR = 0,
|
||||
NBYTES_VERSION_REVISION = 1,
|
||||
};
|
||||
|
||||
#endif // SRC_STRING_SEARCH_H_
|
||||
} // namespace nbytes
|
8
node.gyp
8
node.gyp
@ -187,8 +187,6 @@
|
||||
'src/base_object.h',
|
||||
'src/base_object-inl.h',
|
||||
'src/base_object_types.h',
|
||||
'src/base64.h',
|
||||
'src/base64-inl.h',
|
||||
'src/blob_serializer_deserializer.h',
|
||||
'src/blob_serializer_deserializer-inl.h',
|
||||
'src/callback_queue.h',
|
||||
@ -293,7 +291,6 @@
|
||||
'src/string_bytes.h',
|
||||
'src/string_decoder.h',
|
||||
'src/string_decoder-inl.h',
|
||||
'src/string_search.h',
|
||||
'src/tcp_wrap.h',
|
||||
'src/timers.h',
|
||||
'src/tracing/agent.h',
|
||||
@ -845,6 +842,7 @@
|
||||
'deps/simdjson/simdjson.gyp:simdjson',
|
||||
'deps/simdutf/simdutf.gyp:simdutf',
|
||||
'deps/ada/ada.gyp:ada',
|
||||
'deps/nbytes/nbytes.gyp:nbytes',
|
||||
'node_js2c#host',
|
||||
],
|
||||
|
||||
@ -1120,6 +1118,7 @@
|
||||
'deps/sqlite/sqlite.gyp:sqlite',
|
||||
'deps/uvwasi/uvwasi.gyp:uvwasi',
|
||||
'deps/ada/ada.gyp:ada',
|
||||
'deps/nbytes/nbytes.gyp:nbytes',
|
||||
],
|
||||
'includes': [
|
||||
'node.gypi'
|
||||
@ -1170,6 +1169,7 @@
|
||||
'deps/simdjson/simdjson.gyp:simdjson',
|
||||
'deps/simdutf/simdutf.gyp:simdutf',
|
||||
'deps/ada/ada.gyp:ada',
|
||||
'deps/nbytes/nbytes.gyp:nbytes',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
@ -1246,6 +1246,7 @@
|
||||
'deps/histogram/histogram.gyp:histogram',
|
||||
'deps/sqlite/sqlite.gyp:sqlite',
|
||||
'deps/ada/ada.gyp:ada',
|
||||
'deps/nbytes/nbytes.gyp:nbytes',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
@ -1361,6 +1362,7 @@
|
||||
'deps/histogram/histogram.gyp:histogram',
|
||||
'deps/sqlite/sqlite.gyp:sqlite',
|
||||
'deps/ada/ada.gyp:ada',
|
||||
'deps/nbytes/nbytes.gyp:nbytes',
|
||||
'deps/simdjson/simdjson.gyp:simdjson',
|
||||
'deps/simdutf/simdutf.gyp:simdutf',
|
||||
],
|
||||
|
126
src/base64-inl.h
126
src/base64-inl.h
@ -1,126 +0,0 @@
|
||||
#ifndef SRC_BASE64_INL_H_
|
||||
#define SRC_BASE64_INL_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "base64.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
extern const int8_t unbase64_table[256];
|
||||
|
||||
|
||||
inline static int8_t unbase64(uint8_t x) {
|
||||
return unbase64_table[x];
|
||||
}
|
||||
|
||||
|
||||
inline uint32_t ReadUint32BE(const unsigned char* p) {
|
||||
return static_cast<uint32_t>(p[0] << 24U) |
|
||||
static_cast<uint32_t>(p[1] << 16U) |
|
||||
static_cast<uint32_t>(p[2] << 8U) |
|
||||
static_cast<uint32_t>(p[3]);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
// MSVC C4003: not enough actual parameters for macro 'identifier'
|
||||
#pragma warning(disable : 4003)
|
||||
#endif
|
||||
|
||||
template <typename TypeName>
|
||||
bool base64_decode_group_slow(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen,
|
||||
size_t* const i, size_t* const k) {
|
||||
uint8_t hi;
|
||||
uint8_t lo;
|
||||
#define V(expr) \
|
||||
for (;;) { \
|
||||
const uint8_t c = static_cast<uint8_t>(src[*i]); \
|
||||
lo = unbase64(c); \
|
||||
*i += 1; \
|
||||
if (lo < 64) break; /* Legal character. */ \
|
||||
if (c == '=' || *i >= srclen) return false; /* Stop decoding. */ \
|
||||
} \
|
||||
expr; \
|
||||
if (*i >= srclen) return false; \
|
||||
if (*k >= dstlen) return false; \
|
||||
hi = lo;
|
||||
V(/* Nothing. */);
|
||||
V(dst[(*k)++] = ((hi & 0x3F) << 2) | ((lo & 0x30) >> 4));
|
||||
V(dst[(*k)++] = ((hi & 0x0F) << 4) | ((lo & 0x3C) >> 2));
|
||||
V(dst[(*k)++] = ((hi & 0x03) << 6) | ((lo & 0x3F) >> 0));
|
||||
#undef V
|
||||
return true; // Continue decoding.
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <typename TypeName>
|
||||
size_t base64_decode_fast(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen,
|
||||
const size_t decoded_size) {
|
||||
const size_t available = dstlen < decoded_size ? dstlen : decoded_size;
|
||||
const size_t max_k = available / 3 * 3;
|
||||
size_t max_i = srclen / 4 * 4;
|
||||
size_t i = 0;
|
||||
size_t k = 0;
|
||||
while (i < max_i && k < max_k) {
|
||||
const unsigned char txt[] = {
|
||||
static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 0]))),
|
||||
static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 1]))),
|
||||
static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 2]))),
|
||||
static_cast<unsigned char>(unbase64(static_cast<uint8_t>(src[i + 3]))),
|
||||
};
|
||||
|
||||
const uint32_t v = ReadUint32BE(txt);
|
||||
// If MSB is set, input contains whitespace or is not valid base64.
|
||||
if (v & 0x80808080) {
|
||||
if (!base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k))
|
||||
return k;
|
||||
max_i = i + (srclen - i) / 4 * 4; // Align max_i again.
|
||||
} else {
|
||||
dst[k + 0] = ((v >> 22) & 0xFC) | ((v >> 20) & 0x03);
|
||||
dst[k + 1] = ((v >> 12) & 0xF0) | ((v >> 10) & 0x0F);
|
||||
dst[k + 2] = ((v >> 2) & 0xC0) | ((v >> 0) & 0x3F);
|
||||
i += 4;
|
||||
k += 3;
|
||||
}
|
||||
}
|
||||
if (i < srclen && k < dstlen) {
|
||||
base64_decode_group_slow(dst, dstlen, src, srclen, &i, &k);
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
template <typename TypeName>
|
||||
size_t base64_decoded_size(const TypeName* src, size_t size) {
|
||||
// 1-byte input cannot be decoded
|
||||
if (size < 2)
|
||||
return 0;
|
||||
|
||||
if (src[size - 1] == '=') {
|
||||
size--;
|
||||
if (src[size - 1] == '=')
|
||||
size--;
|
||||
}
|
||||
return base64_decoded_size_fast(size);
|
||||
}
|
||||
|
||||
|
||||
template <typename TypeName>
|
||||
size_t base64_decode(char* const dst, const size_t dstlen,
|
||||
const TypeName* const src, const size_t srclen) {
|
||||
const size_t decoded_size = base64_decoded_size(src, srclen);
|
||||
return base64_decode_fast(dst, dstlen, src, srclen, decoded_size);
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_BASE64_INL_H_
|
49
src/base64.h
49
src/base64.h
@ -1,49 +0,0 @@
|
||||
#ifndef SRC_BASE64_H_
|
||||
#define SRC_BASE64_H_
|
||||
|
||||
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace node {
|
||||
//// Base 64 ////
|
||||
|
||||
enum class Base64Mode {
|
||||
NORMAL,
|
||||
URL
|
||||
};
|
||||
|
||||
static inline constexpr size_t base64_encoded_size(
|
||||
size_t size,
|
||||
Base64Mode mode = Base64Mode::NORMAL) {
|
||||
return mode == Base64Mode::NORMAL ? ((size + 2) / 3 * 4)
|
||||
: static_cast<size_t>(std::ceil(
|
||||
static_cast<double>(size * 4) / 3));
|
||||
}
|
||||
|
||||
// Doesn't check for padding at the end. Can be 1-2 bytes over.
|
||||
static inline constexpr size_t base64_decoded_size_fast(size_t size) {
|
||||
// 1-byte input cannot be decoded
|
||||
return size > 1 ? (size / 4) * 3 + (size % 4 + 1) / 2 : 0;
|
||||
}
|
||||
|
||||
inline uint32_t ReadUint32BE(const unsigned char* p);
|
||||
|
||||
template <typename TypeName>
|
||||
size_t base64_decoded_size(const TypeName* src, size_t size);
|
||||
|
||||
template <typename TypeName>
|
||||
size_t base64_decode(char* const dst,
|
||||
const size_t dstlen,
|
||||
const TypeName* const src,
|
||||
const size_t srclen);
|
||||
} // namespace node
|
||||
|
||||
|
||||
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
||||
|
||||
#endif // SRC_BASE64_H_
|
@ -22,10 +22,10 @@
|
||||
#include "cares_wrap.h"
|
||||
#include "ada.h"
|
||||
#include "async_wrap-inl.h"
|
||||
#include "base64-inl.h"
|
||||
#include "base_object-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "nbytes.h"
|
||||
#include "node.h"
|
||||
#include "node_errors.h"
|
||||
#include "node_external_reference.h"
|
||||
@ -591,11 +591,11 @@ int ParseSoaReply(
|
||||
return ARES_EBADRESP;
|
||||
}
|
||||
|
||||
const unsigned int serial = ReadUint32BE(ptr + 0 * 4);
|
||||
const unsigned int refresh = ReadUint32BE(ptr + 1 * 4);
|
||||
const unsigned int retry = ReadUint32BE(ptr + 2 * 4);
|
||||
const unsigned int expire = ReadUint32BE(ptr + 3 * 4);
|
||||
const unsigned int minttl = ReadUint32BE(ptr + 4 * 4);
|
||||
const unsigned int serial = nbytes::ReadUint32BE(ptr + 0 * 4);
|
||||
const unsigned int refresh = nbytes::ReadUint32BE(ptr + 1 * 4);
|
||||
const unsigned int retry = nbytes::ReadUint32BE(ptr + 2 * 4);
|
||||
const unsigned int expire = nbytes::ReadUint32BE(ptr + 3 * 4);
|
||||
const unsigned int minttl = nbytes::ReadUint32BE(ptr + 4 * 4);
|
||||
|
||||
Local<Object> soa_record = Object::New(env->isolate());
|
||||
soa_record->Set(env->context(),
|
||||
@ -1801,7 +1801,7 @@ void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
|
||||
// to 0 (any).
|
||||
|
||||
if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) {
|
||||
ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr0));
|
||||
ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0));
|
||||
type0 = 4;
|
||||
} else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) {
|
||||
ares_set_local_ip6(channel->cares_channel(), addr0);
|
||||
@ -1820,7 +1820,8 @@ void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
|
||||
THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses.");
|
||||
return;
|
||||
} else {
|
||||
ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr1));
|
||||
ares_set_local_ip4(channel->cares_channel(),
|
||||
nbytes::ReadUint32BE(addr1));
|
||||
}
|
||||
} else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) {
|
||||
if (type0 == 6) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "base_object-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "nbytes.h"
|
||||
#include "node.h"
|
||||
#include "node_buffer.h"
|
||||
#include "node_crypto.h"
|
||||
@ -90,10 +91,10 @@ void LogSecret(
|
||||
}
|
||||
|
||||
std::string line = name;
|
||||
line += " " + StringBytes::hex_encode(reinterpret_cast<const char*>(crandom),
|
||||
kTlsClientRandomSize);
|
||||
line += " " + StringBytes::hex_encode(
|
||||
reinterpret_cast<const char*>(secret), secretlen);
|
||||
line += " " + nbytes::HexEncode(reinterpret_cast<const char*>(crandom),
|
||||
kTlsClientRandomSize);
|
||||
line +=
|
||||
" " + nbytes::HexEncode(reinterpret_cast<const char*>(secret), secretlen);
|
||||
keylog_cb(ssl.get(), line.c_str());
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "inspector_socket.h"
|
||||
#include "llhttp.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "nbytes.h"
|
||||
#include "simdutf.h"
|
||||
#include "util-inl.h"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
|
||||
#define ACCEPT_KEY_LENGTH base64_encoded_size(20)
|
||||
#define ACCEPT_KEY_LENGTH nbytes::Base64EncodedSize(20)
|
||||
|
||||
#define DUMP_READS 0
|
||||
#define DUMP_WRITES 0
|
||||
@ -149,7 +149,7 @@ static void generate_accept_string(const std::string& client_key,
|
||||
std::string input(client_key + ws_magic);
|
||||
char hash[SHA_DIGEST_LENGTH];
|
||||
|
||||
CHECK(ACCEPT_KEY_LENGTH >= base64_encoded_size(SHA_DIGEST_LENGTH) &&
|
||||
CHECK(ACCEPT_KEY_LENGTH >= nbytes::Base64EncodedSize(SHA_DIGEST_LENGTH) &&
|
||||
"not enough space provided for base64 encode");
|
||||
USE(SHA1(reinterpret_cast<const unsigned char*>(input.data()),
|
||||
input.size(),
|
||||
|
@ -30,13 +30,14 @@
|
||||
#include "env-inl.h"
|
||||
#include "simdutf.h"
|
||||
#include "string_bytes.h"
|
||||
#include "string_search.h"
|
||||
|
||||
#include "util-inl.h"
|
||||
#include "v8-fast-api-calls.h"
|
||||
#include "v8.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include "nbytes.h"
|
||||
|
||||
#define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \
|
||||
THROW_AND_RETURN_IF_NOT_BUFFER(env, obj, "argument") \
|
||||
@ -667,7 +668,7 @@ void Fill(const FunctionCallbackInfo<Value>& args) {
|
||||
str_length = str_obj->Length() * sizeof(uint16_t);
|
||||
node::TwoByteValue str(env->isolate(), args[1]);
|
||||
if constexpr (IsBigEndian())
|
||||
SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
|
||||
CHECK(nbytes::SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length));
|
||||
|
||||
memcpy(ts_obj_data + start, *str, std::min(str_length, fill_length));
|
||||
|
||||
@ -969,19 +970,20 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
||||
if (decoded_string == nullptr)
|
||||
return args.GetReturnValue().Set(-1);
|
||||
|
||||
result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
decoded_string,
|
||||
decoder.size() / 2,
|
||||
offset / 2,
|
||||
is_forward);
|
||||
result = nbytes::SearchString(reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
decoded_string,
|
||||
decoder.size() / 2,
|
||||
offset / 2,
|
||||
is_forward);
|
||||
} else {
|
||||
result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
reinterpret_cast<const uint16_t*>(*needle_value),
|
||||
needle_value.length(),
|
||||
offset / 2,
|
||||
is_forward);
|
||||
result =
|
||||
nbytes::SearchString(reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
reinterpret_cast<const uint16_t*>(*needle_value),
|
||||
needle_value.length(),
|
||||
offset / 2,
|
||||
is_forward);
|
||||
}
|
||||
result *= 2;
|
||||
} else if (enc == UTF8) {
|
||||
@ -989,12 +991,13 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
||||
if (*needle_value == nullptr)
|
||||
return args.GetReturnValue().Set(-1);
|
||||
|
||||
result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
reinterpret_cast<const uint8_t*>(*needle_value),
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
result =
|
||||
nbytes::SearchString(reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
reinterpret_cast<const uint8_t*>(*needle_value),
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
} else if (enc == LATIN1) {
|
||||
uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length);
|
||||
if (needle_data == nullptr) {
|
||||
@ -1003,12 +1006,12 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
||||
needle->WriteOneByte(
|
||||
isolate, needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
|
||||
|
||||
result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
needle_data,
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
result = nbytes::SearchString(reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
needle_data,
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
free(needle_data);
|
||||
}
|
||||
|
||||
@ -1067,22 +1070,20 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||
if (haystack_length < 2 || needle_length < 2) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
result = SearchString(
|
||||
reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
reinterpret_cast<const uint16_t*>(needle),
|
||||
needle_length / 2,
|
||||
offset / 2,
|
||||
is_forward);
|
||||
result = nbytes::SearchString(reinterpret_cast<const uint16_t*>(haystack),
|
||||
haystack_length / 2,
|
||||
reinterpret_cast<const uint16_t*>(needle),
|
||||
needle_length / 2,
|
||||
offset / 2,
|
||||
is_forward);
|
||||
result *= 2;
|
||||
} else {
|
||||
result = SearchString(
|
||||
reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
reinterpret_cast<const uint8_t*>(needle),
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
result = nbytes::SearchString(reinterpret_cast<const uint8_t*>(haystack),
|
||||
haystack_length,
|
||||
reinterpret_cast<const uint8_t*>(needle),
|
||||
needle_length,
|
||||
offset,
|
||||
is_forward);
|
||||
}
|
||||
|
||||
args.GetReturnValue().Set(
|
||||
@ -1105,7 +1106,7 @@ int32_t IndexOfNumber(const uint8_t* buffer_data,
|
||||
if (is_forward) {
|
||||
ptr = memchr(buffer_data + offset, needle, buffer_length - offset);
|
||||
} else {
|
||||
ptr = node::stringsearch::MemrchrFill(buffer_data, needle, offset + 1);
|
||||
ptr = nbytes::stringsearch::MemrchrFill(buffer_data, needle, offset + 1);
|
||||
}
|
||||
const uint8_t* ptr_uint8 = static_cast<const uint8_t*>(ptr);
|
||||
return ptr != nullptr ? static_cast<int32_t>(ptr_uint8 - buffer_data) : -1;
|
||||
@ -1145,7 +1146,7 @@ void Swap16(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
|
||||
SPREAD_BUFFER_ARG(args[0], ts_obj);
|
||||
SwapBytes16(ts_obj_data, ts_obj_length);
|
||||
CHECK(nbytes::SwapBytes16(ts_obj_data, ts_obj_length));
|
||||
args.GetReturnValue().Set(args[0]);
|
||||
}
|
||||
|
||||
@ -1154,7 +1155,7 @@ void Swap32(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
|
||||
SPREAD_BUFFER_ARG(args[0], ts_obj);
|
||||
SwapBytes32(ts_obj_data, ts_obj_length);
|
||||
CHECK(nbytes::SwapBytes32(ts_obj_data, ts_obj_length));
|
||||
args.GetReturnValue().Set(args[0]);
|
||||
}
|
||||
|
||||
@ -1163,7 +1164,7 @@ void Swap64(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
|
||||
SPREAD_BUFFER_ARG(args[0], ts_obj);
|
||||
SwapBytes64(ts_obj_data, ts_obj_length);
|
||||
CHECK(nbytes::SwapBytes64(ts_obj_data, ts_obj_length));
|
||||
args.GetReturnValue().Set(args[0]);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,8 @@
|
||||
#include "stream_base-inl.h"
|
||||
#include "util-inl.h"
|
||||
|
||||
#include "nbytes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -455,8 +457,8 @@ Origins::Origins(
|
||||
}
|
||||
|
||||
// Make sure the start address is aligned appropriately for an nghttp2_nv*.
|
||||
char* start = AlignUp(static_cast<char*>(bs_->Data()),
|
||||
alignof(nghttp2_origin_entry));
|
||||
char* start = nbytes::AlignUp(static_cast<char*>(bs_->Data()),
|
||||
alignof(nghttp2_origin_entry));
|
||||
char* origin_contents = start + (count_ * sizeof(nghttp2_origin_entry));
|
||||
nghttp2_origin_entry* const nva =
|
||||
reinterpret_cast<nghttp2_origin_entry*>(start);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "v8.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "nbytes.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@ -31,7 +32,7 @@ NgHeaders<T>::NgHeaders(Environment* env, v8::Local<v8::Array> headers) {
|
||||
count_ * sizeof(nv_t) +
|
||||
header_string_len);
|
||||
|
||||
char* start = AlignUp(buf_.out(), alignof(nv_t));
|
||||
char* start = nbytes::AlignUp(buf_.out(), alignof(nv_t));
|
||||
char* header_contents = start + (count_ * sizeof(nv_t));
|
||||
nv_t* const nva = reinterpret_cast<nv_t*>(start);
|
||||
|
||||
|
@ -69,6 +69,7 @@
|
||||
#include <unicode/utypes.h>
|
||||
#include <unicode/uvernum.h>
|
||||
#include <unicode/uversion.h>
|
||||
#include "nbytes.h"
|
||||
|
||||
#ifdef NODE_HAVE_SMALL_ICU
|
||||
/* if this is defined, we have a 'secondary' entry point.
|
||||
@ -113,7 +114,7 @@ MaybeLocal<Object> ToBufferEndian(Environment* env, MaybeStackBuffer<T>* buf) {
|
||||
"Currently only one- or two-byte buffers are supported");
|
||||
if constexpr (sizeof(T) > 1 && IsBigEndian()) {
|
||||
SPREAD_BUFFER_ARG(ret.ToLocalChecked(), retbuf);
|
||||
SwapBytes16(retbuf_data, retbuf_length);
|
||||
CHECK(nbytes::SwapBytes16(retbuf_data, retbuf_length));
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -129,7 +130,7 @@ void CopySourceBuffer(MaybeStackBuffer<UChar>* dest,
|
||||
char* dst = reinterpret_cast<char*>(**dest);
|
||||
memcpy(dst, data, length);
|
||||
if constexpr (IsBigEndian()) {
|
||||
SwapBytes16(dst, length);
|
||||
CHECK(nbytes::SwapBytes16(dst, length));
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,7 +529,7 @@ void ConverterObject::Decode(const FunctionCallbackInfo<Value>& args) {
|
||||
char* value = reinterpret_cast<char*>(output) + beginning;
|
||||
|
||||
if constexpr (IsBigEndian()) {
|
||||
SwapBytes16(value, length);
|
||||
CHECK(nbytes::SwapBytes16(value, length));
|
||||
}
|
||||
|
||||
MaybeLocal<Value> encoded =
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "brotli/encode.h"
|
||||
#include "cjs_module_lexer_version.h"
|
||||
#include "llhttp.h"
|
||||
#include "nbytes.h"
|
||||
#include "nghttp2/nghttp2ver.h"
|
||||
#include "node.h"
|
||||
#include "simdjson.h"
|
||||
@ -133,6 +134,7 @@ Metadata::Versions::Versions() {
|
||||
simdutf = SIMDUTF_VERSION;
|
||||
sqlite = SQLITE_VERSION;
|
||||
ada = ADA_VERSION;
|
||||
nbytes = NBYTES_VERSION;
|
||||
}
|
||||
|
||||
Metadata::Release::Release() : name(NODE_RELEASE) {
|
||||
|
@ -50,6 +50,7 @@ namespace node {
|
||||
V(simdutf) \
|
||||
V(sqlite) \
|
||||
V(ada) \
|
||||
V(nbytes) \
|
||||
NODE_VERSIONS_KEY_UNDICI(V) \
|
||||
V(cjs_module_lexer)
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
#include "node_sockaddr-inl.h" // NOLINT(build/include)
|
||||
#include "env-inl.h"
|
||||
#include "base64-inl.h"
|
||||
#include "node_sockaddr.h" // NOLINT(build/include_inline)
|
||||
#include "base_object-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "memory_tracker-inl.h"
|
||||
#include "nbytes.h"
|
||||
#include "node_errors.h"
|
||||
#include "node_sockaddr-inl.h" // NOLINT(build/include_inline)
|
||||
#include "uv.h"
|
||||
|
||||
#include <memory>
|
||||
@ -308,7 +309,7 @@ bool in_network_ipv6_ipv4(
|
||||
return false;
|
||||
|
||||
ptr += sizeof(mask);
|
||||
uint32_t check = ReadUint32BE(ptr);
|
||||
uint32_t check = nbytes::ReadUint32BE(ptr);
|
||||
|
||||
return (check & m) == (htonl(net_in->sin_addr.s_addr) & m);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <memory_tracker-inl.h>
|
||||
#include <node_mutex.h>
|
||||
#include <string_bytes.h>
|
||||
#include "nbytes.h"
|
||||
#include "quic/defs.h"
|
||||
|
||||
namespace node {
|
||||
@ -71,11 +72,10 @@ size_t CID::length() const {
|
||||
|
||||
std::string CID::ToString() const {
|
||||
char dest[kMaxLength * 2];
|
||||
size_t written =
|
||||
StringBytes::hex_encode(reinterpret_cast<const char*>(ptr_->data),
|
||||
ptr_->datalen,
|
||||
dest,
|
||||
arraysize(dest));
|
||||
size_t written = nbytes::HexEncode(reinterpret_cast<const char*>(ptr_->data),
|
||||
ptr_->datalen,
|
||||
dest,
|
||||
arraysize(dest));
|
||||
return std::string(dest, written);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string_bytes.h>
|
||||
#include <util-inl.h>
|
||||
#include <algorithm>
|
||||
#include "nbytes.h"
|
||||
|
||||
namespace node {
|
||||
namespace quic {
|
||||
@ -49,8 +50,8 @@ TokenSecret::operator const char*() const {
|
||||
|
||||
std::string TokenSecret::ToString() const {
|
||||
char dest[QUIC_TOKENSECRET_LEN * 2];
|
||||
size_t written = StringBytes::hex_encode(
|
||||
*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest));
|
||||
size_t written =
|
||||
nbytes::HexEncode(*this, QUIC_TOKENSECRET_LEN, dest, arraysize(dest));
|
||||
DCHECK_EQ(written, arraysize(dest));
|
||||
return std::string(dest, written);
|
||||
}
|
||||
@ -117,7 +118,7 @@ std::string StatelessResetToken::ToString() const {
|
||||
if (ptr_ == nullptr) return std::string();
|
||||
char dest[kStatelessTokenLen * 2];
|
||||
size_t written =
|
||||
StringBytes::hex_encode(*this, kStatelessTokenLen, dest, arraysize(dest));
|
||||
nbytes::HexEncode(*this, kStatelessTokenLen, dest, arraysize(dest));
|
||||
DCHECK_EQ(written, arraysize(dest));
|
||||
return std::string(dest, written);
|
||||
}
|
||||
@ -230,7 +231,7 @@ std::string RetryToken::ToString() const {
|
||||
if (ptr_.base == nullptr) return std::string();
|
||||
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
|
||||
size_t written =
|
||||
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
|
||||
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
|
||||
DCHECK_EQ(written, dest.length());
|
||||
return std::string(dest.out(), written);
|
||||
}
|
||||
@ -289,7 +290,7 @@ std::string RegularToken::ToString() const {
|
||||
if (ptr_.base == nullptr) return std::string();
|
||||
MaybeStackBuffer<char, 32> dest(ptr_.len * 2);
|
||||
size_t written =
|
||||
StringBytes::hex_encode(*this, ptr_.len, dest.out(), dest.length());
|
||||
nbytes::HexEncode(*this, ptr_.len, dest.out(), dest.length());
|
||||
DCHECK_EQ(written, dest.length());
|
||||
return std::string(dest.out(), written);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "util-inl.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "nbytes.h"
|
||||
|
||||
namespace node {
|
||||
|
||||
@ -1069,7 +1069,7 @@ Maybe<int> SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
||||
Maybe<size_t> maybe_size = StringBytes::StorageSize(isolate, value, UTF8);
|
||||
if (maybe_size.IsNothing()) return Nothing<int>();
|
||||
data_size += maybe_size.FromJust() + 1;
|
||||
data_size = RoundUp(data_size, sizeof(void*));
|
||||
data_size = nbytes::RoundUp(data_size, sizeof(void*));
|
||||
}
|
||||
|
||||
buffer = new char[list_size + data_size];
|
||||
@ -1086,7 +1086,7 @@ Maybe<int> SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
|
||||
value,
|
||||
UTF8);
|
||||
buffer[data_offset++] = '\0';
|
||||
data_offset = RoundUp(data_offset, sizeof(void*));
|
||||
data_offset = nbytes::RoundUp(data_offset, sizeof(void*));
|
||||
}
|
||||
|
||||
list[length] = nullptr;
|
||||
|
@ -21,8 +21,8 @@
|
||||
|
||||
#include "string_bytes.h"
|
||||
|
||||
#include "base64-inl.h"
|
||||
#include "env-inl.h"
|
||||
#include "nbytes.h"
|
||||
#include "node_buffer.h"
|
||||
#include "node_errors.h"
|
||||
#include "simdutf.h"
|
||||
@ -200,67 +200,6 @@ MaybeLocal<Value> ExternTwoByteString::NewSimpleFromCopy(Isolate* isolate,
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// supports regular and URL-safe base64
|
||||
const int8_t unbase64_table[256] =
|
||||
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -1, -1, -2, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
|
||||
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
|
||||
static const int8_t unhex_table[256] =
|
||||
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
static inline unsigned unhex(uint8_t x) {
|
||||
return unhex_table[x];
|
||||
}
|
||||
|
||||
template <typename TypeName>
|
||||
static size_t hex_decode(char* buf,
|
||||
size_t len,
|
||||
const TypeName* src,
|
||||
const size_t srcLen) {
|
||||
size_t i;
|
||||
for (i = 0; i < len && i * 2 + 1 < srcLen; ++i) {
|
||||
unsigned a = unhex(static_cast<uint8_t>(src[i * 2 + 0]));
|
||||
unsigned b = unhex(static_cast<uint8_t>(src[i * 2 + 1]));
|
||||
if (!~a || !~b)
|
||||
return i;
|
||||
buf[i] = (a << 4) | b;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t StringBytes::WriteUCS2(
|
||||
Isolate* isolate, char* buf, size_t buflen, Local<String> str, int flags) {
|
||||
uint16_t* const dst = reinterpret_cast<uint16_t*>(buf);
|
||||
@ -270,7 +209,7 @@ size_t StringBytes::WriteUCS2(
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t* const aligned_dst = AlignUp(dst, sizeof(*dst));
|
||||
uint16_t* const aligned_dst = nbytes::AlignUp(dst, sizeof(*dst));
|
||||
size_t nchars;
|
||||
if (aligned_dst == dst) {
|
||||
nchars = str->Write(isolate, dst, 0, max_chars, flags);
|
||||
@ -339,7 +278,7 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
// the Buffer, so we need to reorder on BE platforms. See
|
||||
// https://nodejs.org/api/buffer.html regarding Node's "ucs2"
|
||||
// encoding specification
|
||||
if constexpr (IsBigEndian()) SwapBytes16(buf, nbytes);
|
||||
if constexpr (IsBigEndian()) CHECK(nbytes::SwapBytes16(buf, nbytes));
|
||||
|
||||
break;
|
||||
}
|
||||
@ -356,7 +295,8 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
// The input does not follow the WHATWG forgiving-base64 specification
|
||||
// adapted for base64url
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, ext->data(), ext->length());
|
||||
nbytes =
|
||||
nbytes::Base64Decode(buf, buflen, ext->data(), ext->length());
|
||||
}
|
||||
} else if (str->IsOneByte()) {
|
||||
MaybeStackBuffer<uint8_t> stack_buf(str->Length());
|
||||
@ -378,7 +318,8 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
// The input does not follow the WHATWG forgiving-base64 specification
|
||||
// (adapted for base64url with + and / replaced by - and _).
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length());
|
||||
nbytes =
|
||||
nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length());
|
||||
}
|
||||
} else {
|
||||
String::Value value(isolate, str);
|
||||
@ -395,7 +336,7 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
// The input does not follow the WHATWG forgiving-base64 specification
|
||||
// (adapted for base64url with + and / replaced by - and _).
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, *value, value.length());
|
||||
nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -411,7 +352,8 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
} else {
|
||||
// The input does not follow the WHATWG forgiving-base64 specification
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, ext->data(), ext->length());
|
||||
nbytes =
|
||||
nbytes::Base64Decode(buf, buflen, ext->data(), ext->length());
|
||||
}
|
||||
} else if (str->IsOneByte()) {
|
||||
MaybeStackBuffer<uint8_t> stack_buf(str->Length());
|
||||
@ -432,7 +374,8 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
// The input does not follow the WHATWG forgiving-base64 specification
|
||||
// (adapted for base64url with + and / replaced by - and _).
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, *stack_buf, stack_buf.length());
|
||||
nbytes =
|
||||
nbytes::Base64Decode(buf, buflen, *stack_buf, stack_buf.length());
|
||||
}
|
||||
} else {
|
||||
String::Value value(isolate, str);
|
||||
@ -447,7 +390,7 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
} else {
|
||||
// The input does not follow the WHATWG base64 specification
|
||||
// https://infra.spec.whatwg.org/#forgiving-base64-decode
|
||||
nbytes = base64_decode(buf, buflen, *value, value.length());
|
||||
nbytes = nbytes::Base64Decode(buf, buflen, *value, value.length());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -455,10 +398,10 @@ size_t StringBytes::Write(Isolate* isolate,
|
||||
case HEX:
|
||||
if (str->IsExternalOneByte()) {
|
||||
auto ext = str->GetExternalOneByteStringResource();
|
||||
nbytes = hex_decode(buf, buflen, ext->data(), ext->length());
|
||||
nbytes = nbytes::HexDecode(buf, buflen, ext->data(), ext->length());
|
||||
} else {
|
||||
String::Value value(isolate, str);
|
||||
nbytes = hex_decode(buf, buflen, *value, value.length());
|
||||
nbytes = nbytes::HexDecode(buf, buflen, *value, value.length());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -568,85 +511,6 @@ Maybe<size_t> StringBytes::Size(Isolate* isolate,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static void force_ascii_slow(const char* src, char* dst, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
dst[i] = src[i] & 0x7f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void force_ascii(const char* src, char* dst, size_t len) {
|
||||
if (len < 16) {
|
||||
force_ascii_slow(src, dst, len);
|
||||
return;
|
||||
}
|
||||
|
||||
const unsigned bytes_per_word = sizeof(uintptr_t);
|
||||
const unsigned align_mask = bytes_per_word - 1;
|
||||
const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
|
||||
const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
|
||||
|
||||
if (src_unalign > 0) {
|
||||
if (src_unalign == dst_unalign) {
|
||||
const unsigned unalign = bytes_per_word - src_unalign;
|
||||
force_ascii_slow(src, dst, unalign);
|
||||
src += unalign;
|
||||
dst += unalign;
|
||||
len -= src_unalign;
|
||||
} else {
|
||||
force_ascii_slow(src, dst, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN64) || defined(_LP64)
|
||||
const uintptr_t mask = ~0x8080808080808080ll;
|
||||
#else
|
||||
const uintptr_t mask = ~0x80808080l;
|
||||
#endif
|
||||
|
||||
const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
|
||||
uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
|
||||
|
||||
for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
|
||||
dstw[i] = srcw[i] & mask;
|
||||
}
|
||||
|
||||
const unsigned remainder = len & align_mask;
|
||||
if (remainder > 0) {
|
||||
const size_t offset = len - remainder;
|
||||
force_ascii_slow(src + offset, dst + offset, remainder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t StringBytes::hex_encode(
|
||||
const char* src,
|
||||
size_t slen,
|
||||
char* dst,
|
||||
size_t dlen) {
|
||||
// We know how much we'll write, just make sure that there's space.
|
||||
CHECK(dlen >= MultiplyWithOverflowCheck<size_t>(slen, 2u) &&
|
||||
"not enough space provided for hex encode");
|
||||
|
||||
dlen = slen * 2;
|
||||
for (size_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
uint8_t val = static_cast<uint8_t>(src[i]);
|
||||
dst[k + 0] = hex[val >> 4];
|
||||
dst[k + 1] = hex[val & 15];
|
||||
}
|
||||
|
||||
return dlen;
|
||||
}
|
||||
|
||||
std::string StringBytes::hex_encode(const char* src, size_t slen) {
|
||||
size_t dlen = slen * 2;
|
||||
std::string dst(dlen, '\0');
|
||||
hex_encode(src, slen, dst.data(), dlen);
|
||||
return dst;
|
||||
}
|
||||
|
||||
#define CHECK_BUFLEN_IN_RANGE(len) \
|
||||
do { \
|
||||
if ((len) > Buffer::kMaxLength) { \
|
||||
@ -688,7 +552,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
force_ascii(buf, out, buflen);
|
||||
nbytes::ForceAscii(buf, out, buflen);
|
||||
return ExternOneByteString::New(isolate, out, buflen, error);
|
||||
} else {
|
||||
return ExternOneByteString::NewFromCopy(isolate, buf, buflen, error);
|
||||
@ -747,7 +611,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
||||
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
|
||||
return MaybeLocal<Value>();
|
||||
}
|
||||
size_t written = hex_encode(buf, buflen, dst, dlen);
|
||||
size_t written = nbytes::HexEncode(buf, buflen, dst, dlen);
|
||||
CHECK_EQ(written, dlen);
|
||||
|
||||
return ExternOneByteString::New(isolate, dst, dlen, error);
|
||||
@ -810,7 +674,7 @@ MaybeLocal<Value> StringBytes::Encode(Isolate* isolate,
|
||||
}
|
||||
size_t nbytes = buflen * sizeof(uint16_t);
|
||||
memcpy(dst, buf, nbytes);
|
||||
SwapBytes16(reinterpret_cast<char*>(dst), nbytes);
|
||||
CHECK(nbytes::SwapBytes16(reinterpret_cast<char*>(dst), nbytes));
|
||||
return ExternTwoByteString::New(isolate, dst, buflen, error);
|
||||
} else {
|
||||
return ExternTwoByteString::NewFromCopy(isolate, buf, buflen, error);
|
||||
|
@ -98,13 +98,6 @@ class StringBytes {
|
||||
enum encoding encoding,
|
||||
v8::Local<v8::Value>* error);
|
||||
|
||||
static size_t hex_encode(const char* src,
|
||||
size_t slen,
|
||||
char* dst,
|
||||
size_t dlen);
|
||||
|
||||
static std::string hex_encode(const char* src, size_t slen);
|
||||
|
||||
private:
|
||||
static size_t WriteUCS2(v8::Isolate* isolate,
|
||||
char* buf,
|
||||
|
104
src/util-inl.h
104
src/util-inl.h
@ -30,41 +30,6 @@
|
||||
#include "node_revert.h"
|
||||
#include "util.h"
|
||||
|
||||
// These are defined by <sys/byteorder.h> or <netinet/in.h> on some systems.
|
||||
// To avoid warnings, undefine them before redefining them.
|
||||
#ifdef BSWAP_2
|
||||
# undef BSWAP_2
|
||||
#endif
|
||||
#ifdef BSWAP_4
|
||||
# undef BSWAP_4
|
||||
#endif
|
||||
#ifdef BSWAP_8
|
||||
# undef BSWAP_8
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#define BSWAP_2(x) _byteswap_ushort(x)
|
||||
#define BSWAP_4(x) _byteswap_ulong(x)
|
||||
#define BSWAP_8(x) _byteswap_uint64(x)
|
||||
#else
|
||||
#define BSWAP_2(x) ((x) << 8) | ((x) >> 8)
|
||||
#define BSWAP_4(x) \
|
||||
(((x) & 0xFF) << 24) | \
|
||||
(((x) & 0xFF00) << 8) | \
|
||||
(((x) >> 8) & 0xFF00) | \
|
||||
(((x) >> 24) & 0xFF)
|
||||
#define BSWAP_8(x) \
|
||||
(((x) & 0xFF00000000000000ull) >> 56) | \
|
||||
(((x) & 0x00FF000000000000ull) >> 40) | \
|
||||
(((x) & 0x0000FF0000000000ull) >> 24) | \
|
||||
(((x) & 0x000000FF00000000ull) >> 8) | \
|
||||
(((x) & 0x00000000FF000000ull) << 8) | \
|
||||
(((x) & 0x0000000000FF0000ull) << 24) | \
|
||||
(((x) & 0x000000000000FF00ull) << 40) | \
|
||||
(((x) & 0x00000000000000FFull) << 56)
|
||||
#endif
|
||||
|
||||
#define CHAR_TEST(bits, name, expr) \
|
||||
template <typename T> \
|
||||
bool name(const T ch) { \
|
||||
@ -214,75 +179,6 @@ inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
void SwapBytes16(char* data, size_t nbytes) {
|
||||
CHECK_EQ(nbytes % 2, 0);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (AlignUp(data, sizeof(uint16_t)) == data) {
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
|
||||
size_t len16 = nbytes / sizeof(*data16);
|
||||
for (size_t i = 0; i < len16; i++) {
|
||||
data16[i] = BSWAP_2(data16[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t temp;
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
|
||||
memcpy(&temp, &data[i], sizeof(temp));
|
||||
temp = BSWAP_2(temp);
|
||||
memcpy(&data[i], &temp, sizeof(temp));
|
||||
}
|
||||
}
|
||||
|
||||
void SwapBytes32(char* data, size_t nbytes) {
|
||||
CHECK_EQ(nbytes % 4, 0);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
if (AlignUp(data, sizeof(uint32_t)) == data) {
|
||||
uint32_t* data32 = reinterpret_cast<uint32_t*>(data);
|
||||
size_t len32 = nbytes / sizeof(*data32);
|
||||
for (size_t i = 0; i < len32; i++) {
|
||||
data32[i] = BSWAP_4(data32[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t temp;
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
|
||||
memcpy(&temp, &data[i], sizeof(temp));
|
||||
temp = BSWAP_4(temp);
|
||||
memcpy(&data[i], &temp, sizeof(temp));
|
||||
}
|
||||
}
|
||||
|
||||
void SwapBytes64(char* data, size_t nbytes) {
|
||||
CHECK_EQ(nbytes % 8, 0);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (AlignUp(data, sizeof(uint64_t)) == data) {
|
||||
// MSVC has no strict aliasing, and is able to highly optimize this case.
|
||||
uint64_t* data64 = reinterpret_cast<uint64_t*>(data);
|
||||
size_t len64 = nbytes / sizeof(*data64);
|
||||
for (size_t i = 0; i < len64; i++) {
|
||||
data64[i] = BSWAP_8(data64[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t temp;
|
||||
for (size_t i = 0; i < nbytes; i += sizeof(temp)) {
|
||||
memcpy(&temp, &data[i], sizeof(temp));
|
||||
temp = BSWAP_8(temp);
|
||||
memcpy(&data[i], &temp, sizeof(temp));
|
||||
}
|
||||
}
|
||||
|
||||
char ToLower(char c) {
|
||||
return std::tolower(c, std::locale::classic());
|
||||
}
|
||||
|
21
src/util.h
21
src/util.h
@ -358,14 +358,6 @@ inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
|
||||
return OneByteString(isolate, arr.data(), N - 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
|
||||
// multiple of the word size (checked by function).
|
||||
inline void SwapBytes16(char* data, size_t nbytes);
|
||||
inline void SwapBytes32(char* data, size_t nbytes);
|
||||
inline void SwapBytes64(char* data, size_t nbytes);
|
||||
|
||||
// tolower() is locale-sensitive. Use ToLower() instead.
|
||||
inline char ToLower(char c);
|
||||
inline std::string ToLower(const std::string& in);
|
||||
@ -794,19 +786,6 @@ constexpr inline bool IsBigEndian() {
|
||||
static_assert(IsLittleEndian() || IsBigEndian(),
|
||||
"Node.js does not support mixed-endian systems");
|
||||
|
||||
// Round up a to the next highest multiple of b.
|
||||
template <typename T>
|
||||
constexpr T RoundUp(T a, T b) {
|
||||
return a % b != 0 ? a + b - (a % b) : a;
|
||||
}
|
||||
|
||||
// Align ptr to an `alignment`-bytes boundary.
|
||||
template <typename T, typename U>
|
||||
constexpr T* AlignUp(T* ptr, U alignment) {
|
||||
return reinterpret_cast<T*>(
|
||||
RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
|
||||
}
|
||||
|
||||
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
|
||||
public:
|
||||
inline explicit SlicedArguments(
|
||||
|
@ -1,13 +1,12 @@
|
||||
#include "base64-inl.h"
|
||||
#include "nbytes.h"
|
||||
#include "simdutf.h"
|
||||
#include "util-inl.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using node::base64_decode;
|
||||
|
||||
TEST(Base64Test, Encode) {
|
||||
auto test = [](const char* string, const char* base64_string) {
|
||||
const size_t len = strlen(base64_string);
|
||||
@ -70,7 +69,7 @@ TEST(Base64Test, Decode) {
|
||||
const size_t len = strlen(string);
|
||||
char* const buffer = new char[len + 1];
|
||||
buffer[len] = 0;
|
||||
base64_decode(buffer, len, base64_string, strlen(base64_string));
|
||||
nbytes::Base64Decode(buffer, len, base64_string, strlen(base64_string));
|
||||
EXPECT_STREQ(string, buffer);
|
||||
delete[] buffer;
|
||||
};
|
||||
|
@ -23,6 +23,7 @@ const expected_keys = [
|
||||
'sqlite',
|
||||
'ada',
|
||||
'cjs_module_lexer',
|
||||
'nbytes',
|
||||
];
|
||||
|
||||
const hasUndici = process.config.variables.node_builtin_shareable_builtins.includes('deps/undici/undici.js');
|
||||
@ -62,6 +63,7 @@ assert.match(process.versions.brotli, commonTemplate);
|
||||
assert.match(process.versions.llhttp, commonTemplate);
|
||||
assert.match(process.versions.node, commonTemplate);
|
||||
assert.match(process.versions.uv, commonTemplate);
|
||||
assert.match(process.versions.nbytes, commonTemplate);
|
||||
assert.match(process.versions.zlib, /^\d+(?:\.\d+){1,3}(?:-.*)?$/);
|
||||
|
||||
if (hasUndici) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user