site-panzai/node_modules/bare-buffer/binding.c

2042 lines
51 KiB
C
Raw Normal View History

2026-11-13 13:57:04 +01:00
#include <assert.h>
#include <bare.h>
#include <base64.h>
#include <hex.h>
#include <js.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <utf.h>
// Results up to this length are encoded on the stack, so that the common case
// of a short hex or base64 string involves neither an allocation nor the
// bookkeeping of an external string.
#define BARE_BUFFER_STACK_STRING_MAX 1024
// A buffer may be viewed at any byte offset, so the code units of a UTF-16
// string are not necessarily aligned within its backing store. Spans that are
// not are staged through an aligned copy.
#define BARE_BUFFER_STACK_UTF16_MAX (BARE_BUFFER_STACK_STRING_MAX / sizeof(utf16_t))
// A typed callback cannot raise, so an argument it rejects is reported as a
// result no successful call can produce and JavaScript raises on it. There is
// one sentinel per error the untyped callback raises directly, so that the
// error does not change once V8 takes the fast path.
#define BARE_BUFFER_OUT_OF_BOUNDS INT32_MIN
#define BARE_BUFFER_INVALID_BUFFER (INT32_MIN + 1)
#define BARE_BUFFER_INVALID_STRING (INT32_MIN + 2)
static inline bool
bare_buffer__is_aligned(const void *data) {
return ((uintptr_t) data & (sizeof(utf16_t) - 1)) == 0;
}
static _Atomic size_t bare_buffer__max_arraybuffer_length;
static _Atomic size_t bare_buffer__max_string_length;
static inline void
bare_buffer__read_limits(js_env_t *env) {
int err;
js_platform_t *platform;
err = js_get_env_platform(env, &platform);
assert(err == 0);
js_platform_limits_t limits = {
.version = 0,
};
err = js_get_platform_limits(platform, &limits);
assert(err == 0);
atomic_store_explicit(&bare_buffer__max_arraybuffer_length, limits.arraybuffer_length, memory_order_relaxed);
atomic_store_explicit(&bare_buffer__max_string_length, limits.string_length, memory_order_relaxed);
}
static inline size_t
bare_buffer__arraybuffer_limit(void) {
return atomic_load_explicit(&bare_buffer__max_arraybuffer_length, memory_order_relaxed);
}
static inline size_t
bare_buffer__string_limit(void) {
return atomic_load_explicit(&bare_buffer__max_string_length, memory_order_relaxed);
}
// Nothing between here and the raising helpers below raises an error. A typed
// callback is entered without a handle scope and V8 does not support reporting
// errors from one, so raising there aborts the process. An argument that does
// not check out is reported to the caller instead, and a condition that has to
// reach JavaScript is returned as a negative count for the caller to raise.
static inline bool
bare_buffer__is_buffer(js_env_t *env, js_value_t *value) {
int err;
bool is_arraybuffer;
err = js_is_arraybuffer(env, value, &is_arraybuffer);
assert(err == 0);
if (is_arraybuffer) return true;
bool is_shared;
err = js_is_sharedarraybuffer(env, value, &is_shared);
assert(err == 0);
return is_shared;
}
static inline int
bare_buffer__get_info(js_env_t *env, js_value_t *buffer, void **data, size_t *len) {
int err;
bool is_arraybuffer;
err = js_is_arraybuffer(env, buffer, &is_arraybuffer);
assert(err == 0);
if (is_arraybuffer) {
err = js_get_arraybuffer_info(env, buffer, data, len);
assert(err == 0);
return 0;
}
bool is_shared;
err = js_is_sharedarraybuffer(env, buffer, &is_shared);
assert(err == 0);
if (is_shared) {
err = js_get_sharedarraybuffer_info(env, buffer, data, len);
assert(err == 0);
return 0;
}
return -1;
}
static inline bool
bare_buffer__is_string(js_env_t *env, js_value_t *value) {
int err;
bool is_string;
err = js_is_string(env, value, &is_string);
assert(err == 0);
return is_string;
}
// Returns 0, or the sentinel for the argument that did not check out.
static inline int
bare_buffer__slice(js_env_t *env, js_value_t *buffer, int64_t offset, int64_t len, void **data) {
int err;
void *base;
size_t byte_len;
err = bare_buffer__get_info(env, buffer, &base, &byte_len);
if (err < 0) return BARE_BUFFER_INVALID_BUFFER;
if (offset < 0 || len < 0 || (uint64_t) offset + (uint64_t) len > byte_len) {
return BARE_BUFFER_OUT_OF_BOUNDS;
}
// A detached or zero length store has no address, and the string and codec
// APIs read a null destination as a request for the length a write would need
// rather than as a write of no bytes.
static uint8_t nowhere;
// Only an empty store lacks an address, so the bounds check above has already
// narrowed the span to nothing and the single byte is never reached.
assert(base != NULL || len == 0);
*data = base == NULL ? &nowhere : (uint8_t *) base + offset;
return 0;
}
static inline int
bare_buffer__alloc(size_t len, void **result) {
void *data = malloc(len);
if (data == NULL) return -1;
*result = data;
return 0;
}
static int64_t
bare_buffer__write_utf8(js_env_t *env, js_value_t *string, utf8_t *buf, int64_t len) {
int err;
size_t str_len;
err = js_get_value_string_utf8(env, string, NULL, 0, &str_len);
assert(err == 0);
size_t written;
if (str_len <= (size_t) len) {
err = js_get_value_string_utf8(env, string, buf, str_len, &written);
assert(err == 0);
return written;
}
// A truncated write stops on a code point boundary, so it leaves at most the
// three bytes of an incomplete sequence. Keeping those is enough to undo the
// null terminator, which can only land among them.
size_t tail_at = (size_t) len - (len < 3 ? (size_t) len : 3);
utf8_t tail[3];
memcpy(tail, &buf[tail_at], (size_t) len - tail_at);
err = js_get_value_string_utf8(env, string, buf, len, &written);
assert(err == 0);
if (written < (size_t) len && written >= tail_at) {
memcpy(&buf[written], &tail[written - tail_at], (size_t) len - written);
}
return written;
}
static int64_t
bare_buffer__write_latin1(js_env_t *env, js_value_t *string, latin1_t *buf, int64_t len) {
int err;
size_t str_len;
err = js_get_value_string_latin1(env, string, NULL, 0, &str_len);
assert(err == 0);
if (str_len > (size_t) len) str_len = len;
size_t written;
err = js_get_value_string_latin1(env, string, buf, str_len, &written);
assert(err == 0);
return written;
}
static int64_t
bare_buffer__write_utf16le(js_env_t *env, js_value_t *string, uint8_t *bytes, int64_t len) {
int err;
size_t str_len;
err = js_get_value_string_utf16le(env, string, NULL, 0, &str_len);
assert(err == 0);
size_t capacity = (size_t) len / sizeof(utf16_t);
if (str_len > capacity) str_len = capacity;
size_t written;
if (bare_buffer__is_aligned(bytes)) {
err = js_get_value_string_utf16le(env, string, (utf16_t *) bytes, str_len, &written);
assert(err == 0);
return written * sizeof(utf16_t);
}
utf16_t stack[BARE_BUFFER_STACK_UTF16_MAX];
utf16_t *str = stack;
if (str_len > BARE_BUFFER_STACK_UTF16_MAX) {
err = bare_buffer__alloc(str_len * sizeof(utf16_t), (void **) &str);
if (err < 0) return -1;
}
err = js_get_value_string_utf16le(env, string, str, str_len, &written);
assert(err == 0);
memcpy(bytes, str, written * sizeof(utf16_t));
if (str != stack) free(str);
return written * sizeof(utf16_t);
}
static int64_t
bare_buffer__write_base64(js_env_t *env, js_value_t *string, utf8_t *buf, int64_t len) {
int err;
js_string_encoding_t encoding;
const void *str;
size_t str_len;
js_string_view_t *str_view;
err = js_get_string_view(env, string, &encoding, &str, &str_len, &str_view);
assert(err == 0);
size_t written = len;
if (encoding == js_utf16le) {
err = base64_decode_utf16le(str, str_len, buf, &written);
} else {
err = base64_decode_utf8(str, str_len, buf, &written);
}
int64_t decoded = err == 0 ? (int64_t) written : -1;
err = js_release_string_view(env, str_view);
assert(err == 0);
return decoded;
}
static int64_t
bare_buffer__write_hex(js_env_t *env, js_value_t *string, utf8_t *buf, int64_t len) {
int err;
js_string_encoding_t encoding;
const void *str;
size_t str_len;
js_string_view_t *str_view;
err = js_get_string_view(env, string, &encoding, &str, &str_len, &str_view);
assert(err == 0);
size_t written = len;
if (encoding == js_utf16le) {
err = hex_decode_utf16le(str, str_len, buf, &written);
} else {
err = hex_decode_utf8(str, str_len, buf, &written);
}
int64_t decoded = err == 0 ? (int64_t) written : -1;
err = js_release_string_view(env, str_view);
assert(err == 0);
return decoded;
}
static bool
bare_buffer__check_buffer(js_env_t *env, js_value_t *value) {
int err;
if (bare_buffer__is_buffer(env, value)) return true;
err = js_throw_type_error(env, NULL, "Buffer must be an array buffer");
assert(err == 0);
return false;
}
static bool
bare_buffer__check_number(js_env_t *env, js_value_t *value, const char *message) {
int err;
bool is_number;
err = js_is_number(env, value, &is_number);
assert(err == 0);
if (!is_number) {
err = js_throw_type_error(env, NULL, message);
assert(err == 0);
}
return is_number;
}
static bool
bare_buffer__check_string(js_env_t *env, js_value_t *value, const char *message) {
int err;
if (bare_buffer__is_string(env, value)) return true;
err = js_throw_type_error(env, NULL, message);
assert(err == 0);
return false;
}
static js_value_t *
bare_buffer__view_out_of_bounds(js_env_t *env) {
int err;
err = js_throw_range_error(env, NULL, "View is out of bounds of its backing store");
assert(err == 0);
return NULL;
}
static js_value_t *
bare_buffer__out_of_memory(js_env_t *env) {
int err;
err = js_throw_error(env, NULL, "Out of memory");
assert(err == 0);
return NULL;
}
static js_value_t *
bare_buffer__invalid_string_length(js_env_t *env) {
int err;
err = js_throw_range_error(env, NULL, "Invalid string length");
assert(err == 0);
return NULL;
}
static inline int64_t
bare_buffer__to_int64(js_env_t *env, js_value_t *value) {
int err;
int64_t result;
err = js_get_value_int64(env, value, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_alloc(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_number(env, argv[0], "Length must be a number")) return NULL;
int64_t len = bare_buffer__to_int64(env, argv[0]);
if (len < 0) {
err = js_throw_range_error(env, NULL, "Length must not be negative");
assert(err == 0);
return NULL;
}
if ((uint64_t) len > bare_buffer__arraybuffer_limit()) {
err = js_throw_range_error(env, NULL, "Length must not exceed the maximum array buffer length");
assert(err == 0);
return NULL;
}
js_value_t *result;
err = js_create_arraybuffer(env, len, NULL, &result);
if (err < 0) return NULL;
return result;
}
static js_value_t *
bare_buffer_alloc_unsafe(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_number(env, argv[0], "Length must be a number")) return NULL;
int64_t len = bare_buffer__to_int64(env, argv[0]);
if (len < 0) {
err = js_throw_range_error(env, NULL, "Length must not be negative");
assert(err == 0);
return NULL;
}
if ((uint64_t) len > bare_buffer__arraybuffer_limit()) {
err = js_throw_range_error(env, NULL, "Length must not exceed the maximum array buffer length");
assert(err == 0);
return NULL;
}
js_value_t *result;
err = js_create_unsafe_arraybuffer(env, len, NULL, &result);
if (err < 0) return NULL;
return result;
}
static int64_t
bare_buffer_typed_byte_length_utf8(js_value_t *receiver, js_value_t *str, js_typed_callback_info_t *info) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_string(env, str)) return BARE_BUFFER_INVALID_STRING;
size_t str_len;
err = js_get_value_string_utf8(env, str, NULL, 0, &str_len);
assert(err == 0);
return str_len;
}
static js_value_t *
bare_buffer_byte_length_utf8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 1;
js_value_t *argv[1];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_string(env, argv[0], "String must be a string")) return NULL;
size_t str_len;
err = js_get_value_string_utf8(env, argv[0], NULL, 0, &str_len);
assert(err == 0);
js_value_t *result;
err = js_create_int64(env, str_len, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_to_string_utf8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
js_value_t *result;
err = js_create_string_utf8(env, buf, len, &result);
if (err < 0) return NULL;
return result;
}
static int32_t
bare_buffer_typed_validate_utf8(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
utf8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return utf8_validate(buf, len);
}
static js_value_t *
bare_buffer_validate_utf8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int32_t valid = err == 0 ? utf8_validate(buf, len) : err;
js_value_t *result;
err = js_create_int32(env, valid, &result);
assert(err == 0);
return result;
}
static int64_t
bare_buffer_typed_write_utf8(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *string,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_string(env, string)) return BARE_BUFFER_INVALID_STRING;
utf8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return bare_buffer__write_utf8(env, string, buf, len);
}
static js_value_t *
bare_buffer_write_utf8(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_string(env, argv[3], "String must be a string")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t written = err == 0 ? bare_buffer__write_utf8(env, argv[3], buf, len) : err;
js_value_t *result;
err = js_create_int64(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_to_string_utf16le(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
uint8_t *bytes;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &bytes);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
size_t str_len = (size_t) len / sizeof(utf16_t);
if (str_len > bare_buffer__string_limit()) {
return bare_buffer__invalid_string_length(env);
}
js_value_t *result;
if (bare_buffer__is_aligned(bytes)) {
err = js_create_string_utf16le(env, (utf16_t *) bytes, str_len, &result);
if (err < 0) return NULL;
return result;
}
utf16_t stack[BARE_BUFFER_STACK_UTF16_MAX];
utf16_t *str = stack;
if (str_len > BARE_BUFFER_STACK_UTF16_MAX) {
err = bare_buffer__alloc(str_len * sizeof(utf16_t), (void **) &str);
if (err < 0) return bare_buffer__out_of_memory(env);
}
memcpy(str, bytes, str_len * sizeof(utf16_t));
err = js_create_string_utf16le(env, str, str_len, &result);
if (str != stack) free(str);
if (err < 0) return NULL;
return result;
}
static int64_t
bare_buffer_typed_write_utf16le(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *string,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_string(env, string)) return BARE_BUFFER_INVALID_STRING;
uint8_t *bytes;
err = bare_buffer__slice(env, handle, offset, len, (void **) &bytes);
if (err != 0) return err;
return bare_buffer__write_utf16le(env, string, bytes, len);
}
static js_value_t *
bare_buffer_write_utf16le(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_string(env, argv[3], "String must be a string")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
uint8_t *bytes;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &bytes);
int64_t written = err == 0 ? bare_buffer__write_utf16le(env, argv[3], bytes, len) : err;
js_value_t *result;
err = js_create_int64(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_to_string_latin1(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
latin1_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
js_value_t *result;
err = js_create_string_latin1(env, buf, len, &result);
if (err < 0) return NULL;
return result;
}
static int64_t
bare_buffer_typed_write_latin1(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *string,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_string(env, string)) return BARE_BUFFER_INVALID_STRING;
latin1_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return bare_buffer__write_latin1(env, string, buf, len);
}
static js_value_t *
bare_buffer_write_latin1(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_string(env, argv[3], "String must be a string")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
latin1_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t written = err == 0 ? bare_buffer__write_latin1(env, argv[3], buf, len) : err;
js_value_t *result;
err = js_create_int64(env, written, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_to_string_base64(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
size_t str_len;
err = base64_encode_utf8(buf, len, NULL, &str_len);
assert(err == 0);
if (str_len > bare_buffer__string_limit()) {
return bare_buffer__invalid_string_length(env);
}
utf8_t stack[BARE_BUFFER_STACK_STRING_MAX];
utf8_t *str = stack;
if (str_len > sizeof(stack)) {
err = bare_buffer__alloc(str_len, (void **) &str);
if (err < 0) return bare_buffer__out_of_memory(env);
}
err = base64_encode_utf8(buf, len, str, &str_len);
assert(err == 0);
js_value_t *result;
err = js_create_string_latin1(env, str, str_len, &result);
if (str != stack) free(str);
if (err < 0) return NULL;
return result;
}
static js_value_t *
bare_buffer_to_string_base64url(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
size_t str_len;
err = base64url_encode_utf8(buf, len, NULL, &str_len);
assert(err == 0);
if (str_len > bare_buffer__string_limit()) {
return bare_buffer__invalid_string_length(env);
}
utf8_t stack[BARE_BUFFER_STACK_STRING_MAX];
utf8_t *str = stack;
if (str_len > sizeof(stack)) {
err = bare_buffer__alloc(str_len, (void **) &str);
if (err < 0) return bare_buffer__out_of_memory(env);
}
err = base64url_encode_utf8(buf, len, str, &str_len);
assert(err == 0);
js_value_t *result;
err = js_create_string_latin1(env, str, str_len, &result);
if (str != stack) free(str);
if (err < 0) return NULL;
return result;
}
static int64_t
bare_buffer_typed_write_base64(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *string,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_string(env, string)) return BARE_BUFFER_INVALID_STRING;
utf8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return bare_buffer__write_base64(env, string, buf, len);
}
static js_value_t *
bare_buffer_write_base64(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_string(env, argv[3], "String must be a string")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t decoded = err == 0 ? bare_buffer__write_base64(env, argv[3], buf, len) : err;
js_value_t *result;
err = js_create_int64(env, decoded, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_to_string_hex(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err < 0) return bare_buffer__view_out_of_bounds(env);
size_t str_len;
err = hex_encode_utf8(buf, len, NULL, &str_len);
assert(err == 0);
if (str_len > bare_buffer__string_limit()) {
return bare_buffer__invalid_string_length(env);
}
utf8_t stack[BARE_BUFFER_STACK_STRING_MAX];
utf8_t *str = stack;
if (str_len > sizeof(stack)) {
err = bare_buffer__alloc(str_len, (void **) &str);
if (err < 0) return bare_buffer__out_of_memory(env);
}
err = hex_encode_utf8(buf, len, str, &str_len);
assert(err == 0);
js_value_t *result;
err = js_create_string_latin1(env, str, str_len, &result);
if (str != stack) free(str);
if (err < 0) return NULL;
return result;
}
static int64_t
bare_buffer_typed_write_hex(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *string,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_string(env, string)) return BARE_BUFFER_INVALID_STRING;
utf8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return bare_buffer__write_hex(env, string, buf, len);
}
static js_value_t *
bare_buffer_write_hex(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 4;
js_value_t *argv[4];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_string(env, argv[3], "String must be a string")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
utf8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t decoded = err == 0 ? bare_buffer__write_hex(env, argv[3], buf, len) : err;
js_value_t *result;
err = js_create_int64(env, decoded, &result);
assert(err == 0);
return result;
}
static int32_t
bare_buffer_typed_validate_ascii(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
ascii_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
return ascii_validate(buf, len);
}
static js_value_t *
bare_buffer_validate_ascii(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
ascii_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int32_t valid = err == 0 ? ascii_validate(buf, len) : err;
js_value_t *result;
err = js_create_int32(env, valid, &result);
assert(err == 0);
return result;
}
static inline void
bare_buffer__swap16(uint8_t *data, size_t len) {
for (size_t i = 0; i + 1 < len; i += 2) {
uint8_t a = data[i];
data[i] = data[i + 1];
data[i + 1] = a;
}
}
static inline void
bare_buffer__swap32(uint8_t *data, size_t len) {
for (size_t i = 0; i + 3 < len; i += 4) {
uint8_t a = data[i];
uint8_t b = data[i + 1];
data[i] = data[i + 3];
data[i + 1] = data[i + 2];
data[i + 2] = b;
data[i + 3] = a;
}
}
static inline void
bare_buffer__swap64(uint8_t *data, size_t len) {
for (size_t i = 0; i + 7 < len; i += 8) {
for (size_t j = 0; j < 4; j++) {
uint8_t a = data[i + j];
data[i + j] = data[i + 7 - j];
data[i + 7 - j] = a;
}
}
}
static const uint8_t *
bare_buffer__memrchr(const uint8_t *data, uint8_t c, size_t len) {
const size_t chunk_len = 512;
while (len > 0) {
size_t take = len < chunk_len ? len : chunk_len;
const uint8_t *chunk = &data[len - take];
// When matches are dense the last one is within a few bytes of the end,
// which is far cheaper to find by looking than by narrowing.
size_t probe = take < 8 ? take : 8;
for (size_t i = 0; i < probe; i++) {
if (chunk[take - 1 - i] == c) return &chunk[take - 1 - i];
}
if (memchr(chunk, c, take - probe) != NULL) {
size_t lo = 0;
size_t hi = take - probe;
while (hi - lo > 1) {
size_t mid = lo + (hi - lo) / 2;
if (memchr(&chunk[mid], c, hi - mid) != NULL) lo = mid;
else hi = mid;
}
return &chunk[lo];
}
len -= take;
}
return NULL;
}
static int64_t
bare_buffer__index_of(const uint8_t *data, size_t len, const uint8_t *needle, size_t needle_len, int64_t start) {
if (needle_len == 0 || needle_len > len) return -1;
// Compared before narrowing, so that a start past the end cannot wrap into a
// valid position on a target where size_t is narrower than int64_t.
if (start < 0 || (uint64_t) start > len - needle_len) return -1;
size_t from = (size_t) start;
if (needle_len == 1) {
const uint8_t *at = memchr(&data[from], needle[0], len - from);
return at == NULL ? -1 : (int64_t) (at - data);
}
size_t end = len - needle_len + 1;
size_t i = from;
size_t rejected = 0;
while (i < end) {
const uint8_t *at = memchr(&data[i], needle[0], end - i);
if (at == NULL) return -1;
i = (size_t) (at - data);
if (memcmp(&data[i + 1], &needle[1], needle_len - 1) == 0) return (int64_t) i;
i++;
if (++rejected == 32) break;
}
if (i >= end) return -1;
size_t skip[256];
for (size_t j = 0; j < 256; j++) {
skip[j] = needle_len;
}
for (size_t j = 0; j < needle_len - 1; j++) {
skip[needle[j]] = needle_len - 1 - j;
}
size_t last = needle_len - 1;
while (i < end) {
if (data[i + last] == needle[last] && memcmp(&data[i], needle, last) == 0) {
return (int64_t) i;
}
i += skip[data[i + last]];
}
return -1;
}
static int64_t
bare_buffer__last_index_of(const uint8_t *data, size_t len, const uint8_t *needle, size_t needle_len, int64_t start) {
if (needle_len == 0 || needle_len > len) return -1;
// A start before the first byte names no position, the same reading that has
// the forward search report no match for a start past the last one.
if (start < 0) return -1;
size_t last = len - needle_len;
size_t from = (uint64_t) start > last ? last : (size_t) start;
if (needle_len == 1) {
const uint8_t *at = bare_buffer__memrchr(data, needle[0], from + 1);
return at == NULL ? -1 : (int64_t) (at - data);
}
size_t i = from;
size_t rejected = 0;
while (rejected < 32) {
const uint8_t *at = bare_buffer__memrchr(data, needle[0], i + 1);
if (at == NULL) return -1;
i = (size_t) (at - data);
if (memcmp(&data[i + 1], &needle[1], needle_len - 1) == 0) return (int64_t) i;
if (i == 0) return -1;
i--;
rejected++;
}
size_t skip[256];
for (size_t j = 0; j < 256; j++) {
skip[j] = needle_len;
}
for (size_t j = needle_len - 1; j >= 1; j--) {
skip[needle[j]] = j;
}
while (true) {
if (data[i] == needle[0] && memcmp(&data[i + 1], &needle[1], needle_len - 1) == 0) {
return (int64_t) i;
}
size_t shift = skip[data[i]];
if (i < shift) return -1;
i -= shift;
}
}
static inline int
bare_buffer__memcmp(void *a, size_t a_len, void *b, size_t b_len) {
int r = memcmp(a, b, a_len < b_len ? a_len : b_len);
if (r == 0) {
if (a_len < b_len) return -1;
if (a_len > b_len) return 1;
return 0;
}
return r < 0 ? -1 : 1;
}
static int32_t
bare_buffer_typed_compare(
js_value_t *receiver,
js_value_t *a_handle,
int64_t a_offset,
int64_t a_len,
js_value_t *b_handle,
int64_t b_offset,
int64_t b_len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, a_handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_buffer(env, b_handle)) return BARE_BUFFER_INVALID_BUFFER;
uint8_t *a;
err = bare_buffer__slice(env, a_handle, a_offset, a_len, (void **) &a);
if (err != 0) return err;
uint8_t *b;
err = bare_buffer__slice(env, b_handle, b_offset, b_len, (void **) &b);
if (err != 0) return err;
return bare_buffer__memcmp(a, a_len, b, b_len);
}
static js_value_t *
bare_buffer_compare(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 6;
js_value_t *argv[6];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
if (!bare_buffer__check_buffer(env, argv[3])) return NULL;
if (!bare_buffer__check_number(env, argv[4], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[5], "Length must be a number")) return NULL;
int64_t a_offset = bare_buffer__to_int64(env, argv[1]);
int64_t a_len = bare_buffer__to_int64(env, argv[2]);
int64_t b_offset = bare_buffer__to_int64(env, argv[4]);
int64_t b_len = bare_buffer__to_int64(env, argv[5]);
uint8_t *a;
err = bare_buffer__slice(env, argv[0], a_offset, a_len, (void **) &a);
int32_t comparison = err;
if (err == 0) {
uint8_t *b;
err = bare_buffer__slice(env, argv[3], b_offset, b_len, (void **) &b);
comparison = err == 0 ? bare_buffer__memcmp(a, a_len, b, b_len) : err;
}
js_value_t *result;
err = js_create_int32(env, comparison, &result);
assert(err == 0);
return result;
}
static int32_t
bare_buffer_typed_swap16(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
uint8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
bare_buffer__swap16(buf, len);
return 0;
}
static js_value_t *
bare_buffer_swap16(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
uint8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err == 0) bare_buffer__swap16(buf, len);
int32_t swapped = err;
js_value_t *result;
err = js_create_int32(env, swapped, &result);
assert(err == 0);
return result;
}
static int32_t
bare_buffer_typed_swap32(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
uint8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
bare_buffer__swap32(buf, len);
return 0;
}
static js_value_t *
bare_buffer_swap32(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
uint8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err == 0) bare_buffer__swap32(buf, len);
int32_t swapped = err;
js_value_t *result;
err = js_create_int32(env, swapped, &result);
assert(err == 0);
return result;
}
static int32_t
bare_buffer_typed_swap64(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
uint8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
bare_buffer__swap64(buf, len);
return 0;
}
static js_value_t *
bare_buffer_swap64(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 3;
js_value_t *argv[3];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
uint8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
if (err == 0) bare_buffer__swap64(buf, len);
int32_t swapped = err;
js_value_t *result;
err = js_create_int32(env, swapped, &result);
assert(err == 0);
return result;
}
static int64_t
bare_buffer_typed_index_of(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *needle_handle,
int64_t needle_offset,
int64_t needle_len,
int64_t from,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_buffer(env, needle_handle)) return BARE_BUFFER_INVALID_BUFFER;
uint8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
uint8_t *needle;
err = bare_buffer__slice(env, needle_handle, needle_offset, needle_len, (void **) &needle);
if (err != 0) return err;
return bare_buffer__index_of(buf, len, needle, needle_len, from);
}
static js_value_t *
bare_buffer_index_of(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 7;
js_value_t *argv[7];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
if (!bare_buffer__check_buffer(env, argv[3])) return NULL;
if (!bare_buffer__check_number(env, argv[4], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[5], "Length must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[6], "Start must be a number")) return NULL;
int64_t needle_offset = bare_buffer__to_int64(env, argv[4]);
int64_t needle_len = bare_buffer__to_int64(env, argv[5]);
int64_t from = bare_buffer__to_int64(env, argv[6]);
uint8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t at = err;
if (err == 0) {
uint8_t *needle;
err = bare_buffer__slice(env, argv[3], needle_offset, needle_len, (void **) &needle);
at = err == 0 ? bare_buffer__index_of(buf, len, needle, needle_len, from) : err;
}
js_value_t *result;
err = js_create_int64(env, at, &result);
assert(err == 0);
return result;
}
static int64_t
bare_buffer_typed_last_index_of(
js_value_t *receiver,
js_value_t *handle,
int64_t offset,
int64_t len,
js_value_t *needle_handle,
int64_t needle_offset,
int64_t needle_len,
int64_t from,
js_typed_callback_info_t *info
) {
int err;
js_env_t *env;
err = js_get_typed_callback_info(info, &env, NULL);
assert(err == 0);
if (!bare_buffer__is_buffer(env, handle)) return BARE_BUFFER_INVALID_BUFFER;
if (!bare_buffer__is_buffer(env, needle_handle)) return BARE_BUFFER_INVALID_BUFFER;
uint8_t *buf;
err = bare_buffer__slice(env, handle, offset, len, (void **) &buf);
if (err != 0) return err;
uint8_t *needle;
err = bare_buffer__slice(env, needle_handle, needle_offset, needle_len, (void **) &needle);
if (err != 0) return err;
return bare_buffer__last_index_of(buf, len, needle, needle_len, from);
}
static js_value_t *
bare_buffer_last_index_of(js_env_t *env, js_callback_info_t *info) {
int err;
size_t argc = 7;
js_value_t *argv[7];
err = js_get_callback_info(env, info, &argc, argv, NULL, NULL);
assert(err == 0);
if (!bare_buffer__check_buffer(env, argv[0])) return NULL;
if (!bare_buffer__check_number(env, argv[1], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[2], "Length must be a number")) return NULL;
int64_t offset = bare_buffer__to_int64(env, argv[1]);
int64_t len = bare_buffer__to_int64(env, argv[2]);
if (!bare_buffer__check_buffer(env, argv[3])) return NULL;
if (!bare_buffer__check_number(env, argv[4], "Offset must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[5], "Length must be a number")) return NULL;
if (!bare_buffer__check_number(env, argv[6], "Start must be a number")) return NULL;
int64_t needle_offset = bare_buffer__to_int64(env, argv[4]);
int64_t needle_len = bare_buffer__to_int64(env, argv[5]);
int64_t from = bare_buffer__to_int64(env, argv[6]);
uint8_t *buf;
err = bare_buffer__slice(env, argv[0], offset, len, (void **) &buf);
int64_t at = err;
if (err == 0) {
uint8_t *needle;
err = bare_buffer__slice(env, argv[3], needle_offset, needle_len, (void **) &needle);
at = err == 0 ? bare_buffer__last_index_of(buf, len, needle, needle_len, from) : err;
}
js_value_t *result;
err = js_create_int64(env, at, &result);
assert(err == 0);
return result;
}
static js_value_t *
bare_buffer_exports(js_env_t *env, js_value_t *exports) {
int err;
js_value_t *constants;
err = js_create_object(env, &constants);
assert(err == 0);
err = js_set_named_property(env, exports, "constants", constants);
assert(err == 0);
bare_buffer__read_limits(env);
#define V(name, value) \
{ \
js_value_t *val; \
err = js_create_int64(env, value, &val); \
assert(err == 0); \
err = js_set_named_property(env, constants, name, val); \
assert(err == 0); \
}
V("MAX_LENGTH", bare_buffer__arraybuffer_limit());
V("MAX_STRING_LENGTH", bare_buffer__string_limit());
#undef V
#define V(name, untyped, signature, typed) \
{ \
js_value_t *val; \
if (signature) { \
err = js_create_typed_function(env, name, -1, untyped, signature, typed, NULL, &val); \
assert(err == 0); \
} else { \
err = js_create_function(env, name, -1, untyped, NULL, &val); \
assert(err == 0); \
} \
err = js_set_named_property(env, exports, name, val); \
assert(err == 0); \
}
V("alloc", bare_buffer_alloc, NULL, NULL);
V("allocUnsafe", bare_buffer_alloc_unsafe, NULL, NULL);
V(
"byteLengthUTF8",
bare_buffer_byte_length_utf8,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 2,
.args = (int[]){
js_object,
js_string,
}
}),
bare_buffer_typed_byte_length_utf8
);
V("toStringUTF8", bare_buffer_to_string_utf8, NULL, NULL);
V(
"validateUTF8",
bare_buffer_validate_utf8,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 4,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_validate_utf8
);
V(
"writeUTF8",
bare_buffer_write_utf8,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 5,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_string,
}
}),
bare_buffer_typed_write_utf8
);
V("toStringUTF16LE", bare_buffer_to_string_utf16le, NULL, NULL);
V(
"writeUTF16LE",
bare_buffer_write_utf16le,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 5,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_string,
}
}),
bare_buffer_typed_write_utf16le
);
V("toStringLatin1", bare_buffer_to_string_latin1, NULL, NULL);
V(
"writeLatin1",
bare_buffer_write_latin1,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 5,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_string,
}
}),
bare_buffer_typed_write_latin1
);
V("toStringBase64", bare_buffer_to_string_base64, NULL, NULL);
V("toStringBase64URL", bare_buffer_to_string_base64url, NULL, NULL);
V(
"writeBase64",
bare_buffer_write_base64,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 5,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_string,
}
}),
bare_buffer_typed_write_base64
);
V("toStringHex", bare_buffer_to_string_hex, NULL, NULL);
V(
"writeHex",
bare_buffer_write_hex,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 5,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_string,
}
}),
bare_buffer_typed_write_hex
);
V(
"validateAscii",
bare_buffer_validate_ascii,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 4,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_validate_ascii
);
V(
"swap16",
bare_buffer_swap16,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 4,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_swap16
);
V(
"swap32",
bare_buffer_swap32,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 4,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_swap32
);
V(
"swap64",
bare_buffer_swap64,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 4,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_swap64
);
V(
"indexOf",
bare_buffer_index_of,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 8,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_object,
js_int64,
js_int64,
js_int64,
}
}),
bare_buffer_typed_index_of
);
V(
"lastIndexOf",
bare_buffer_last_index_of,
&((js_callback_signature_t){
.version = 0,
.result = js_int64,
.args_len = 8,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_object,
js_int64,
js_int64,
js_int64,
}
}),
bare_buffer_typed_last_index_of
);
V(
"compare",
bare_buffer_compare,
&((js_callback_signature_t){
.version = 0,
.result = js_int32,
.args_len = 7,
.args = (int[]){
js_object,
js_object,
js_int64,
js_int64,
js_object,
js_int64,
js_int64,
}
}),
bare_buffer_typed_compare
);
#undef V
return exports;
}
BARE_MODULE(bare_buffer, bare_buffer_exports)