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 {
148148 }
149149 }
150150 };
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 };
151174};
152175
153176test {
lib/std/compress/flate/Decompress.zig+14-14
......@@ -15,8 +15,7 @@ remaining_bits: std.math.Log2Int(usize),
1515
1616reader: Reader,
1717
18/// Hashes, produces checksum, of uncompressed data for gzip/zlib footer.
19hasher: Container.Hasher,
18container_metadata: Container.Metadata,
2019
2120lit_dec: LiteralDecoder,
2221dst_dec: DistanceDecoder,
......@@ -71,7 +70,7 @@ pub fn init(input: *Reader, container: Container, buffer: []u8) Decompress {
7170 .input = input,
7271 .next_bits = 0,
7372 .remaining_bits = 0,
74 .hasher = .init(container),
73 .container_metadata = .init(container),
7574 .lit_dec = .{},
7675 .dst_dec = .{},
7776 .final_block = false,
......@@ -169,7 +168,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
169168 var remaining = @intFromEnum(limit);
170169 const in = d.input;
171170 sw: switch (d.state) {
172 .protocol_header => switch (d.hasher.container()) {
171 .protocol_header => switch (d.container_metadata.container()) {
173172 .gzip => {
174173 const Header = extern struct {
175174 magic: u16 align(1),
......@@ -258,7 +257,7 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
258257 try d.lit_dec.generate(dec_lens[0..hlit]);
259258
260259 // 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
263262 continue :sw .dynamic_block;
264263 },
......@@ -332,14 +331,17 @@ fn readInner(d: *Decompress, w: *Writer, limit: std.Io.Limit) (Error || Reader.S
332331 },
333332 .protocol_footer => {
334333 d.alignBitsToByte();
335 switch (d.hasher) {
334 switch (d.container_metadata) {
336335 .gzip => |*gzip| {
337 if (try in.takeInt(u32, .little) != gzip.crc.final()) return error.WrongGzipChecksum;
338 if (try in.takeInt(u32, .little) != gzip.count) return error.WrongGzipSize;
336 gzip.* = .{
337 .crc = try in.takeInt(u32, .little),
338 .count = try in.takeInt(u32, .little),
339 };
339340 },
340341 .zlib => |*zlib| {
341 const chksum: u32 = @byteSwap(zlib.adler);
342 if (try in.takeInt(u32, .big) != chksum) return error.WrongZlibChecksum;
342 zlib.* = .{
343 .adler = try in.takeInt(u32, .little),
344 };
343345 },
344346 .raw => {},
345347 }
......@@ -868,8 +870,7 @@ fn testBasicCase(in: []const u8, out: []const u8) !void {
868870 defer aw.deinit();
869871
870872 var decompress: Decompress = .init(&reader, .raw, &.{});
871 const r = &decompress.reader;
872 _ = try r.streamRemaining(&aw.writer);
873 _ = try decompress.reader.streamRemaining(&aw.writer);
873874 try testing.expectEqualStrings(out, aw.getWritten());
874875}
875876
......@@ -917,8 +918,7 @@ fn testGzipDecompress(in: []const u8, out: []const u8) !void {
917918 defer aw.deinit();
918919
919920 var decompress: Decompress = .init(&reader, .gzip, &.{});
920 const r = &decompress.reader;
921 _ = try r.streamRemaining(&aw.writer);
921 _ = try decompress.reader.streamRemaining(&aw.writer);
922922 try testing.expectEqualStrings(out, aw.getWritten());
923923}
924924