Skip to content

Instantly share code, notes, and snippets.

@lemire
Created April 2, 2024 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lemire/237b40db76087d332d73f0c702538dab to your computer and use it in GitHub Desktop.
Save lemire/237b40db76087d332d73f0c702538dab to your computer and use it in GitHub Desktop.
base64 runtime functions (simdutf)
// on success: returns a non-negative integer indicating the size of the
// binary produced, it most be no larger than 2147483647 bytes.
// In case of error, a negativ value is returned:
// * -2 indicates an invalid character,
// * -1 indicates a single character remained,
// * -3 indicates a possible overflow (i.e., more than 2 GB output).
void Base64ToBinary(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
SPREAD_BUFFER_ARG(args.This(), ts_obj);
THROW_AND_RETURN_IF_NOT_STRING(env, args[0], "argument");
Local<String> str = args[0]->ToString(env->context()).ToLocalChecked();
size_t offset = 0;
size_t max_length = 0;
THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[1], 0, &offset));
if (offset > ts_obj_length) {
return node::THROW_ERR_BUFFER_OUT_OF_BOUNDS(
env, "\"offset\" is outside of buffer bounds");
}
THROW_AND_RETURN_IF_OOB(ParseArrayIndex(env, args[2], ts_obj_length - offset,
&max_length));
if (max_length == 0)
return args.GetReturnValue().Set(0);
char* buf = ts_obj_data + offset;
size_t buflen = max_length;
if(buflen > INT32_MAX) {
return args.GetReturnValue().Set(-3);
}
int32_t written{0};
if (str->IsExternalOneByte()) { // 8-bit case
auto ext = str->GetExternalOneByteStringResource();
simdutf::result r = simdutf::base64_to_binary_safe(ext->data(), ext->length(), buf, buflen, simdutf::base64_default);
if(r.error == simdutf::error_code::SUCCESS) {
written = buflen;
} else if(r.error == simdutf::error_code::INVALID_BASE64_CHARACTER) {
written = -2;
} else if(r.error == simdutf::error_code::BASE64_INPUT_REMAINDER) {
written = -1;
} else {
written = -3;
}
} else { // 16-bit case
String::Value value(env->isolate(), str);
simdutf::result r = simdutf::base64_to_binary_safe(reinterpret_cast<const char16_t*>(*value), value.length(), buf, buflen, simdutf::base64_default);
if(r.error == simdutf::error_code::SUCCESS) {
written = buflen;
} else if(r.error == simdutf::error_code::INVALID_BASE64_CHARACTER) {
written = -2;
} else if(r.error == simdutf::error_code::BASE64_INPUT_REMAINDER) {
written = -1;
} else {
written = -3;
}
}
args.GetReturnValue().Set(written);
}
// rest is made of code samples, not actual working code...
///....
case BASE64URL: {
// When in URL mode, base64_encode uses a non-accelerated routine, so we
// adopt simdutf.
size_t dlen = simdutf::base64_length_from_binary(buflen, simdutf::base64_url);
char* dst = node::UncheckedMalloc(dlen);
if (dst == nullptr) {
*error = node::ERR_MEMORY_ALLOCATION_FAILED(isolate);
return MaybeLocal<Value>();
}
size_t written = simdutf::binary_to_base64(buf, buflen, dst, simdutf::base64_url);
CHECK_EQ(written, dlen);
return ExternOneByteString::New(isolate, dst, dlen, error);
}
///....
case BASE64URL:
if (str->IsExternalOneByte()) { // 8-bit case
auto ext = str->GetExternalOneByteStringResource();
// Try with WHATWG base64 standard first, adapted for base64url
simdutf::result r = simdutf::base64_to_binary_safe(ext->data(), ext->length(), buf, buflen, simdutf::base64_url);
if(r.error == simdutf::error_code::SUCCESS) {
nbytes = buflen;
} else {
// 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());
}
} else { // 16-bit case
String::Value value(isolate, str);
// Try with WHATWG base64 standard first
simdutf::result r = simdutf::base64_to_binary_safe(reinterpret_cast<const char16_t*>(*value), value.length(), buf, buflen, simdutf::base64_url);
if(r.error == simdutf::error_code::SUCCESS) {
nbytes = buflen;
} else {
// 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());
}
}
break;
case BASE64:
if (str->IsExternalOneByte()) { // 8-bit case
auto ext = str->GetExternalOneByteStringResource();
// Try with WHATWG base64 standard first
simdutf::result r = simdutf::base64_to_binary_safe(ext->data(), ext->length(), buf, buflen, simdutf::base64_default);
if(r.error == simdutf::error_code::SUCCESS) {
nbytes = buflen;
} 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());
}
} else { // 16-bit case
String::Value value(isolate, str);
// Try with WHATWG base64 standard first
simdutf::result r = simdutf::base64_to_binary_safe(reinterpret_cast<const char16_t*>(*value), value.length(), buf, buflen, simdutf::base64_default);
if(r.error == simdutf::error_code::SUCCESS) {
nbytes = buflen;
} 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());
}
}
break;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment