flate change bit reader Bits to usize (#24719)

Don't see why byte returned from specialPeek needs to be shifted by
remaining_needed_bits.
I believe that decision in specialPeek should be done on the number of
the remaining bits not of the content of that bits.

Some test result are changed, but they are now consistent with the
original state as found in:
5f790464b0/lib/std/compress/flate/Decompress.zig

Changing Bits from usize to u32 or u64 now returns same results.

* flate: simplify peekBitsEnding

`peekBits` returns at most asked number of bits. Fails with EndOfStream
when there are no available bits. If there are less bits available than
asked still returns that available bits.
Hopefully this change better reflects intention. On first input stream
peek error we break the loop.
This commit is contained in:
Igor Anić 2025-08-07 23:40:08 +02:00 committed by GitHub
parent 8843631f7e
commit 6de2310035
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -25,8 +25,7 @@ state: State,
err: ?Error,
/// TODO: change this to usize
const Bits = u64;
const Bits = usize;
const BlockType = enum(u2) {
stored = 0,
@ -550,29 +549,19 @@ fn peekBitsEnding(d: *Decompress, comptime U: type) !U {
var u: Bits = 0;
var remaining_needed_bits = @bitSizeOf(U) - remaining_bits;
var i: usize = 0;
while (remaining_needed_bits >= 8) {
const byte = try specialPeek(in, next_bits, i);
u |= @as(Bits, byte) << @intCast(i * 8);
remaining_needed_bits -= 8;
while (remaining_needed_bits > 0) {
const peeked = in.peek(i + 1) catch |err| switch (err) {
error.ReadFailed => return error.ReadFailed,
error.EndOfStream => break,
};
u |= @as(Bits, peeked[i]) << @intCast(i * 8);
remaining_needed_bits -|= 8;
i += 1;
}
if (remaining_needed_bits != 0) {
const byte = try specialPeek(in, next_bits, i);
u |= @as(Bits, byte) << @intCast((i * 8) + remaining_needed_bits);
}
if (remaining_bits == 0 and i == 0) return error.EndOfStream;
return @truncate((u << remaining_bits) | next_bits);
}
/// If there is any unconsumed data, handles EndOfStream by pretending there
/// are zeroes afterwards.
fn specialPeek(in: *Reader, next_bits: Bits, i: usize) Reader.Error!u8 {
const peeked = in.peek(i + 1) catch |err| switch (err) {
error.ReadFailed => return error.ReadFailed,
error.EndOfStream => if (next_bits == 0 and i == 0) return error.EndOfStream else return 0,
};
return peeked[i];
}
fn tossBits(d: *Decompress, n: u4) !void {
const remaining_bits = d.remaining_bits;
const next_bits = d.next_bits;
@ -1032,7 +1021,7 @@ test "failing invalid-tree01" {
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
}
test "failing invalid-tree02" {
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.EndOfStream);
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree);
}
test "failing invalid-tree03" {
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
@ -1065,7 +1054,7 @@ test "failing puff10" {
try testFailure(.raw, @embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
}
test "failing puff11" {
try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.EndOfStream);
try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch);
}
test "failing puff12" {
try testFailure(.raw, @embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
@ -1137,7 +1126,7 @@ test "deflate-stream" {
}
test "empty-distance-alphabet01" {
try testFailure(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), error.EndOfStream);
try testDecompress(.raw, @embedFile("testdata/fuzz/empty-distance-alphabet01.input"), "");
}
test "empty-distance-alphabet02" {