authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-28 18:00:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-31 22:10:11-07:00
logac4fbb427ba71e20fe8042b86179409598241d6a
tree934d380df498fb31a2bd132f67651bc4bdb6428c
parent5f571f53d63e8742374c3c3cdda1ca0bb432d8fc

std.compress.flate.Decompress: don't compute checksums

These have no business being in-bound; simply provide the expected values to user code for maximum flexibility.

2 files changed, 37 insertions(+), 14 deletions(-)

lib/std/compress/flate.zig+23
...@@ -148,6 +148,29 @@ pub const Container = enum {...@@ -148,6 +148,29 @@ pub const Container = enum {
148 }148 }
149 }149 }
150 };150 };
151
152 pub const Metadata = union(Container) {
153 raw: void,
154 gzip: struct {
155 crc: u32 = 0,
156 count: u32 = 0,
157 },
158 zlib: struct {
159 adler: u32 = 0,
160 },
161
162 pub fn init(containter: Container) Metadata {
163 return switch (containter) {
164 .gzip => .{ .gzip = .{} },
165 .zlib => .{ .zlib = .{} },
166 .raw => .raw,
167 };
168 }
169
170 pub fn container(m: Metadata) Container {
171 return m;
172 }
173 };
151};174};
152175
153test {176test {
lib/std/compress/flate/Decompress.zig+14-14
...@@ -15,8 +15,7 @@ remaining_bits: std.math.Log2Int(usize),...@@ -15,8 +15,7 @@ remaining_bits: std.math.Log2Int(usize),
1515
16reader: Reader,16reader: Reader,
1717
18/// Hashes, produces checksum, of uncompressed data for gzip/zlib footer.18container_metadata: Container.Metadata,
19hasher: Container.Hasher,
2019
21lit_dec: LiteralDecoder,20lit_dec: LiteralDecoder,
22dst_dec: DistanceDecoder,21dst_dec: DistanceDecoder,
...@@ -71,7 +70,7 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {...@@ -71,7 +70,7 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
71 .input = input,70 .input = input,
72 .next_bits = 0,71 .next_bits = 0,
73 .remaining_bits = 0,72 .remaining_bits = 0,
74 .hasher = .init(container),73 .container_metadata = .init(container),
75 .lit_dec = .{},74 .lit_dec = .{},
76 .dst_dec = .{},75 .dst_dec = .{},
77 .final_block = false,76 .final_block = false,
...@@ -169,7 +168,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S...@@ -169,7 +168,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
169 var remaining = @intFromEnum(limit);168 var remaining = @intFromEnum(limit);
170 const in = d.input;169 const in = d.input;
171 sw: switch (d.state) {170 sw: switch (d.state) {
172 .protocol_header => switch (d.hasher.container()) {171 .protocol_header => switch (d.container_metadata.container()) {
173 .gzip => {172 .gzip => {
174 const Header = extern struct {173 const Header = extern struct {
175 magic: u16 align(1),174 magic: u16 align(1),
...@@ -258,7 +257,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S...@@ -258,7 +257,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
258 try d.lit_dec.generate(dec_lens[0..hlit]);257 try d.lit_dec.generate(dec_lens[0..hlit]);
259258
260 // distance code lengths to distance decoder259 // distance code lengths to distance decoder
261 try d.dst_dec.generate(dec_lens[hlit .. hlit + hdist]);260 try d.dst_dec.generate(dec_lens[hlit..][0..hdist]);
262261
263 continue :sw .dynamic_block;262 continue :sw .dynamic_block;
264 },263 },
...@@ -332,14 +331,17 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S...@@ -332,14 +331,17 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
332 },331 },
333 .protocol_footer => {332 .protocol_footer => {
334 d.alignBitsToByte();333 d.alignBitsToByte();
335 switch (d.hasher) {334 switch (d.container_metadata) {
336 .gzip => |*gzip| {335 .gzip => |*gzip| {
337 if (try in.takeInt(u32, .little) != gzip.crc.final()) return error.WrongGzipChecksum;336 gzip.* = .{
338 if (try in.takeInt(u32, .little) != gzip.count) return error.WrongGzipSize;337 .crc = try in.takeInt(u32, .little),
338 .count = try in.takeInt(u32, .little),
339 };
339 },340 },
340 .zlib => |*zlib| {341 .zlib => |*zlib| {
341 const chksum: u32 = @byteSwap(zlib.adler);342 zlib.* = .{
342 if (try in.takeInt(u32, .big) != chksum) return error.WrongZlibChecksum;343 .adler = try in.takeInt(u32, .little),
344 };
343 },345 },
344 .raw => {},346 .raw => {},
345 }347 }
...@@ -868,8 +870,7 @@ fn testBasicCase(in: []const u8, out: []const u8) !void {...@@ -868,8 +870,7 @@ fn testBasicCase(in: []const u8, out: []const u8) !void {
868 defer aw.deinit();870 defer aw.deinit();
869871
870 var decompress: Decompress = .init(&reader, .raw, &.{});872 var decompress: Decompress = .init(&reader, .raw, &.{});
871 const r = &decompress.reader;873 _ = try decompress.reader.streamRemaining(&aw.writer);
872 _ = try r.streamRemaining(&aw.writer);
873 try testing.expectEqualStrings(out, aw.getWritten());874 try testing.expectEqualStrings(out, aw.getWritten());
874}875}
875876
...@@ -917,8 +918,7 @@ fn testGzipDecompress(in: []const u8, out: []const u8) !void {...@@ -917,8 +918,7 @@ fn testGzipDecompress(in: []const u8, out: []const u8) !void {
917 defer aw.deinit();918 defer aw.deinit();
918919
919 var decompress: Decompress = .init(&reader, .gzip, &.{});920 var decompress: Decompress = .init(&reader, .gzip, &.{});
920 const r = &decompress.reader;921 _ = try decompress.reader.streamRemaining(&aw.writer);
921 _ = try r.streamRemaining(&aw.writer);
922 try testing.expectEqualStrings(out, aw.getWritten());922 try testing.expectEqualStrings(out, aw.getWritten());
923}923}
924924