| ... | @@ -219,7 +219,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S | ... | @@ -219,7 +219,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S |
| 219 | const block_type: BlockType = @enumFromInt(try d.takeBits(u2)); | 219 | const block_type: BlockType = @enumFromInt(try d.takeBits(u2)); |
| 220 | switch (block_type) { | 220 | switch (block_type) { |
| 221 | .stored => { | 221 | .stored => { |
| 222 | d.alignBitsToByte(); // skip padding until byte boundary | 222 | d.alignBitsDiscarding(); |
| 223 | // everything after this is byte aligned in stored block | 223 | // everything after this is byte aligned in stored block |
| 224 | const len = try in.takeInt(u16, .little); | 224 | const len = try in.takeInt(u16, .little); |
| 225 | const nlen = try in.takeInt(u16, .little); | 225 | const nlen = try in.takeInt(u16, .little); |
| ... | @@ -333,20 +333,23 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S | ... | @@ -333,20 +333,23 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S |
| 333 | return @intFromEnum(limit) - remaining; | 333 | return @intFromEnum(limit) - remaining; |
| 334 | }, | 334 | }, |
| 335 | .protocol_footer => { | 335 | .protocol_footer => { |
| 336 | d.alignBitsToByte(); | | |
| 337 | switch (d.container_metadata) { | 336 | switch (d.container_metadata) { |
| 338 | .gzip => |*gzip| { | 337 | .gzip => |*gzip| { |
| | 338 | d.alignBitsDiscarding(); |
| 339 | gzip.* = .{ | 339 | gzip.* = .{ |
| 340 | .crc = try in.takeInt(u32, .little), | 340 | .crc = try in.takeInt(u32, .little), |
| 341 | .count = try in.takeInt(u32, .little), | 341 | .count = try in.takeInt(u32, .little), |
| 342 | }; | 342 | }; |
| 343 | }, | 343 | }, |
| 344 | .zlib => |*zlib| { | 344 | .zlib => |*zlib| { |
| | 345 | d.alignBitsDiscarding(); |
| 345 | zlib.* = .{ | 346 | zlib.* = .{ |
| 346 | .adler = try in.takeInt(u32, .little), | 347 | .adler = try in.takeInt(u32, .little), |
| 347 | }; | 348 | }; |
| 348 | }, | 349 | }, |
| 349 | .raw => {}, | 350 | .raw => { |
| | 351 | d.alignBitsPreserving(); |
| | 352 | }, |
| 350 | } | 353 | } |
| 351 | d.state = .end; | 354 | d.state = .end; |
| 352 | return 0; | 355 | return 0; |
| ... | @@ -475,22 +478,16 @@ fn tossBits(d: *Decompress, n: u6) !void { | ... | @@ -475,22 +478,16 @@ fn tossBits(d: *Decompress, n: u6) !void { |
| 475 | fn tossBitsEnding(d: *Decompress, n: u6) !void { | 478 | fn tossBitsEnding(d: *Decompress, n: u6) !void { |
| 476 | const remaining_bits = d.remaining_bits; | 479 | const remaining_bits = d.remaining_bits; |
| 477 | const in = d.input; | 480 | const in = d.input; |
| 478 | var remaining_needed_bits = n - remaining_bits; | 481 | const buffered_n = in.bufferedLen(); |
| 479 | while (remaining_needed_bits >= 8) { | 482 | if (buffered_n == 0) return error.EndOfStream; |
| 480 | try in.discardAll(1); | 483 | assert(buffered_n < @sizeOf(usize)); |
| 481 | remaining_needed_bits -= 8; | 484 | const needed_bits = n - remaining_bits; |
| 482 | } | 485 | const next_int = in.takeVarInt(usize, .little, buffered_n) catch |err| switch (err) { |
| 483 | if (remaining_needed_bits == 0) { | | |
| 484 | d.next_bits = 0; | | |
| 485 | d.remaining_bits = 0; | | |
| 486 | return; | | |
| 487 | } | | |
| 488 | const byte = in.takeByte() catch |err| switch (err) { | | |
| 489 | error.ReadFailed => return error.ReadFailed, | 486 | error.ReadFailed => return error.ReadFailed, |
| 490 | error.EndOfStream => if (remaining_bits == 0) return error.EndOfStream else 0, | 487 | error.EndOfStream => unreachable, |
| 491 | }; | 488 | }; |
| 492 | d.next_bits = @as(usize, byte) >> remaining_needed_bits; | 489 | d.next_bits = next_int >> needed_bits; |
| 493 | d.remaining_bits = @intCast(8 - remaining_needed_bits); | 490 | d.remaining_bits = @intCast(@as(usize, n) * 8 -| @as(usize, needed_bits)); |
| 494 | } | 491 | } |
| 495 | | 492 | |
| 496 | fn takeBitsRuntime(d: *Decompress, n: u4) !u16 { | 493 | fn takeBitsRuntime(d: *Decompress, n: u4) !u16 { |
| ... | @@ -501,7 +498,7 @@ fn takeBitsRuntime(d: *Decompress, n: u4) !u16 { | ... | @@ -501,7 +498,7 @@ fn takeBitsRuntime(d: *Decompress, n: u4) !u16 { |
| 501 | return u; | 498 | return u; |
| 502 | } | 499 | } |
| 503 | | 500 | |
| 504 | fn alignBitsToByte(d: *Decompress) void { | 501 | fn alignBitsDiscarding(d: *Decompress) void { |
| 505 | const remaining_bits = d.remaining_bits; | 502 | const remaining_bits = d.remaining_bits; |
| 506 | const next_bits = d.next_bits; | 503 | const next_bits = d.next_bits; |
| 507 | if (remaining_bits == 0) return; | 504 | if (remaining_bits == 0) return; |
| ... | @@ -518,6 +515,21 @@ fn alignBitsToByte(d: *Decompress) void { | ... | @@ -518,6 +515,21 @@ fn alignBitsToByte(d: *Decompress) void { |
| 518 | d.next_bits = 0; | 515 | d.next_bits = 0; |
| 519 | } | 516 | } |
| 520 | | 517 | |
| | 518 | fn alignBitsPreserving(d: *Decompress) void { |
| | 519 | const remaining_bits: usize = d.remaining_bits; |
| | 520 | if (remaining_bits == 0) return; |
| | 521 | const n_bytes = (remaining_bits + 7) / 8; |
| | 522 | const in = d.input; |
| | 523 | in.seek -= n_bytes; |
| | 524 | var put_back_bits = d.next_bits; |
| | 525 | for (in.buffer[in.seek..][0..n_bytes]) |*b| { |
| | 526 | b.* = @truncate(put_back_bits); |
| | 527 | put_back_bits >>= 8; |
| | 528 | } |
| | 529 | d.remaining_bits = 0; |
| | 530 | d.next_bits = 0; |
| | 531 | } |
| | 532 | |
| 521 | /// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code. | 533 | /// Reads first 7 bits, and then maybe 1 or 2 more to get full 7,8 or 9 bit code. |
| 522 | /// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12 | 534 | /// ref: https://datatracker.ietf.org/doc/html/rfc1951#page-12 |
| 523 | /// Lit Value Bits Codes | 535 | /// Lit Value Bits Codes |