authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-28 14:36:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
log73e5594c78a66fb943638d99f8540bec0b5ed839
tree3d497ebf7f0781342e35ae12921a3b8a8b7614e5
parent9c8cb777d461406c4185bdb38b9462abde5d5e52

std.compress.flate.Decompress: fix bit read at eof


1 files changed, 52 insertions(+), 3 deletions(-)

lib/std/compress/flate/Decompress.zig+52-3
...@@ -372,7 +372,10 @@ fn takeBits(d: *Decompress, comptime T: type) !T {...@@ -372,7 +372,10 @@ fn takeBits(d: *Decompress, comptime T: type) !T {
372 };372 };
373 }373 }
374 const in = d.input;374 const in = d.input;
375 const next_int = try in.takeInt(usize, .little);375 const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
376 error.ReadFailed => return error.ReadFailed,
377 error.EndOfStream => return takeBitsEnding(d, T),
378 };
376 const needed_bits = @bitSizeOf(T) - remaining_bits;379 const needed_bits = @bitSizeOf(T) - remaining_bits;
377 const u: U = @intCast((next_bits << needed_bits) | (next_int & ((@as(usize, 1) << needed_bits) - 1)));380 const u: U = @intCast((next_bits << needed_bits) | (next_int & ((@as(usize, 1) << needed_bits) - 1)));
378 d.next_bits = next_int >> needed_bits;381 d.next_bits = next_int >> needed_bits;
...@@ -384,6 +387,35 @@ fn takeBits(d: *Decompress, comptime T: type) !T {...@@ -384,6 +387,35 @@ fn takeBits(d: *Decompress, comptime T: type) !T {
384 };387 };
385}388}
386389
390fn takeBitsEnding(d: *Decompress, comptime T: type) !T {
391 const remaining_bits = d.remaining_bits;
392 const next_bits = d.next_bits;
393 const in = d.input;
394 const U = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
395 var u: U = 0;
396 var remaining_needed_bits = @bitSizeOf(U) - remaining_bits;
397 while (@bitSizeOf(U) >= 8 and remaining_needed_bits >= 8) {
398 const byte = try in.takeByte();
399 u = (u << 8) | byte;
400 remaining_needed_bits -= 8;
401 }
402 if (remaining_needed_bits == 0) {
403 d.next_bits = 0;
404 d.remaining_bits = 0;
405 } else {
406 const byte = try in.takeByte();
407 u = @intCast((@as(usize, u) << remaining_needed_bits) | (byte & ((@as(usize, 1) << remaining_needed_bits) - 1)));
408 d.next_bits = @as(usize, byte) >> remaining_needed_bits;
409 d.remaining_bits = @intCast(8 - remaining_needed_bits);
410 }
411 u = @intCast((@as(usize, u) << remaining_bits) | next_bits);
412 return switch (@typeInfo(T)) {
413 .int => u,
414 .@"enum" => @enumFromInt(u),
415 else => @bitCast(u),
416 };
417}
418
387fn peekBits(d: *Decompress, comptime T: type) !T {419fn peekBits(d: *Decompress, comptime T: type) !T {
388 const U = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });420 const U = @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(T) } });
389 const remaining_bits = d.remaining_bits;421 const remaining_bits = d.remaining_bits;
...@@ -397,7 +429,10 @@ fn peekBits(d: *Decompress, comptime T: type) !T {...@@ -397,7 +429,10 @@ fn peekBits(d: *Decompress, comptime T: type) !T {
397 };429 };
398 }430 }
399 const in = d.input;431 const in = d.input;
400 const next_int = try in.peekInt(usize, .little);432 const next_int = in.peekInt(usize, .little) catch |err| switch (err) {
433 error.ReadFailed => return error.ReadFailed,
434 error.EndOfStream => return peekBitsEnding(d, T),
435 };
401 const needed_bits = @bitSizeOf(T) - remaining_bits;436 const needed_bits = @bitSizeOf(T) - remaining_bits;
402 const u: U = @intCast((next_bits << needed_bits) | (next_int & ((@as(usize, 1) << needed_bits) - 1)));437 const u: U = @intCast((next_bits << needed_bits) | (next_int & ((@as(usize, 1) << needed_bits) - 1)));
403 return switch (@typeInfo(T)) {438 return switch (@typeInfo(T)) {
...@@ -407,6 +442,11 @@ fn peekBits(d: *Decompress, comptime T: type) !T {...@@ -407,6 +442,11 @@ fn peekBits(d: *Decompress, comptime T: type) !T {
407 };442 };
408}443}
409444
445fn peekBitsEnding(d: *Decompress, comptime T: type) !T {
446 _ = d;
447 @panic("TODO");
448}
449
410fn tossBits(d: *Decompress, n: u6) !void {450fn tossBits(d: *Decompress, n: u6) !void {
411 const remaining_bits = d.remaining_bits;451 const remaining_bits = d.remaining_bits;
412 const next_bits = d.next_bits;452 const next_bits = d.next_bits;
...@@ -415,13 +455,22 @@ fn tossBits(d: *Decompress, n: u6) !void {...@@ -415,13 +455,22 @@ fn tossBits(d: *Decompress, n: u6) !void {
415 d.remaining_bits = remaining_bits - n;455 d.remaining_bits = remaining_bits - n;
416 } else {456 } else {
417 const in = d.input;457 const in = d.input;
418 const next_int = try in.takeInt(usize, .little);458 const next_int = in.takeInt(usize, .little) catch |err| switch (err) {
459 error.ReadFailed => return error.ReadFailed,
460 error.EndOfStream => return tossBitsEnding(d, n),
461 };
419 const needed_bits = n - remaining_bits;462 const needed_bits = n - remaining_bits;
420 d.next_bits = next_int >> needed_bits;463 d.next_bits = next_int >> needed_bits;
421 d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));464 d.remaining_bits = @intCast(@bitSizeOf(usize) - @as(usize, needed_bits));
422 }465 }
423}466}
424467
468fn tossBitsEnding(d: *Decompress, n: u6) !void {
469 _ = d;
470 _ = n;
471 @panic("TODO");
472}
473
425fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {474fn takeNBitsBuffered(d: *Decompress, n: u4) !u16 {
426 _ = d;475 _ = d;
427 _ = n;476 _ = n;