| ... | ... | @@ -146,8 +146,8 @@ fn dynamicCodeLength(self: *Decompress, code: u16, lens: []u4, pos: usize) !usiz |
| 146 | 146 | // used. Shift bit reader for that much bits, those bits are used. And |
| 147 | 147 | // return symbol. |
| 148 | 148 | fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol { |
| 149 | | const sym = try decoder.find(try self.peekBitsReverseBuffered(u15)); |
| 150 | | try self.shiftBits(sym.code_bits); |
| 149 | const sym = try decoder.find(@bitReverse(try self.peekBits(u15))); |
| 150 | try self.tossBits(sym.code_bits); |
| 151 | 151 | return sym; |
| 152 | 152 | } |
| 153 | 153 | |
| ... | ... | @@ -245,8 +245,8 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S |
| 245 | 245 | var dec_lens: [286 + 30]u4 = @splat(0); |
| 246 | 246 | var pos: usize = 0; |
| 247 | 247 | while (pos < hlit + hdist) { |
| 248 | | const sym = try cl_dec.find(try d.peekBitsReverse(u7)); |
| 249 | | try d.shiftBits(sym.code_bits); |
| 248 | const sym = try cl_dec.find(@bitReverse(try d.peekBits(u7))); |
| 249 | try d.tossBits(sym.code_bits); |
| 250 | 250 | pos += try d.dynamicCodeLength(sym.symbol, &dec_lens, pos); |
| 251 | 251 | } |
| 252 | 252 | if (pos > hlit + hdist) { |
| ... | ... | @@ -291,7 +291,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S |
| 291 | 291 | // Handles fixed block non literal (length) code. |
| 292 | 292 | // Length code is followed by 5 bits of distance code. |
| 293 | 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 | 295 | remaining = try writeMatch(w, length, distance, remaining); |
| 296 | 296 | }, |
| 297 | 297 | else => return error.InvalidCode, |
| ... | ... | @@ -384,24 +384,47 @@ fn takeBits(d: *Decompress, comptime T: type) !T { |
| 384 | 384 | }; |
| 385 | 385 | } |
| 386 | 386 | |
| 387 | | fn takeBitsReverseBuffered(d: *Decompress, comptime T: type) !T { |
| 388 | | _ = d; |
| 389 | | @panic("TODO"); |
| 390 | | } |
| 391 | | |
| 392 | | fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 { |
| 393 | | _ = d; |
| 394 | | _ = n; |
| 395 | | @panic("TODO"); |
| 387 | fn peekBits(d: *Decompress, comptime T: type) !T { |
| 388 | const U = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } }); |
| 389 | const remaining_bits = d.remaining_bits; |
| 390 | const next_bits = d.next_bits; |
| 391 | if (remaining_bits >= @bitSizeOf(T)) { |
| 392 | const u: U = @truncate(next_bits); |
| 393 | return switch (@typeInfo(T)) { |
| 394 | .int => u, |
| 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 | } |
| 397 | 409 | |
| 398 | | fn peekBitsReverse(d: *Decompress, comptime T: type) !T { |
| 399 | | _ = d; |
| 400 | | @panic("TODO"); |
| 410 | fn tossBits(d: *Decompress, n: u6) !void { |
| 411 | const remaining_bits = d.remaining_bits; |
| 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 | } |
| 402 | 424 | |
| 403 | | fn peekBitsReverseBuffered(d: *Decompress, comptime T: type) !T { |
| 425 | fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 { |
| 404 | 426 | _ = d; |
| 427 | _ = n; |
| 405 | 428 | @panic("TODO"); |
| 406 | 429 | } |
| 407 | 430 | |
| ... | ... | @@ -422,15 +445,26 @@ fn alignBitsToByte(d: *Decompress) void { |
| 422 | 445 | d.next_bits = 0; |
| 423 | 446 | } |
| 424 | 447 | |
| 425 | | fn shiftBits(d: *Decompress, n: u6) !void { |
| 426 | | _ = d; |
| 427 | | _ = n; |
| 428 | | @panic("TODO"); |
| 429 | | } |
| 430 | | |
| 448 | /// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code. |
| 449 | /// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12 |
| 450 | /// Lit Value Bits Codes |
| 451 | /// --------- ---- ----- |
| 452 | /// 0 - 143 8 00110000 through |
| 453 | /// 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 |
| 431 | 460 | fn readFixedCode(d: *Decompress) !u16 { |
| 432 | | _ = d; |
| 433 | | @panic("TODO"); |
| 461 | const code7 = @bitReverse(try d.takeBits(u7)); |
| 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 | } |
| 435 | 469 | |
| 436 | 470 | pub const Symbol = packed struct { |
| ... | ... | @@ -731,20 +765,21 @@ test "encode/decode literals" { |
| 731 | 765 | } |
| 732 | 766 | } |
| 733 | 767 | |
| 734 | | test "basic" { |
| 735 | | // non compressed block (type 0) |
| 768 | test "non compressed block (type 0)" { |
| 736 | 769 | try testBasicCase(&[_]u8{ |
| 737 | 770 | 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen |
| 738 | 771 | 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a, // non compressed data |
| 739 | 772 | }, "Hello world\n"); |
| 773 | } |
| 740 | 774 | |
| 741 | | // fixed code block (type 1) |
| 775 | test "fixed code block (type 1)" { |
| 742 | 776 | try testBasicCase(&[_]u8{ |
| 743 | 777 | 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x28, 0xcf, // deflate data block type 1 |
| 744 | 778 | 0x2f, 0xca, 0x49, 0xe1, 0x02, 0x00, |
| 745 | 779 | }, "Hello world\n"); |
| 780 | } |
| 746 | 781 | |
| 747 | | // dynamic block (type 2) |
| 782 | test "dynamic block (type 2)" { |
| 748 | 783 | try testBasicCase(&[_]u8{ |
| 749 | 784 | 0x3d, 0xc6, 0x39, 0x11, 0x00, 0x00, 0x0c, 0x02, // deflate data block type 2 |
| 750 | 785 | 0x30, 0x2b, 0xb5, 0x52, 0x1e, 0xff, 0x96, 0x38, |