authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-03-02 23:20:02+01:00
committergravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-03-04 09:53:01+01:00
log711281602a0efdd3b194c0419e8bccc2bb399167
tree28640cc1a1a714fa2bd0e8c6abcafcd22646768a
parent8a963fd66e22820119bac1b0a568f0cf3af4fa8e

flate: option to fill BitReader

fill(0) will fill all bytes in bit reader. If bit reader is aligned to the byte, as it is at the end of the stream this ensures no overshoot when reading footer. Footer is 4 bytes (zlib) or 8 bytes (gzip). For zlib we will use 4 bytes BitReader and 8 for gzip. After align and fill we will read those bytes and leave BitReader empty after that.

1 files changed, 59 insertions(+), 2 deletions(-)

lib/std/compress/flate/bit_reader.zig+59-2
...@@ -56,7 +56,7 @@ pub fn BitReader(T: type, comptime ReaderType: type) type {...@@ -56,7 +56,7 @@ pub fn BitReader(T: type, comptime ReaderType: type) type {
56 /// that number of bits available. If end of forward stream is reached56 /// that number of bits available. If end of forward stream is reached
57 /// it may be some extra zero bits in buffer.57 /// it may be some extra zero bits in buffer.
58 pub inline fn fill(self: *Self, nice: u6) !void {58 pub inline fn fill(self: *Self, nice: u6) !void {
59 if (self.nbits >= nice) {59 if (self.nbits >= nice and nice != 0) {
60 return; // We have enought bits60 return; // We have enought bits
61 }61 }
62 // Read more bits from forward reader62 // Read more bits from forward reader
...@@ -115,7 +115,7 @@ pub fn BitReader(T: type, comptime ReaderType: type) type {...@@ -115,7 +115,7 @@ pub fn BitReader(T: type, comptime ReaderType: type) type {
115 assert(how == 0);115 assert(how == 0);
116 assert(self.alignBits() == 0);116 assert(self.alignBits() == 0);
117 try self.fill(@bitSizeOf(T));117 try self.fill(@bitSizeOf(T));
118 assert(self.nbits == @bitSizeOf(T));118 if (self.nbits != @bitSizeOf(T)) return error.EndOfStream;
119 const v = self.bits;119 const v = self.bits;
120 self.nbits = 0;120 self.nbits = 0;
121 self.bits = 0;121 self.bits = 0;
...@@ -363,3 +363,60 @@ test "readFixedCode" {...@@ -363,3 +363,60 @@ test "readFixedCode" {
363 try testing.expect(rdr.nbits == 0);363 try testing.expect(rdr.nbits == 0);
364 }364 }
365}365}
366
367test "u32 leaves no bits on u32 reads" {
368 const data = [_]u8{
369 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
370 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
371 };
372 var fbs = std.io.fixedBufferStream(&data);
373 var br = bitReader(u32, fbs.reader());
374
375 _ = try br.read(u3);
376 try testing.expectEqual(29, br.nbits);
377 br.alignToByte();
378 try testing.expectEqual(24, br.nbits);
379 try testing.expectEqual(0x04_03_02_01, try br.read(u32));
380 try testing.expectEqual(0, br.nbits);
381 try testing.expectEqual(0x08_07_06_05, try br.read(u32));
382 try testing.expectEqual(0, br.nbits);
383
384 _ = try br.read(u9);
385 try testing.expectEqual(23, br.nbits);
386 br.alignToByte();
387 try testing.expectEqual(16, br.nbits);
388 try testing.expectEqual(0x0e_0d_0c_0b, try br.read(u32));
389 try testing.expectEqual(0, br.nbits);
390}
391
392test "u64 need fill after alignToByte" {
393 const data = [_]u8{
394 0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
395 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
396 };
397
398 // without fill
399 var fbs = std.io.fixedBufferStream(&data);
400 var br = bitReader(u64, fbs.reader());
401 _ = try br.read(u23);
402 try testing.expectEqual(41, br.nbits);
403 br.alignToByte();
404 try testing.expectEqual(40, br.nbits);
405 try testing.expectEqual(0x06_05_04_03, try br.read(u32));
406 try testing.expectEqual(8, br.nbits);
407 try testing.expectEqual(0x0a_09_08_07, try br.read(u32));
408 try testing.expectEqual(32, br.nbits);
409
410 // fill after align ensures all bits filled
411 fbs.reset();
412 br = bitReader(u64, fbs.reader());
413 _ = try br.read(u23);
414 try testing.expectEqual(41, br.nbits);
415 br.alignToByte();
416 try br.fill(0);
417 try testing.expectEqual(64, br.nbits);
418 try testing.expectEqual(0x06_05_04_03, try br.read(u32));
419 try testing.expectEqual(32, br.nbits);
420 try testing.expectEqual(0x0a_09_08_07, try br.read(u32));
421 try testing.expectEqual(0, br.nbits);
422}