error.EndOfStream disambiguation
This commit is contained in:
@@ -44,14 +44,13 @@ const State = union(enum) {
|
||||
pub const Error = Container.Error || error{
|
||||
InvalidCode,
|
||||
InvalidMatch,
|
||||
InvalidBlockType,
|
||||
WrongStoredBlockNlen,
|
||||
InvalidDynamicBlockHeader,
|
||||
EndOfStream,
|
||||
ReadFailed,
|
||||
OversubscribedHuffmanTree,
|
||||
IncompleteHuffmanTree,
|
||||
MissingEndOfBlockCode,
|
||||
EndOfStream,
|
||||
};
|
||||
|
||||
pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
|
||||
@@ -153,7 +152,14 @@ fn decodeSymbol(self: *Decompress, decoder: anytype) !Symbol {
|
||||
pub fn stream(r: *Reader, w: *Writer, limit: std.Io.Limit) Reader.StreamError!usize {
|
||||
const d: *Decompress = @alignCast(@fieldParentPtr("reader", r));
|
||||
return readInner(d, w, limit) catch |err| switch (err) {
|
||||
error.EndOfStream => return error.EndOfStream,
|
||||
error.EndOfStream => {
|
||||
if (d.state == .end) {
|
||||
return error.EndOfStream;
|
||||
} else {
|
||||
d.read_err = error.EndOfStream;
|
||||
return error.ReadFailed;
|
||||
}
|
||||
},
|
||||
error.WriteFailed => return error.WriteFailed,
|
||||
else => |e| {
|
||||
// In the event of an error, state is unmodified so that it can be
|
||||
@@ -922,120 +928,109 @@ test "zlib decompress non compressed block (type 0)" {
|
||||
}
|
||||
|
||||
test "failing end-of-stream" {
|
||||
try testFailure(@embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/end-of-stream.input"), error.EndOfStream);
|
||||
}
|
||||
test "failing invalid-distance" {
|
||||
try testFailure(@embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-distance.input"), error.InvalidMatch);
|
||||
}
|
||||
test "failing invalid-tree01" {
|
||||
try testFailure(@embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree01.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing invalid-tree02" {
|
||||
try testFailure(@embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree02.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing invalid-tree03" {
|
||||
try testFailure(@embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/invalid-tree03.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing lengths-overflow" {
|
||||
try testFailure(@embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/lengths-overflow.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing out-of-codes" {
|
||||
try testFailure(@embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/out-of-codes.input"), error.InvalidCode);
|
||||
}
|
||||
test "failing puff01" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff01.input"), error.WrongStoredBlockNlen);
|
||||
}
|
||||
test "failing puff02" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff02.input"), error.EndOfStream);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff02.input"), error.EndOfStream);
|
||||
}
|
||||
test "failing puff04" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff04.input"), error.InvalidCode);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff04.input"), error.InvalidCode);
|
||||
}
|
||||
test "failing puff05" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff05.input"), error.EndOfStream);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff05.input"), error.EndOfStream);
|
||||
}
|
||||
test "failing puff06" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff06.input"), error.EndOfStream);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff06.input"), error.EndOfStream);
|
||||
}
|
||||
test "failing puff08" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff08.input"), error.InvalidCode);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff08.input"), error.InvalidCode);
|
||||
}
|
||||
test "failing puff10" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff10.input"), error.InvalidCode);
|
||||
}
|
||||
test "failing puff11" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff11.input"), error.InvalidMatch);
|
||||
}
|
||||
test "failing puff12" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff12.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing puff13" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff13.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing puff14" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff14.input"), error.EndOfStream);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff14.input"), error.EndOfStream);
|
||||
}
|
||||
test "failing puff15" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff15.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing puff16" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff16.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing puff17" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff17.input"), error.MissingEndOfBlockCode);
|
||||
}
|
||||
test "failing fuzz1" {
|
||||
try testFailure(@embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/fuzz1.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing fuzz2" {
|
||||
try testFailure(@embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/fuzz2.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing fuzz3" {
|
||||
try testFailure(@embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/fuzz3.input"), error.InvalidMatch);
|
||||
}
|
||||
test "failing fuzz4" {
|
||||
try testFailure(@embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/fuzz4.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff18" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff18.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff19" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff19.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff20" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff20.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff21" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff21.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff22" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff22.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff23" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff23.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff24" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff24.input"), error.IncompleteHuffmanTree);
|
||||
}
|
||||
test "failing puff25" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff25.input"), error.OversubscribedHuffmanTree);
|
||||
}
|
||||
test "failing puff26" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff26.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
test "failing puff27" {
|
||||
try testFailure(@embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
|
||||
fn testFailure(in: []const u8, expected_err: anyerror) !void {
|
||||
var reader: Reader = .fixed(in);
|
||||
var aw: Writer.Allocating = .init(testing.allocator);
|
||||
try aw.ensureUnusedCapacity(flate.history_len);
|
||||
defer aw.deinit();
|
||||
|
||||
var decompress: Decompress = .init(&reader, .raw, &.{});
|
||||
try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer));
|
||||
try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed);
|
||||
try testFailure(.raw, @embedFile("testdata/fuzz/puff27.input"), error.InvalidDynamicBlockHeader);
|
||||
}
|
||||
|
||||
test "deflate-stream" {
|
||||
@@ -1097,82 +1092,57 @@ test "don't read past deflate stream's end" {
|
||||
|
||||
test "zlib header" {
|
||||
// Truncated header
|
||||
try testing.expectError(
|
||||
error.EndOfStream,
|
||||
testDecompress(.zlib, &[_]u8{0x78}, ""),
|
||||
);
|
||||
try testFailure(.zlib, &[_]u8{0x78}, error.EndOfStream);
|
||||
|
||||
// Wrong CM
|
||||
try testing.expectError(
|
||||
error.BadZlibHeader,
|
||||
testDecompress(.zlib, &[_]u8{ 0x79, 0x94 }, ""),
|
||||
);
|
||||
try testFailure(.zlib, &[_]u8{ 0x79, 0x94 }, error.BadZlibHeader);
|
||||
|
||||
// Wrong CINFO
|
||||
try testing.expectError(
|
||||
error.BadZlibHeader,
|
||||
testDecompress(.zlib, &[_]u8{ 0x88, 0x98 }, ""),
|
||||
);
|
||||
try testFailure(.zlib, &[_]u8{ 0x88, 0x98 }, error.BadZlibHeader);
|
||||
|
||||
// Wrong checksum
|
||||
try testing.expectError(
|
||||
error.WrongZlibChecksum,
|
||||
testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, ""),
|
||||
);
|
||||
try testFailure(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, error.WrongZlibChecksum);
|
||||
|
||||
// Truncated checksum
|
||||
try testing.expectError(
|
||||
error.EndOfStream,
|
||||
testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, ""),
|
||||
);
|
||||
try testFailure(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, error.EndOfStream);
|
||||
}
|
||||
|
||||
test "gzip header" {
|
||||
// Truncated header
|
||||
try testing.expectError(
|
||||
error.EndOfStream,
|
||||
testDecompress(.gzip, &[_]u8{ 0x1f, 0x8B }, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{ 0x1f, 0x8B }, error.EndOfStream);
|
||||
|
||||
// Wrong CM
|
||||
try testing.expectError(
|
||||
error.BadGzipHeader,
|
||||
testDecompress(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03,
|
||||
}, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03,
|
||||
}, error.BadGzipHeader);
|
||||
|
||||
// Wrong checksum
|
||||
try testing.expectError(
|
||||
error.WrongGzipChecksum,
|
||||
testDecompress(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
}, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
}, error.WrongGzipChecksum);
|
||||
|
||||
// Truncated checksum
|
||||
try testing.expectError(
|
||||
error.EndOfStream,
|
||||
testDecompress(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
}, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
|
||||
}, error.EndOfStream);
|
||||
|
||||
// Wrong initial size
|
||||
try testing.expectError(
|
||||
error.WrongGzipSize,
|
||||
testDecompress(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
}, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
}, error.WrongGzipSize);
|
||||
|
||||
// Truncated initial size field
|
||||
try testing.expectError(
|
||||
error.EndOfStream,
|
||||
testDecompress(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
}, undefined),
|
||||
);
|
||||
try testFailure(.gzip, &[_]u8{
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00,
|
||||
}, error.EndOfStream);
|
||||
|
||||
try testDecompress(.gzip, &[_]u8{
|
||||
// GZIP header
|
||||
@@ -1184,17 +1154,6 @@ test "gzip header" {
|
||||
}, "");
|
||||
}
|
||||
|
||||
fn testDecompress(container: Container, compressed: []const u8, expected_plain: []const u8) !void {
|
||||
var in: std.Io.Reader = .fixed(compressed);
|
||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||
try aw.ensureUnusedCapacity(flate.history_len);
|
||||
defer aw.deinit();
|
||||
|
||||
var decompress: Decompress = .init(&in, container, &.{});
|
||||
_ = try decompress.reader.streamRemaining(&aw.writer);
|
||||
try testing.expectEqualSlices(u8, expected_plain, aw.getWritten());
|
||||
}
|
||||
|
||||
test "zlib should not overshoot" {
|
||||
// Compressed zlib data with extra 4 bytes at the end.
|
||||
const data = [_]u8{
|
||||
@@ -1220,3 +1179,25 @@ test "zlib should not overshoot" {
|
||||
try std.testing.expectEqual(n, 4);
|
||||
try std.testing.expectEqualSlices(u8, data[data.len - 4 .. data.len], out[0..n]);
|
||||
}
|
||||
|
||||
fn testFailure(container: Container, in: []const u8, expected_err: anyerror) !void {
|
||||
var reader: Reader = .fixed(in);
|
||||
var aw: Writer.Allocating = .init(testing.allocator);
|
||||
try aw.ensureUnusedCapacity(flate.history_len);
|
||||
defer aw.deinit();
|
||||
|
||||
var decompress: Decompress = .init(&reader, container, &.{});
|
||||
try testing.expectError(error.ReadFailed, decompress.reader.streamRemaining(&aw.writer));
|
||||
try testing.expectEqual(expected_err, decompress.read_err orelse return error.TestFailed);
|
||||
}
|
||||
|
||||
fn testDecompress(container: Container, compressed: []const u8, expected_plain: []const u8) !void {
|
||||
var in: std.Io.Reader = .fixed(compressed);
|
||||
var aw: std.Io.Writer.Allocating = .init(testing.allocator);
|
||||
try aw.ensureUnusedCapacity(flate.history_len);
|
||||
defer aw.deinit();
|
||||
|
||||
var decompress: Decompress = .init(&in, container, &.{});
|
||||
_ = try decompress.reader.streamRemaining(&aw.writer);
|
||||
try testing.expectEqualSlices(u8, expected_plain, aw.getWritten());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user