authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-28 13:13:59-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
log9c8cb777d461406c4185bdb38b9462abde5d5e52
tree930646e325722a5daba9af16db1d473f53c59af4
parent6509fa1cf3694ae16333739fa0f3fae1b63f1eaf

std.compress.flate.Decompress: implement more bit reading


1 files changed, 65 insertions(+), 30 deletions(-)

lib/std/compress/flate/Decompress.zig+65-30
...@@ -146,8 +146,8 @@ fn dynamicCodeLength(self: *Decompress, code: u16, lens: []u4, pos: usize) !usiz...@@ -146,8 +146,8 @@ fn dynamicCodeLength(self: *Decompress, code: u16, lens: []u4, pos: usize) !usiz
146// used. Shift bit reader for that much bits, those bits are used. And146// used. Shift bit reader for that much bits, those bits are used. And
147// return symbol.147// return symbol.
148fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {148fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
149 const sym = try decoder.find(try self.peekBitsReverseBuffered(u15));149 const sym = try decoder.find(@bitReverse(try self.peekBits(u15)));
150 try self.shiftBits(sym.code_bits);150 try self.tossBits(sym.code_bits);
151 return sym;151 return sym;
152}152}
153153
...@@ -245,8 +245,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S...@@ -245,8 +245,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
245 var dec_lens: [286 + 30]u4 = @splat(0);245 var dec_lens: [286 + 30]u4 = @splat(0);
246 var pos: usize = 0;246 var pos: usize = 0;
247 while (pos < hlit + hdist) {247 while (pos < hlit + hdist) {
248 const sym = try cl_dec.find(try d.peekBitsReverse(u7));248 const sym = try cl_dec.find(@bitReverse(try d.peekBits(u7)));
249 try d.shiftBits(sym.code_bits);249 try d.tossBits(sym.code_bits);
250 pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);250 pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos);
251 }251 }
252 if (pos > hlit + hdist) {252 if (pos > hlit + hdist) {
...@@ -291,7 +291,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S...@@ -291,7 +291,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
291 // Handles fixed block non literal (length) code.291 // Handles fixed block non literal (length) code.
292 // Length code is followed by 5 bits of distance code.292 // Length code is followed by 5 bits of distance code.
293 const length = try d.decodeLength(@intCast(code - 257));293 const length = try d.decodeLength(@intCast(code - 257));
294 const distance = try d.decodeDistance(try d.takeBitsReverseBuffered(u5));294 const distance = try d.decodeDistance(@bitReverse(try d.takeBits(u5)));
295 remaining = try writeMatch(w, length, distance, remaining);295 remaining = try writeMatch(w, length, distance, remaining);
296 },296 },
297 else => return error.InvalidCode,297 else => return error.InvalidCode,
...@@ -384,24 +384,47 @@ fn takeBits(d: *Decompress, comptime T: type) !T {...@@ -384,24 +384,47 @@ fn takeBits(d: *Decompress, comptime T: type) !T {
384 };384 };
385}385}
386386
387fn takeBitsReverseBuffered(d: *Decompress, comptime T: type) !T {387fn peekBits(d: *Decompress, comptime T: type) !T {
388 _ = d;388 const U = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
389 @panic("TODO");389 const remaining_bits = d.remaining_bits;
390}390 const next_bits = d.next_bits;
391391 if (remaining_bits >= @bitSizeOf(T)) {
392fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {392 const u: U = @truncate(next_bits);
393 _ = d;393 return switch (@typeInfo(T)) {
394 _ = n;394 .int => u,
395 @panic("TODO");395 .@"enum" => @enumFromInt(u),
396 else => @bitCast(u),
397 };
398 }
399 const in = d.input;
400 const next_int = try in.peekInt(usize, .little);
401 const needed_bits = @bitSizeOf(T) - remaining_bits;
402 const u: U = @intCast((next_bits << needed_bits) | (next_int & ((@as(usize, 1) << needed_bits) - 1)));
403 return switch (@typeInfo(T)) {
404 .int => u,
405 .@"enum" => @enumFromInt(u),
406 else => @bitCast(u),
407 };
396}408}
397409
398fn peekBitsReverse(d: *Decompress, comptime T: type) !T {410fn tossBits(d: *Decompress, n: u6) !void {
399 _ = d;411 const remaining_bits = d.remaining_bits;
400 @panic("TODO");412 const next_bits = d.next_bits;
413 if (remaining_bits >= n) {
414 d.next_bits = next_bits >> n;
415 d.remaining_bits = remaining_bits - n;
416 } else {
417 const in = d.input;
418 const next_int = try in.takeInt(usize, .little);
419 const needed_bits = n - remaining_bits;
420 d.next_bits = next_int >> needed_bits;
421 d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
422 }
401}423}
402424
403fn peekBitsReverseBuffered(d: *Decompress, comptime T: type) !T {425fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {
404 _ = d;426 _ = d;
427 _ = n;
405 @panic("TODO");428 @panic("TODO");
406}429}
407430
...@@ -422,15 +445,26 @@ fn alignBitsToByte(d: *Decompress) void {...@@ -422,15 +445,26 @@ fn alignBitsToByte(d: *Decompress) void {
422 d.next_bits = 0;445 d.next_bits = 0;
423}446}
424447
425fn shiftBits(d: *Decompress, n: u6) !void {448/// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code.
426 _ = d;449/// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12
427 _ = n;450/// Lit Value Bits Codes
428 @panic("TODO");451/// --------- ---- -----
429}452/// 0 - 143 8 00110000 through
430453/// 10111111
454/// 144 - 255 9 110010000 through
455/// 111111111
456/// 256 - 279 7 0000000 through
457/// 0010111
458/// 280 - 287 8 11000000 through
459/// 11000111
431fn readFixedCode(d: *Decompress) !u16 {460fn readFixedCode(d: *Decompress) !u16 {
432 _ = d;461 const code7 = @bitReverse(try d.takeBits(u7));
433 @panic("TODO");462 return switch (code7) {
463 0...0b0010_111 => @as(u16, code7) + 256,
464 0b0010_111 + 1...0b1011_111 => (@as(u16, code7) << 1) + @as(u16, try d.takeBits(u1)) - 0b0011_0000,
465 0b1011_111 + 1...0b1100_011 => (@as(u16, code7 - 0b1100000) << 1) + try d.takeBits(u1) + 280,
466 else => (@as(u16, code7 - 0b1100_100) << 2) + @as(u16, @bitReverse(try d.takeBits(u2))) + 144,
467 };
434}468}
435469
436pub const Symbol = packed struct {470pub const Symbol = packed struct {
...@@ -731,20 +765,21 @@ test "encode/decode literals" {...@@ -731,20 +765,21 @@ test "encode/decode literals" {
731 }765 }
732}766}
733767
734test "basic" {768test "non compressed block (type 0)" {
735 // non compressed block (type 0)
736 try testBasicCase(&[_]u8{769 try testBasicCase(&[_]u8{
737 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen770 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
738 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data771 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data
739 }, "Hello world\n");772 }, "Hello world\n");
773}
740774
741 // fixed code block (type 1)775test "fixed code block (type 1)" {
742 try testBasicCase(&[_]u8{776 try testBasicCase(&[_]u8{
743 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1777 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1
744 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,778 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00,
745 }, "Hello world\n");779 }, "Hello world\n");
780}
746781
747 // dynamic block (type 2)782test "dynamic block (type 2)" {
748 try testBasicCase(&[_]u8{783 try testBasicCase(&[_]u8{
749 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2784 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2
750 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,785 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38,