Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve Buffer compatibility with Node.js #2341

Merged
merged 2 commits into from
Mar 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/baby_list.zig
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub fn BabyList(comptime Type: type) type {
const orig_len = list_.items.len;

var slice_ = list_.items.ptr[orig_len..list_.capacity];
const result = strings.copyUTF16IntoUTF8WithBuffer(slice_, []const u16, remain, trimmed, out_len);
const result = strings.copyUTF16IntoUTF8WithBuffer(slice_, []const u16, remain, trimmed, out_len, true);
remain = remain[result.read..];
list_.items.len += @as(usize, result.written);
if (result.read == 0 or result.written == 0) break;
Expand Down
92 changes: 41 additions & 51 deletions src/base64/base64.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,28 @@ pub const DecodeResult = struct {
fail: bool = false,
};

pub fn decode(destination: []u8, source: []const u8) DecodeResult {
var wrote: usize = 0;
const result = zig_base64.standard.decoderWithIgnore(&[_]u8{
' ',
'\n',
'\r',
'\t',
const mixed_decoder = brk: {
var decoder = zig_base64.standard.decoderWithIgnore("\xff \t\r\n" ++ [_]u8{
std.ascii.control_code.vt,
}).decode(destination, source, &wrote) catch {
return .{
.written = wrote,
.fail = true,
};
};
std.ascii.control_code.ff,
});

return .{ .written = result, .fail = false };
}
for (zig_base64.url_safe_alphabet_chars[62..], 62..) |c, i| {
decoder.decoder.char_to_index[c] = @intCast(u8, i);
}

pub fn decodeURLSafe(destination: []u8, source: []const u8) DecodeResult {
break :brk decoder;
};

pub fn decode(destination: []u8, source: []const u8) DecodeResult {
var wrote: usize = 0;
const result = urlsafe.decode(destination, source, &wrote) catch {
mixed_decoder.decode(destination, source, &wrote) catch {
return .{
.written = wrote,
.fail = true,
};
};

return .{ .written = result, .fail = false };
return .{ .written = wrote, .fail = false };
}

pub fn encode(destination: []u8, source: []const u8) usize {
Expand All @@ -58,14 +52,6 @@ pub fn encodeLen(source: anytype) usize {
return zig_base64.standard.Encoder.calcSize(source.len);
}

pub const urlsafe = zig_base64.Base64DecoderWithIgnore.init(
zig_base64.url_safe_alphabet_chars,
null,
"= \t\r\n" ++ [_]u8{ std.ascii.control_code.vt, std.ascii.control_code.ff },
);

pub const urlsafeEncoder = zig_base64.url_safe_no_pad.Encoder;

// This is just std.base64 copy-pasted
// with support for returning how many bytes were decoded
const zig_base64 = struct {
Expand Down Expand Up @@ -118,7 +104,7 @@ const zig_base64 = struct {

pub const url_safe_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*;
fn urlSafeBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore {
return Base64DecoderWithIgnore.init(url_safe_alphabet_chars, null, ignore);
return Base64DecoderWithIgnore.init(url_safe_alphabet_chars, '=', ignore);
}

/// URL-safe Base64 codecs, with padding
Expand Down Expand Up @@ -316,7 +302,7 @@ const zig_base64 = struct {

/// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding
/// `InvalidPadding` is returned if the input length is not valid.
pub fn calcSizeUpperBound(decoder_with_ignore: *const Base64DecoderWithIgnore, source_len: usize) Error!usize {
pub fn calcSizeUpperBound(decoder_with_ignore: *const Base64DecoderWithIgnore, source_len: usize) usize {
var result = source_len / 4 * 3;
if (decoder_with_ignore.decoder.pad_char == null) {
const leftover = source_len % 4;
Expand All @@ -329,24 +315,29 @@ const zig_base64 = struct {
/// Invalid padding results in error.InvalidPadding.
/// Decoding more data than can fit in dest results in error.NoSpaceLeft. See also ::calcSizeUpperBound.
/// Returns the number of bytes written to dest.
pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8, wrote: *usize) Error!usize {
pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8, wrote: *usize) Error!void {
const decoder = &decoder_with_ignore.decoder;
var acc: u12 = 0;
var acc_len: u4 = 0;
var dest_idx: usize = 0;
var leftover_idx: ?usize = null;

defer {
wrote.* = leftover_idx orelse dest_idx;
wrote.* = dest_idx;
}

for (source, 0..) |c, src_idx| {
if (decoder_with_ignore.char_is_ignored[c]) continue;
const d = decoder.char_to_index[c];
if (d == Base64Decoder.invalid_char) {
if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter;
leftover_idx = src_idx;
break;
if (decoder.pad_char) |pad_char| {
if (c == pad_char) {
leftover_idx = src_idx;
break;
}
}
if (decoder_with_ignore.char_is_ignored[Base64Decoder.invalid_char]) continue;
return error.InvalidCharacter;
}
acc = (acc << 6) + d;
acc_len += 6;
Expand All @@ -357,27 +348,26 @@ const zig_base64 = struct {
dest_idx += 1;
}
}
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) {
return error.InvalidPadding;
}
const padding_len = acc_len / 2;
if (leftover_idx == null) {
if (decoder.pad_char != null and padding_len != 0) return error.InvalidPadding;
return dest_idx;
}
var leftover = source[leftover_idx.?..];
if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) return error.InvalidPadding;

if (decoder.pad_char) |pad_char| {
var padding_chars: usize = 0;
for (leftover) |c| {
if (decoder_with_ignore.char_is_ignored[c]) continue;
if (c != pad_char) {
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
const padding_len = acc_len / 2;

if (leftover_idx) |idx| {
var leftover = source[idx..];
var padding_chars: usize = 0;
for (leftover) |c| {
if (decoder_with_ignore.char_is_ignored[c]) continue;
if (c != pad_char) {
return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding;
}
padding_chars += 1;
}
padding_chars += 1;
if (padding_chars != padding_len) return error.InvalidPadding;
} else if (padding_len > 0) {
return error.InvalidPadding;
}
if (padding_chars != padding_len) return error.InvalidPadding;
}
return dest_idx;
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/bindings/Buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extern "C" JSC::EncodedJSValue JSBuffer__bufferFromLength(JSC::JSGlobalObject* l
extern "C" JSC::EncodedJSValue JSBuffer__bufferFromPointerAndLengthAndDeinit(JSC::JSGlobalObject* lexicalGlobalObject, char* ptr, size_t length, void* ctx, JSTypedArrayBytesDeallocator bytesDeallocator);
extern "C" JSC::EncodedJSValue Bun__encoding__toString(const uint8_t* input, size_t len, JSC::JSGlobalObject* globalObject, Encoding encoding);
extern "C" JSC::EncodedJSValue Bun__encoding__toStringUTF8(const uint8_t* input, size_t len, JSC::JSGlobalObject* globalObject);
extern "C" void Bun__Buffer_fill(ZigString*, void*, size_t, WebCore::BufferEncodingType);
extern "C" bool Bun__Buffer_fill(ZigString*, void*, size_t, WebCore::BufferEncodingType);

namespace WebCore {

Expand Down
Loading