Re-implement forgiving base64 decode without intermediate allocation

Was looking at, what I thought was a related issue, and started to extract this
code to re-use it (in DataURIs). Realized it could be written without the
intermediate allocation. Then I realized the dataURI issue is something else,
but wanted to keep this improvement.
This commit is contained in:
Karl Seguin
2026-02-28 11:22:31 +08:00
parent 516bd98198
commit 7fc6e97cd8

View File

@@ -396,28 +396,19 @@ pub fn btoa(_: *const Window, input: []const u8, page: *Page) ![]const u8 {
pub fn atob(_: *const Window, input: []const u8, page: *Page) ![]const u8 { pub fn atob(_: *const Window, input: []const u8, page: *Page) ![]const u8 {
const trimmed = std.mem.trim(u8, input, &std.ascii.whitespace); const trimmed = std.mem.trim(u8, input, &std.ascii.whitespace);
// Per HTML spec "forgiving-base64 decode" algorithm: // Forgiving base64 decode per WHATWG spec:
// https://infra.spec.whatwg.org/#forgiving-base64-decode // https://infra.spec.whatwg.org/#forgiving-base64-decode
const padded: []const u8 = switch (trimmed.len % 4) { // Remove trailing padding to use standard_no_pad decoder
1 => return error.InvalidCharacterError, const unpadded = std.mem.trimRight(u8, trimmed, "=");
2 => blk: {
const buf = try page.call_arena.alloc(u8, trimmed.len + 2); // Length % 4 == 1 is invalid (can't represent valid base64)
@memcpy(buf[0..trimmed.len], trimmed); if (unpadded.len % 4 == 1) {
buf[trimmed.len] = '='; return error.InvalidCharacterError;
buf[trimmed.len + 1] = '='; }
break :blk buf;
}, const decoded_len = std.base64.standard_no_pad.Decoder.calcSizeForSlice(unpadded) catch return error.InvalidCharacterError;
3 => blk: {
const buf = try page.call_arena.alloc(u8, trimmed.len + 1);
@memcpy(buf[0..trimmed.len], trimmed);
buf[trimmed.len] = '=';
break :blk buf;
},
else => trimmed,
};
const decoded_len = std.base64.standard.Decoder.calcSizeForSlice(padded) catch return error.InvalidCharacterError;
const decoded = try page.call_arena.alloc(u8, decoded_len); const decoded = try page.call_arena.alloc(u8, decoded_len);
std.base64.standard.Decoder.decode(decoded, padded) catch return error.InvalidCharacterError; std.base64.standard_no_pad.Decoder.decode(decoded, unpadded) catch return error.InvalidCharacterError;
return decoded; return decoded;
} }