Skip to content

Commit 66e403c

Browse files
authored
Merge pull request #1042 from lightpanda-io/textdecoder_decode
Improve TextDecoder.decode
2 parents 6d3065c + 0913abe commit 66e403c

File tree

2 files changed

+56
-7
lines changed

2 files changed

+56
-7
lines changed

src/browser/encoding/TextDecoder.zig

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const std = @import("std");
2020
const log = @import("../../log.zig");
2121

2222
const Env = @import("../env.zig").Env;
23+
const Page = @import("../page.zig").Page;
2324

2425
// https://encoding.spec.whatwg.org/#interface-textdecoder
2526
const TextDecoder = @This();
@@ -37,6 +38,7 @@ const Options = struct {
3738

3839
fatal: bool,
3940
ignore_bom: bool,
41+
stream: std.ArrayList(u8),
4042

4143
pub fn constructor(label_: ?[]const u8, opts_: ?Options) !TextDecoder {
4244
if (label_) |l| {
@@ -47,6 +49,7 @@ pub fn constructor(label_: ?[]const u8, opts_: ?Options) !TextDecoder {
4749
}
4850
const opts = opts_ orelse Options{};
4951
return .{
52+
.stream = .empty,
5053
.fatal = opts.fatal,
5154
.ignore_bom = opts.ignoreBOM,
5255
};
@@ -64,18 +67,34 @@ pub fn get_fatal(self: *const TextDecoder) bool {
6467
return self.fatal;
6568
}
6669

67-
// TODO: Should accept an ArrayBuffer, TypedArray or DataView
68-
// js.zig will currently only map a TypedArray to our []const u8.
69-
pub fn _decode(self: *const TextDecoder, v: []const u8) ![]const u8 {
70-
if (self.fatal and !std.unicode.utf8ValidateSlice(v)) {
70+
const DecodeOptions = struct {
71+
stream: bool = false,
72+
};
73+
pub fn _decode(self: *TextDecoder, input_: ?[]const u8, opts_: ?DecodeOptions, page: *Page) ![]const u8 {
74+
var str = input_ orelse return "";
75+
const opts: DecodeOptions = opts_ orelse .{};
76+
77+
if (self.stream.items.len > 0) {
78+
try self.stream.appendSlice(page.arena, str);
79+
str = self.stream.items;
80+
}
81+
82+
if (self.fatal and !std.unicode.utf8ValidateSlice(str)) {
83+
if (opts.stream) {
84+
if (self.stream.items.len == 0) {
85+
try self.stream.appendSlice(page.arena, str);
86+
}
87+
return "";
88+
}
7189
return error.InvalidUtf8;
7290
}
7391

74-
if (self.ignore_bom == false and std.mem.startsWith(u8, v, &.{ 0xEF, 0xBB, 0xBF })) {
75-
return v[3..];
92+
self.stream.clearRetainingCapacity();
93+
if (self.ignore_bom == false and std.mem.startsWith(u8, str, &.{ 0xEF, 0xBB, 0xBF })) {
94+
return str[3..];
7695
}
7796

78-
return v;
97+
return str;
7998
}
8099

81100
const testing = @import("../../testing.zig");

src/tests/encoding/decoder.html

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,47 @@
1+
<!DOCTYPE html>
2+
<meta charset="UTF-8">
3+
14
<script src="../testing.js"></script>
25
<script id=decoder>
36
let d1 = new TextDecoder();
47
testing.expectEqual('utf-8', d1.encoding);
58
testing.expectEqual(false, d1.fatal);
69
testing.expectEqual(false, d1.ignoreBOM);
710

11+
testing.expectEqual('', d1.decode());
812
testing.expectEqual('𠮷', d1.decode(new Uint8Array([240, 160, 174, 183])));
913
testing.expectEqual('𠮷', d1.decode(new Uint8Array([0xEF, 0xBB, 0xBF, 240, 160, 174, 183])));
1014
testing.expectEqual('�2', d1.decode(new Uint8Array([249, 50])));
1115

16+
{
17+
const buffer = new ArrayBuffer(4);
18+
const ints = new Uint8Array(buffer)
19+
ints[0] = 240;
20+
ints[1] = 160;
21+
ints[2] = 174;
22+
ints[3] = 183;
23+
testing.expectEqual('𠮷', d1.decode(buffer));
24+
}
25+
26+
{
27+
const buffer = new ArrayBuffer(4);
28+
const dv = new DataView(buffer);
29+
dv.setUint8(0, 240);
30+
dv.setUint8(1, 160);
31+
dv.setUint8(2, 174);
32+
dv.setUint8(3, 183);
33+
testing.expectEqual('𠮷', d1.decode(dv));
34+
}
35+
1236
let d2 = new TextDecoder('utf8', {fatal: true})
1337
testing.expectError('Error: InvalidUtf8', () => {
1438
let data = new Uint8Array([240, 240, 160, 174, 183]);
1539
d2.decode(data);
1640
});
1741
</script>
42+
43+
<script id=stream>
44+
let d3 = new TextDecoder();
45+
testing.expectEqual('', d2.decode(new Uint8Array([226, 153]), { stream: true }));
46+
testing.expectEqual('♥', d2.decode(new Uint8Array([165]), { stream: true }));
47+
</script>

0 commit comments

Comments
 (0)