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 {
5656 /// that number of bits available. If end of forward stream is reached
5757 /// it may be some extra zero bits in buffer.
5858 pub inline fn fill(self: *Self, nice: u6) !void {
59 if (self.nbits >= nice) {
59 if (self.nbits >= nice and nice != 0) {
6060 return; // We have enought bits
6161 }
6262 // Read more bits from forward reader
......@@ -115,7 +115,7 @@ pub fn BitReader(T: type, comptime ReaderType: type) type {
115115 assert(how == 0);
116116 assert(self.alignBits() == 0);
117117 try self.fill(@bitSizeOf(T));
118 assert(self.nbits == @bitSizeOf(T));
118 if (self.nbits != @bitSizeOf(T)) return error.EndOfStream;
119119 const v = self.bits;
120120 self.nbits = 0;
121121 self.bits = 0;
......@@ -363,3 +363,60 @@ test "readFixedCode" {
363363 try testing.expect(rdr.nbits == 0);
364364 }
365365}
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}