authorgravatar for fncontroloption@noreply.codeberg.orgFnControlOption <fncontroloption@noreply.codeberg.org> 2023-02-05 08:23:51-08:00
committergravatar for fncontroloption@noreply.codeberg.orgFnControlOption <fncontroloption@noreply.codeberg.org> 2023-02-05 08:23:51-08:00
log622a364715522b239eee57aa071399fa268fd372
treefdeeb68767ec2039187c213ed5adceda57674304
parente03d6c42ea8b65a3b283c4da8c9593b82762874c

Implement std.io.Reader for LZMA1


5 files changed, 97 insertions(+), 54 deletions(-)

lib/std/compress/lzma.zig+74-5
......@@ -1,4 +1,6 @@
11const std = @import("../std.zig");
2const math = std.math;
3const mem = std.mem;
24const Allocator = std.mem.Allocator;
35
46pub const decode = @import("lzma/decode.zig");
......@@ -6,13 +8,80 @@ pub const decode = @import("lzma/decode.zig");
68pub fn decompress(
79 allocator: Allocator,
810 reader: anytype,
9 writer: anytype,
11) !Decompress(@TypeOf(reader)) {
12 return decompressWithOptions(allocator, reader, .{});
13}
14
15pub fn decompressWithOptions(
16 allocator: Allocator,
17 reader: anytype,
1018 options: decode.Options,
11) !void {
19) !Decompress(@TypeOf(reader)) {
1220 const params = try decode.Params.readHeader(reader, options);
13 var decoder = try decode.Decoder.init(allocator, params, options.memlimit);
14 defer decoder.deinit(allocator);
15 return decoder.decompress(allocator, reader, writer);
21 return Decompress(@TypeOf(reader)).init(allocator, reader, params, options.memlimit);
22}
23
24pub fn Decompress(comptime ReaderType: type) type {
25 return struct {
26 const Self = @This();
27
28 pub const Error =
29 ReaderType.Error ||
30 Allocator.Error ||
31 error{ CorruptInput, EndOfStream, Overflow };
32
33 pub const Reader = std.io.Reader(*Self, Error, read);
34
35 allocator: Allocator,
36 in_reader: ReaderType,
37 to_read: std.ArrayListUnmanaged(u8),
38
39 buffer: decode.lzbuffer.LzCircularBuffer,
40 decoder: decode.rangecoder.RangeDecoder,
41 state: decode.DecoderState,
42
43 pub fn init(allocator: Allocator, source: ReaderType, params: decode.Params, memlimit: ?usize) !Self {
44 return Self{
45 .allocator = allocator,
46 .in_reader = source,
47 .to_read = .{},
48
49 .buffer = decode.lzbuffer.LzCircularBuffer.init(params.dict_size, memlimit orelse math.maxInt(usize)),
50 .decoder = try decode.rangecoder.RangeDecoder.init(source),
51 .state = try decode.DecoderState.init(allocator, params.properties, params.unpacked_size),
52 };
53 }
54
55 pub fn reader(self: *Self) Reader {
56 return .{ .context = self };
57 }
58
59 pub fn deinit(self: *Self) void {
60 self.to_read.deinit(self.allocator);
61 self.buffer.deinit(self.allocator);
62 self.state.deinit(self.allocator);
63 self.* = undefined;
64 }
65
66 pub fn read(self: *Self, output: []u8) Error!usize {
67 const writer = self.to_read.writer(self.allocator);
68 while (self.to_read.items.len < output.len) {
69 switch (try self.state.process(self.allocator, self.in_reader, writer, &self.buffer, &self.decoder)) {
70 .continue_ => {},
71 .finished => {
72 try self.buffer.finish(writer);
73 break;
74 },
75 }
76 }
77 const input = self.to_read.items;
78 const n = math.min(input.len, output.len);
79 mem.copy(u8, output[0..n], input[0..n]);
80 mem.copy(u8, input, input[n..]);
81 self.to_read.shrinkRetainingCapacity(input.len - n);
82 return n;
83 }
84 };
1685}
1786
1887test {
lib/std/compress/lzma/decode.zig+11-41
......@@ -280,26 +280,29 @@ pub const DecoderState = struct {
280280 writer: anytype,
281281 buffer: anytype,
282282 decoder: *RangeDecoder,
283 ) !void {
284 while (true) {
283 ) !ProcessingStatus {
284 process_next: {
285285 if (self.unpacked_size) |unpacked_size| {
286286 if (buffer.len >= unpacked_size) {
287 break;
287 break :process_next;
288288 }
289289 } else if (decoder.isFinished()) {
290 break;
290 break :process_next;
291291 }
292292
293 if (try self.processNext(allocator, reader, writer, buffer, decoder) == .finished) {
294 break;
293 switch (try self.processNext(allocator, reader, writer, buffer, decoder)) {
294 .continue_ => return .continue_,
295 .finished => break :process_next,
295296 }
296297 }
297298
298 if (self.unpacked_size) |len| {
299 if (len != buffer.len) {
299 if (self.unpacked_size) |unpacked_size| {
300 if (buffer.len != unpacked_size) {
300301 return error.CorruptInput;
301302 }
302303 }
304
305 return .finished;
303306 }
304307
305308 fn decodeLiteral(
......@@ -374,36 +377,3 @@ pub const DecoderState = struct {
374377 return result;
375378 }
376379};
377
378pub const Decoder = struct {
379 params: Params,
380 memlimit: usize,
381 state: DecoderState,
382
383 pub fn init(allocator: Allocator, params: Params, memlimit: ?usize) !Decoder {
384 return Decoder{
385 .params = params,
386 .memlimit = memlimit orelse math.maxInt(usize),
387 .state = try DecoderState.init(allocator, params.properties, params.unpacked_size),
388 };
389 }
390
391 pub fn deinit(self: *Decoder, allocator: Allocator) void {
392 self.state.deinit(allocator);
393 self.* = undefined;
394 }
395
396 pub fn decompress(
397 self: *Decoder,
398 allocator: Allocator,
399 reader: anytype,
400 writer: anytype,
401 ) !void {
402 var buffer = LzCircularBuffer.init(self.params.dict_size, self.memlimit);
403 defer buffer.deinit(allocator);
404
405 var decoder = try RangeDecoder.init(reader);
406 try self.state.process(allocator, reader, writer, &buffer, &decoder);
407 try buffer.finish(writer);
408 }
409};
lib/std/compress/lzma/decode/lzbuffer.zig+2
......@@ -98,6 +98,7 @@ pub const LzAccumBuffer = struct {
9898
9999 pub fn finish(self: *Self, writer: anytype) !void {
100100 try writer.writeAll(self.buf.items);
101 self.buf.clearRetainingCapacity();
101102 }
102103
103104 pub fn deinit(self: *Self, allocator: Allocator) void {
......@@ -216,6 +217,7 @@ pub const LzCircularBuffer = struct {
216217 pub fn finish(self: *Self, writer: anytype) !void {
217218 if (self.cursor > 0) {
218219 try writer.writeAll(self.buf.items[0..self.cursor]);
220 self.cursor = 0;
219221 }
220222 }
221223
lib/std/compress/lzma/test.zig+9-7
......@@ -1,22 +1,24 @@
11const std = @import("../../std.zig");
22const lzma = @import("../lzma.zig");
33
4fn testDecompress(compressed: []const u8, writer: anytype) !void {
4fn testDecompress(compressed: []const u8) ![]u8 {
55 const allocator = std.testing.allocator;
66 var stream = std.io.fixedBufferStream(compressed);
7 try lzma.decompress(allocator, stream.reader(), writer, .{});
7 var decompressor = try lzma.decompress(allocator, stream.reader());
8 defer decompressor.deinit();
9 const reader = decompressor.reader();
10 return reader.readAllAlloc(allocator, std.math.maxInt(usize));
811}
912
1013fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void {
1114 const allocator = std.testing.allocator;
12 var decomp = std.ArrayList(u8).init(allocator);
13 defer decomp.deinit();
14 try testDecompress(compressed, decomp.writer());
15 try std.testing.expectEqualSlices(u8, expected, decomp.items);
15 const decomp = try testDecompress(compressed);
16 defer allocator.free(decomp);
17 try std.testing.expectEqualSlices(u8, expected, decomp);
1618}
1719
1820fn testDecompressError(expected: anyerror, compressed: []const u8) !void {
19 return std.testing.expectError(expected, testDecompress(compressed, std.io.null_writer));
21 return std.testing.expectError(expected, testDecompress(compressed));
2022}
2123
2224test "LZMA: decompress empty world" {
lib/std/compress/lzma2/decode.zig+1-1
......@@ -141,7 +141,7 @@ pub const Decoder = struct {
141141 const counter_reader = counter.reader();
142142
143143 var rangecoder = try RangeDecoder.init(counter_reader);
144 try self.lzma_state.process(allocator, counter_reader, writer, accum, &rangecoder);
144 while (try self.lzma_state.process(allocator, counter_reader, writer, accum, &rangecoder) == .continue_) {}
145145
146146 if (counter.bytes_read != packed_size) {
147147 return error.CorruptInput;