From e03d6c42ea8b65a3b283c4da8c9593b82762874c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Sun, 5 Feb 2023 06:52:28 -0800 Subject: [PATCH] Delete redundant `lzma`/`lzma2` prefix in function/struct names --- lib/std/compress.zig | 2 + lib/std/compress/lzma.zig | 23 +- lib/std/compress/lzma/decode.zig | 397 ++++++++++++++++- lib/std/compress/lzma/decode/lzma.zig | 398 ------------------ lib/std/compress/lzma/decode/rangecoder.zig | 3 - lib/std/compress/lzma/lzma2_test.zig | 27 -- .../compress/lzma/{lzma_test.zig => test.zig} | 18 +- lib/std/compress/lzma2.zig | 26 ++ .../decode/lzma2.zig => lzma2/decode.zig} | 28 +- 9 files changed, 450 insertions(+), 472 deletions(-) delete mode 100644 lib/std/compress/lzma/decode/lzma.zig delete mode 100644 lib/std/compress/lzma/lzma2_test.zig rename lib/std/compress/lzma/{lzma_test.zig => test.zig} (83%) create mode 100644 lib/std/compress/lzma2.zig rename lib/std/compress/{lzma/decode/lzma2.zig => lzma2/decode.zig} (86%) diff --git a/lib/std/compress.zig b/lib/std/compress.zig index 03d05c1ef7..9af1b30259 100644 --- a/lib/std/compress.zig +++ b/lib/std/compress.zig @@ -3,6 +3,7 @@ const std = @import("std.zig"); pub const deflate = @import("compress/deflate.zig"); pub const gzip = @import("compress/gzip.zig"); pub const lzma = @import("compress/lzma.zig"); +pub const lzma2 = @import("compress/lzma2.zig"); pub const xz = @import("compress/xz.zig"); pub const zlib = @import("compress/zlib.zig"); @@ -40,6 +41,7 @@ test { _ = deflate; _ = gzip; _ = lzma; + _ = lzma2; _ = xz; _ = zlib; } diff --git a/lib/std/compress/lzma.zig b/lib/std/compress/lzma.zig index 3cf7f65459..6e7c29684b 100644 --- a/lib/std/compress/lzma.zig +++ b/lib/std/compress/lzma.zig @@ -1,36 +1,21 @@ const std = @import("../std.zig"); const Allocator = std.mem.Allocator; -const FixedBufferStream = std.io.FixedBufferStream; pub const decode = @import("lzma/decode.zig"); -pub const LzmaParams = decode.lzma.LzmaParams; -pub const LzmaDecoder = decode.lzma.LzmaDecoder; -pub const Lzma2Decoder = decode.lzma2.Lzma2Decoder; -pub fn lzmaDecompress( +pub fn decompress( allocator: Allocator, reader: anytype, writer: anytype, options: decode.Options, ) !void { - const params = try LzmaParams.readHeader(reader, options); - var decoder = try LzmaDecoder.init(allocator, params, options.memlimit); - defer decoder.deinit(allocator); - return decoder.decompress(allocator, reader, writer); -} - -pub fn lzma2Decompress( - allocator: Allocator, - reader: anytype, - writer: anytype, -) !void { - var decoder = try Lzma2Decoder.init(allocator); + const params = try decode.Params.readHeader(reader, options); + var decoder = try decode.Decoder.init(allocator, params, options.memlimit); defer decoder.deinit(allocator); return decoder.decompress(allocator, reader, writer); } test { - _ = @import("lzma/lzma_test.zig"); - _ = @import("lzma/lzma2_test.zig"); + _ = @import("lzma/test.zig"); _ = @import("lzma/vec2d.zig"); } diff --git a/lib/std/compress/lzma/decode.zig b/lib/std/compress/lzma/decode.zig index f0615516f7..31a676b40a 100644 --- a/lib/std/compress/lzma/decode.zig +++ b/lib/std/compress/lzma/decode.zig @@ -1,8 +1,17 @@ +const std = @import("../../std.zig"); +const assert = std.debug.assert; +const math = std.math; +const Allocator = std.mem.Allocator; + pub const lzbuffer = @import("decode/lzbuffer.zig"); -pub const lzma = @import("decode/lzma.zig"); -pub const lzma2 = @import("decode/lzma2.zig"); pub const rangecoder = @import("decode/rangecoder.zig"); +const LzCircularBuffer = lzbuffer.LzCircularBuffer; +const BitTree = rangecoder.BitTree; +const LenDecoder = rangecoder.LenDecoder; +const RangeDecoder = rangecoder.RangeDecoder; +const Vec2D = @import("vec2d.zig").Vec2D; + pub const Options = struct { unpacked_size: UnpackedSize = .read_from_header, memlimit: ?usize = null, @@ -14,3 +23,387 @@ pub const UnpackedSize = union(enum) { read_header_but_use_provided: ?u64, use_provided: ?u64, }; + +const ProcessingStatus = enum { + continue_, + finished, +}; + +pub const Properties = struct { + lc: u4, + lp: u3, + pb: u3, + + fn validate(self: Properties) void { + assert(self.lc <= 8); + assert(self.lp <= 4); + assert(self.pb <= 4); + } +}; + +pub const Params = struct { + properties: Properties, + dict_size: u32, + unpacked_size: ?u64, + + pub fn readHeader(reader: anytype, options: Options) !Params { + var props = try reader.readByte(); + if (props >= 225) { + return error.CorruptInput; + } + + const lc = @intCast(u4, props % 9); + props /= 9; + const lp = @intCast(u3, props % 5); + props /= 5; + const pb = @intCast(u3, props); + + const dict_size_provided = try reader.readIntLittle(u32); + const dict_size = math.max(0x1000, dict_size_provided); + + const unpacked_size = switch (options.unpacked_size) { + .read_from_header => blk: { + const unpacked_size_provided = try reader.readIntLittle(u64); + const marker_mandatory = unpacked_size_provided == 0xFFFF_FFFF_FFFF_FFFF; + break :blk if (marker_mandatory) + null + else + unpacked_size_provided; + }, + .read_header_but_use_provided => |x| blk: { + _ = try reader.readIntLittle(u64); + break :blk x; + }, + .use_provided => |x| x, + }; + + return Params{ + .properties = Properties{ .lc = lc, .lp = lp, .pb = pb }, + .dict_size = dict_size, + .unpacked_size = unpacked_size, + }; + } +}; + +pub const DecoderState = struct { + lzma_props: Properties, + unpacked_size: ?u64, + literal_probs: Vec2D(u16), + pos_slot_decoder: [4]BitTree(6), + align_decoder: BitTree(4), + pos_decoders: [115]u16, + is_match: [192]u16, + is_rep: [12]u16, + is_rep_g0: [12]u16, + is_rep_g1: [12]u16, + is_rep_g2: [12]u16, + is_rep_0long: [192]u16, + state: usize, + rep: [4]usize, + len_decoder: LenDecoder, + rep_len_decoder: LenDecoder, + + pub fn init( + allocator: Allocator, + lzma_props: Properties, + unpacked_size: ?u64, + ) !DecoderState { + return .{ + .lzma_props = lzma_props, + .unpacked_size = unpacked_size, + .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }), + .pos_slot_decoder = .{.{}} ** 4, + .align_decoder = .{}, + .pos_decoders = .{0x400} ** 115, + .is_match = .{0x400} ** 192, + .is_rep = .{0x400} ** 12, + .is_rep_g0 = .{0x400} ** 12, + .is_rep_g1 = .{0x400} ** 12, + .is_rep_g2 = .{0x400} ** 12, + .is_rep_0long = .{0x400} ** 192, + .state = 0, + .rep = .{0} ** 4, + .len_decoder = .{}, + .rep_len_decoder = .{}, + }; + } + + pub fn deinit(self: *DecoderState, allocator: Allocator) void { + self.literal_probs.deinit(allocator); + self.* = undefined; + } + + pub fn resetState(self: *DecoderState, allocator: Allocator, new_props: Properties) !void { + new_props.validate(); + if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) { + self.literal_probs.fill(0x400); + } else { + self.literal_probs.deinit(allocator); + self.literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (new_props.lc + new_props.lp), 0x300 }); + } + + self.lzma_props = new_props; + for (self.pos_slot_decoder) |*t| t.reset(); + self.align_decoder.reset(); + self.pos_decoders = .{0x400} ** 115; + self.is_match = .{0x400} ** 192; + self.is_rep = .{0x400} ** 12; + self.is_rep_g0 = .{0x400} ** 12; + self.is_rep_g1 = .{0x400} ** 12; + self.is_rep_g2 = .{0x400} ** 12; + self.is_rep_0long = .{0x400} ** 192; + self.state = 0; + self.rep = .{0} ** 4; + self.len_decoder.reset(); + self.rep_len_decoder.reset(); + } + + fn processNextInner( + self: *DecoderState, + allocator: Allocator, + reader: anytype, + writer: anytype, + buffer: anytype, + decoder: *RangeDecoder, + update: bool, + ) !ProcessingStatus { + const pos_state = buffer.len & ((@as(usize, 1) << self.lzma_props.pb) - 1); + + if (!try decoder.decodeBit( + reader, + &self.is_match[(self.state << 4) + pos_state], + update, + )) { + const byte: u8 = try self.decodeLiteral(reader, buffer, decoder, update); + + if (update) { + try buffer.appendLiteral(allocator, byte, writer); + + self.state = if (self.state < 4) + 0 + else if (self.state < 10) + self.state - 3 + else + self.state - 6; + } + return .continue_; + } + + var len: usize = undefined; + if (try decoder.decodeBit(reader, &self.is_rep[self.state], update)) { + if (!try decoder.decodeBit(reader, &self.is_rep_g0[self.state], update)) { + if (!try decoder.decodeBit( + reader, + &self.is_rep_0long[(self.state << 4) + pos_state], + update, + )) { + if (update) { + self.state = if (self.state < 7) 9 else 11; + const dist = self.rep[0] + 1; + try buffer.appendLz(allocator, 1, dist, writer); + } + return .continue_; + } + } else { + const idx: usize = if (!try decoder.decodeBit(reader, &self.is_rep_g1[self.state], update)) + 1 + else if (!try decoder.decodeBit(reader, &self.is_rep_g2[self.state], update)) + 2 + else + 3; + if (update) { + const dist = self.rep[idx]; + var i = idx; + while (i > 0) : (i -= 1) { + self.rep[i] = self.rep[i - 1]; + } + self.rep[0] = dist; + } + } + + len = try self.rep_len_decoder.decode(reader, decoder, pos_state, update); + + if (update) { + self.state = if (self.state < 7) 8 else 11; + } + } else { + if (update) { + self.rep[3] = self.rep[2]; + self.rep[2] = self.rep[1]; + self.rep[1] = self.rep[0]; + } + + len = try self.len_decoder.decode(reader, decoder, pos_state, update); + + if (update) { + self.state = if (self.state < 7) 7 else 10; + } + + const rep_0 = try self.decodeDistance(reader, decoder, len, update); + + if (update) { + self.rep[0] = rep_0; + if (self.rep[0] == 0xFFFF_FFFF) { + if (decoder.isFinished()) { + return .finished; + } + return error.CorruptInput; + } + } + } + + if (update) { + len += 2; + + const dist = self.rep[0] + 1; + try buffer.appendLz(allocator, len, dist, writer); + } + + return .continue_; + } + + fn processNext( + self: *DecoderState, + allocator: Allocator, + reader: anytype, + writer: anytype, + buffer: anytype, + decoder: *RangeDecoder, + ) !ProcessingStatus { + return self.processNextInner(allocator, reader, writer, buffer, decoder, true); + } + + pub fn process( + self: *DecoderState, + allocator: Allocator, + reader: anytype, + writer: anytype, + buffer: anytype, + decoder: *RangeDecoder, + ) !void { + while (true) { + if (self.unpacked_size) |unpacked_size| { + if (buffer.len >= unpacked_size) { + break; + } + } else if (decoder.isFinished()) { + break; + } + + if (try self.processNext(allocator, reader, writer, buffer, decoder) == .finished) { + break; + } + } + + if (self.unpacked_size) |len| { + if (len != buffer.len) { + return error.CorruptInput; + } + } + } + + fn decodeLiteral( + self: *DecoderState, + reader: anytype, + buffer: anytype, + decoder: *RangeDecoder, + update: bool, + ) !u8 { + const def_prev_byte = 0; + const prev_byte = @as(usize, buffer.lastOr(def_prev_byte)); + + var result: usize = 1; + const lit_state = ((buffer.len & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) + + (prev_byte >> (8 - self.lzma_props.lc)); + const probs = try self.literal_probs.getMut(lit_state); + + if (self.state >= 7) { + var match_byte = @as(usize, try buffer.lastN(self.rep[0] + 1)); + + while (result < 0x100) { + const match_bit = (match_byte >> 7) & 1; + match_byte <<= 1; + const bit = @boolToInt(try decoder.decodeBit( + reader, + &probs[((@as(usize, 1) + match_bit) << 8) + result], + update, + )); + result = (result << 1) ^ bit; + if (match_bit != bit) { + break; + } + } + } + + while (result < 0x100) { + result = (result << 1) ^ @boolToInt(try decoder.decodeBit(reader, &probs[result], update)); + } + + return @truncate(u8, result - 0x100); + } + + fn decodeDistance( + self: *DecoderState, + reader: anytype, + decoder: *RangeDecoder, + length: usize, + update: bool, + ) !usize { + const len_state = if (length > 3) 3 else length; + + const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(reader, decoder, update)); + if (pos_slot < 4) + return pos_slot; + + const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1); + var result = (2 ^ (pos_slot & 1)) << num_direct_bits; + + if (pos_slot < 14) { + result += try decoder.parseReverseBitTree( + reader, + num_direct_bits, + &self.pos_decoders, + result - pos_slot, + update, + ); + } else { + result += @as(usize, try decoder.get(reader, num_direct_bits - 4)) << 4; + result += try self.align_decoder.parseReverse(reader, decoder, update); + } + + return result; + } +}; + +pub const Decoder = struct { + params: Params, + memlimit: usize, + state: DecoderState, + + pub fn init(allocator: Allocator, params: Params, memlimit: ?usize) !Decoder { + return Decoder{ + .params = params, + .memlimit = memlimit orelse math.maxInt(usize), + .state = try DecoderState.init(allocator, params.properties, params.unpacked_size), + }; + } + + pub fn deinit(self: *Decoder, allocator: Allocator) void { + self.state.deinit(allocator); + self.* = undefined; + } + + pub fn decompress( + self: *Decoder, + allocator: Allocator, + reader: anytype, + writer: anytype, + ) !void { + var buffer = LzCircularBuffer.init(self.params.dict_size, self.memlimit); + defer buffer.deinit(allocator); + + var decoder = try RangeDecoder.init(reader); + try self.state.process(allocator, reader, writer, &buffer, &decoder); + try buffer.finish(writer); + } +}; diff --git a/lib/std/compress/lzma/decode/lzma.zig b/lib/std/compress/lzma/decode/lzma.zig deleted file mode 100644 index dfa24f7e91..0000000000 --- a/lib/std/compress/lzma/decode/lzma.zig +++ /dev/null @@ -1,398 +0,0 @@ -const std = @import("../../../std.zig"); -const assert = std.debug.assert; -const math = std.math; -const Allocator = std.mem.Allocator; -const ArrayListUnmanaged = std.ArrayListUnmanaged; -const FixedBufferStream = std.io.FixedBufferStream; - -const LzCircularBuffer = @import("lzbuffer.zig").LzCircularBuffer; -const Options = @import("../decode.zig").Options; -const Vec2D = @import("../vec2d.zig").Vec2D; -const rangecoder = @import("rangecoder.zig"); -const BitTree = rangecoder.BitTree; -const LenDecoder = rangecoder.LenDecoder; -const RangeDecoder = rangecoder.RangeDecoder; - -const ProcessingStatus = enum { - continue_, - finished, -}; - -pub const LzmaProperties = struct { - lc: u4, - lp: u3, - pb: u3, - - fn validate(self: LzmaProperties) void { - assert(self.lc <= 8); - assert(self.lp <= 4); - assert(self.pb <= 4); - } -}; - -pub const LzmaParams = struct { - properties: LzmaProperties, - dict_size: u32, - unpacked_size: ?u64, - - pub fn readHeader(reader: anytype, options: Options) !LzmaParams { - var props = try reader.readByte(); - if (props >= 225) { - return error.CorruptInput; - } - - const lc = @intCast(u4, props % 9); - props /= 9; - const lp = @intCast(u3, props % 5); - props /= 5; - const pb = @intCast(u3, props); - - const dict_size_provided = try reader.readIntLittle(u32); - const dict_size = math.max(0x1000, dict_size_provided); - - const unpacked_size = switch (options.unpacked_size) { - .read_from_header => blk: { - const unpacked_size_provided = try reader.readIntLittle(u64); - const marker_mandatory = unpacked_size_provided == 0xFFFF_FFFF_FFFF_FFFF; - break :blk if (marker_mandatory) - null - else - unpacked_size_provided; - }, - .read_header_but_use_provided => |x| blk: { - _ = try reader.readIntLittle(u64); - break :blk x; - }, - .use_provided => |x| x, - }; - - return LzmaParams{ - .properties = LzmaProperties{ .lc = lc, .lp = lp, .pb = pb }, - .dict_size = dict_size, - .unpacked_size = unpacked_size, - }; - } -}; - -pub const DecoderState = struct { - lzma_props: LzmaProperties, - unpacked_size: ?u64, - literal_probs: Vec2D(u16), - pos_slot_decoder: [4]BitTree(6), - align_decoder: BitTree(4), - pos_decoders: [115]u16, - is_match: [192]u16, - is_rep: [12]u16, - is_rep_g0: [12]u16, - is_rep_g1: [12]u16, - is_rep_g2: [12]u16, - is_rep_0long: [192]u16, - state: usize, - rep: [4]usize, - len_decoder: LenDecoder, - rep_len_decoder: LenDecoder, - - pub fn init( - allocator: Allocator, - lzma_props: LzmaProperties, - unpacked_size: ?u64, - ) !DecoderState { - return .{ - .lzma_props = lzma_props, - .unpacked_size = unpacked_size, - .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }), - .pos_slot_decoder = .{.{}} ** 4, - .align_decoder = .{}, - .pos_decoders = .{0x400} ** 115, - .is_match = .{0x400} ** 192, - .is_rep = .{0x400} ** 12, - .is_rep_g0 = .{0x400} ** 12, - .is_rep_g1 = .{0x400} ** 12, - .is_rep_g2 = .{0x400} ** 12, - .is_rep_0long = .{0x400} ** 192, - .state = 0, - .rep = .{0} ** 4, - .len_decoder = .{}, - .rep_len_decoder = .{}, - }; - } - - pub fn deinit(self: *DecoderState, allocator: Allocator) void { - self.literal_probs.deinit(allocator); - self.* = undefined; - } - - pub fn resetState(self: *DecoderState, allocator: Allocator, new_props: LzmaProperties) !void { - new_props.validate(); - if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) { - self.literal_probs.fill(0x400); - } else { - self.literal_probs.deinit(allocator); - self.literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (new_props.lc + new_props.lp), 0x300 }); - } - - self.lzma_props = new_props; - for (self.pos_slot_decoder) |*t| t.reset(); - self.align_decoder.reset(); - self.pos_decoders = .{0x400} ** 115; - self.is_match = .{0x400} ** 192; - self.is_rep = .{0x400} ** 12; - self.is_rep_g0 = .{0x400} ** 12; - self.is_rep_g1 = .{0x400} ** 12; - self.is_rep_g2 = .{0x400} ** 12; - self.is_rep_0long = .{0x400} ** 192; - self.state = 0; - self.rep = .{0} ** 4; - self.len_decoder.reset(); - self.rep_len_decoder.reset(); - } - - fn processNextInner( - self: *DecoderState, - allocator: Allocator, - reader: anytype, - writer: anytype, - buffer: anytype, - decoder: *RangeDecoder, - update: bool, - ) !ProcessingStatus { - const pos_state = buffer.len & ((@as(usize, 1) << self.lzma_props.pb) - 1); - - if (!try decoder.decodeBit( - reader, - &self.is_match[(self.state << 4) + pos_state], - update, - )) { - const byte: u8 = try self.decodeLiteral(reader, buffer, decoder, update); - - if (update) { - try buffer.appendLiteral(allocator, byte, writer); - - self.state = if (self.state < 4) - 0 - else if (self.state < 10) - self.state - 3 - else - self.state - 6; - } - return .continue_; - } - - var len: usize = undefined; - if (try decoder.decodeBit(reader, &self.is_rep[self.state], update)) { - if (!try decoder.decodeBit(reader, &self.is_rep_g0[self.state], update)) { - if (!try decoder.decodeBit( - reader, - &self.is_rep_0long[(self.state << 4) + pos_state], - update, - )) { - if (update) { - self.state = if (self.state < 7) 9 else 11; - const dist = self.rep[0] + 1; - try buffer.appendLz(allocator, 1, dist, writer); - } - return .continue_; - } - } else { - const idx: usize = if (!try decoder.decodeBit(reader, &self.is_rep_g1[self.state], update)) - 1 - else if (!try decoder.decodeBit(reader, &self.is_rep_g2[self.state], update)) - 2 - else - 3; - if (update) { - const dist = self.rep[idx]; - var i = idx; - while (i > 0) : (i -= 1) { - self.rep[i] = self.rep[i - 1]; - } - self.rep[0] = dist; - } - } - - len = try self.rep_len_decoder.decode(reader, decoder, pos_state, update); - - if (update) { - self.state = if (self.state < 7) 8 else 11; - } - } else { - if (update) { - self.rep[3] = self.rep[2]; - self.rep[2] = self.rep[1]; - self.rep[1] = self.rep[0]; - } - - len = try self.len_decoder.decode(reader, decoder, pos_state, update); - - if (update) { - self.state = if (self.state < 7) 7 else 10; - } - - const rep_0 = try self.decodeDistance(reader, decoder, len, update); - - if (update) { - self.rep[0] = rep_0; - if (self.rep[0] == 0xFFFF_FFFF) { - if (decoder.isFinished()) { - return .finished; - } - return error.CorruptInput; - } - } - } - - if (update) { - len += 2; - - const dist = self.rep[0] + 1; - try buffer.appendLz(allocator, len, dist, writer); - } - - return .continue_; - } - - fn processNext( - self: *DecoderState, - allocator: Allocator, - reader: anytype, - writer: anytype, - buffer: anytype, - decoder: *RangeDecoder, - ) !ProcessingStatus { - return self.processNextInner(allocator, reader, writer, buffer, decoder, true); - } - - pub fn process( - self: *DecoderState, - allocator: Allocator, - reader: anytype, - writer: anytype, - buffer: anytype, - decoder: *RangeDecoder, - ) !void { - while (true) { - if (self.unpacked_size) |unpacked_size| { - if (buffer.len >= unpacked_size) { - break; - } - } else if (decoder.isFinished()) { - break; - } - - if (try self.processNext(allocator, reader, writer, buffer, decoder) == .finished) { - break; - } - } - - if (self.unpacked_size) |len| { - if (len != buffer.len) { - return error.CorruptInput; - } - } - } - - fn decodeLiteral( - self: *DecoderState, - reader: anytype, - buffer: anytype, - decoder: *RangeDecoder, - update: bool, - ) !u8 { - const def_prev_byte = 0; - const prev_byte = @as(usize, buffer.lastOr(def_prev_byte)); - - var result: usize = 1; - const lit_state = ((buffer.len & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) + - (prev_byte >> (8 - self.lzma_props.lc)); - const probs = try self.literal_probs.getMut(lit_state); - - if (self.state >= 7) { - var match_byte = @as(usize, try buffer.lastN(self.rep[0] + 1)); - - while (result < 0x100) { - const match_bit = (match_byte >> 7) & 1; - match_byte <<= 1; - const bit = @boolToInt(try decoder.decodeBit( - reader, - &probs[((@as(usize, 1) + match_bit) << 8) + result], - update, - )); - result = (result << 1) ^ bit; - if (match_bit != bit) { - break; - } - } - } - - while (result < 0x100) { - result = (result << 1) ^ @boolToInt(try decoder.decodeBit(reader, &probs[result], update)); - } - - return @truncate(u8, result - 0x100); - } - - fn decodeDistance( - self: *DecoderState, - reader: anytype, - decoder: *RangeDecoder, - length: usize, - update: bool, - ) !usize { - const len_state = if (length > 3) 3 else length; - - const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(reader, decoder, update)); - if (pos_slot < 4) - return pos_slot; - - const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1); - var result = (2 ^ (pos_slot & 1)) << num_direct_bits; - - if (pos_slot < 14) { - result += try decoder.parseReverseBitTree( - reader, - num_direct_bits, - &self.pos_decoders, - result - pos_slot, - update, - ); - } else { - result += @as(usize, try decoder.get(reader, num_direct_bits - 4)) << 4; - result += try self.align_decoder.parseReverse(reader, decoder, update); - } - - return result; - } -}; - -pub const LzmaDecoder = struct { - params: LzmaParams, - memlimit: usize, - state: DecoderState, - - pub fn init(allocator: Allocator, params: LzmaParams, memlimit: ?usize) !LzmaDecoder { - return LzmaDecoder{ - .params = params, - .memlimit = memlimit orelse math.maxInt(usize), - .state = try DecoderState.init(allocator, params.properties, params.unpacked_size), - }; - } - - pub fn deinit(self: *LzmaDecoder, allocator: Allocator) void { - self.state.deinit(allocator); - self.* = undefined; - } - - pub fn decompress( - self: *LzmaDecoder, - allocator: Allocator, - reader: anytype, - writer: anytype, - ) !void { - var buffer = LzCircularBuffer.init(self.params.dict_size, self.memlimit); - defer buffer.deinit(allocator); - - var decoder = try RangeDecoder.init(reader); - try self.state.process(allocator, reader, writer, &buffer, &decoder); - try buffer.finish(writer); - } -}; diff --git a/lib/std/compress/lzma/decode/rangecoder.zig b/lib/std/compress/lzma/decode/rangecoder.zig index dc85558e3e..6b6ca15997 100644 --- a/lib/std/compress/lzma/decode/rangecoder.zig +++ b/lib/std/compress/lzma/decode/rangecoder.zig @@ -1,8 +1,5 @@ const std = @import("../../../std.zig"); const mem = std.mem; -const Allocator = std.mem.Allocator; -const ArrayListUnmanaged = std.ArrayListUnmanaged; -const FixedBufferStream = std.io.FixedBufferStream; pub const RangeDecoder = struct { range: u32, diff --git a/lib/std/compress/lzma/lzma2_test.zig b/lib/std/compress/lzma/lzma2_test.zig deleted file mode 100644 index 47ebe2d031..0000000000 --- a/lib/std/compress/lzma/lzma2_test.zig +++ /dev/null @@ -1,27 +0,0 @@ -const std = @import("../../std.zig"); -const lzma = @import("../lzma.zig"); - -fn testDecompress(compressed: []const u8, writer: anytype) !void { - const allocator = std.testing.allocator; - var stream = std.io.fixedBufferStream(compressed); - try lzma.lzma2Decompress(allocator, stream.reader(), writer); -} - -fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void { - const allocator = std.testing.allocator; - var decomp = std.ArrayList(u8).init(allocator); - defer decomp.deinit(); - try testDecompress(compressed, decomp.writer()); - try std.testing.expectEqualSlices(u8, expected, decomp.items); -} - -fn testDecompressError(expected: anyerror, compressed: []const u8) !void { - return std.testing.expectError(expected, testDecompress(compressed, std.io.null_writer)); -} - -test { - try testDecompressEqual( - "Hello\nWorld!\n", - &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 }, - ); -} diff --git a/lib/std/compress/lzma/lzma_test.zig b/lib/std/compress/lzma/test.zig similarity index 83% rename from lib/std/compress/lzma/lzma_test.zig rename to lib/std/compress/lzma/test.zig index 2147ca62c5..e720d87222 100644 --- a/lib/std/compress/lzma/lzma_test.zig +++ b/lib/std/compress/lzma/test.zig @@ -4,7 +4,7 @@ const lzma = @import("../lzma.zig"); fn testDecompress(compressed: []const u8, writer: anytype) !void { const allocator = std.testing.allocator; var stream = std.io.fixedBufferStream(compressed); - try lzma.lzmaDecompress(allocator, stream.reader(), writer, .{}); + try lzma.decompress(allocator, stream.reader(), writer, .{}); } fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void { @@ -19,7 +19,7 @@ fn testDecompressError(expected: anyerror, compressed: []const u8) !void { return std.testing.expectError(expected, testDecompress(compressed, std.io.null_writer)); } -test "decompress empty world" { +test "LZMA: decompress empty world" { try testDecompressEqual( "", &[_]u8{ @@ -29,7 +29,7 @@ test "decompress empty world" { ); } -test "decompress hello world" { +test "LZMA: decompress hello world" { try testDecompressEqual( "Hello world\n", &[_]u8{ @@ -40,7 +40,7 @@ test "decompress hello world" { ); } -test "decompress huge dict" { +test "LZMA: decompress huge dict" { try testDecompressEqual( "Hello world\n", &[_]u8{ @@ -51,35 +51,35 @@ test "decompress huge dict" { ); } -test "unknown size with end of payload marker" { +test "LZMA: unknown size with end of payload marker" { try testDecompressEqual( "Hello\nWorld!\n", @embedFile("testdata/good-unknown_size-with_eopm.lzma"), ); } -test "known size without end of payload marker" { +test "LZMA: known size without end of payload marker" { try testDecompressEqual( "Hello\nWorld!\n", @embedFile("testdata/good-known_size-without_eopm.lzma"), ); } -test "known size with end of payload marker" { +test "LZMA: known size with end of payload marker" { try testDecompressEqual( "Hello\nWorld!\n", @embedFile("testdata/good-known_size-with_eopm.lzma"), ); } -test "too big uncompressed size in header" { +test "LZMA: too big uncompressed size in header" { try testDecompressError( error.CorruptInput, @embedFile("testdata/bad-too_big_size-with_eopm.lzma"), ); } -test "too small uncompressed size in header" { +test "LZMA: too small uncompressed size in header" { try testDecompressError( error.CorruptInput, @embedFile("testdata/bad-too_small_size-without_eopm-3.lzma"), diff --git a/lib/std/compress/lzma2.zig b/lib/std/compress/lzma2.zig new file mode 100644 index 0000000000..2797990f9c --- /dev/null +++ b/lib/std/compress/lzma2.zig @@ -0,0 +1,26 @@ +const std = @import("../std.zig"); +const Allocator = std.mem.Allocator; + +pub const decode = @import("lzma2/decode.zig"); + +pub fn decompress( + allocator: Allocator, + reader: anytype, + writer: anytype, +) !void { + var decoder = try decode.Decoder.init(allocator); + defer decoder.deinit(allocator); + return decoder.decompress(allocator, reader, writer); +} + +test { + const expected = "Hello\nWorld!\n"; + const compressed = &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 }; + + const allocator = std.testing.allocator; + var decomp = std.ArrayList(u8).init(allocator); + defer decomp.deinit(); + var stream = std.io.fixedBufferStream(compressed); + try decompress(allocator, stream.reader(), decomp.writer()); + try std.testing.expectEqualSlices(u8, expected, decomp.items); +} diff --git a/lib/std/compress/lzma/decode/lzma2.zig b/lib/std/compress/lzma2/decode.zig similarity index 86% rename from lib/std/compress/lzma/decode/lzma2.zig rename to lib/std/compress/lzma2/decode.zig index 7de4fd0e17..911f0352f2 100644 --- a/lib/std/compress/lzma/decode/lzma2.zig +++ b/lib/std/compress/lzma2/decode.zig @@ -1,20 +1,20 @@ -const std = @import("../../../std.zig"); +const std = @import("../../std.zig"); const Allocator = std.mem.Allocator; -const lzma = @import("lzma.zig"); -const DecoderState = lzma.DecoderState; -const LzmaProperties = lzma.LzmaProperties; -const LzAccumBuffer = @import("lzbuffer.zig").LzAccumBuffer; -const RangeDecoder = @import("rangecoder.zig").RangeDecoder; +const lzma = @import("../lzma.zig"); +const DecoderState = lzma.decode.DecoderState; +const LzAccumBuffer = lzma.decode.lzbuffer.LzAccumBuffer; +const Properties = lzma.decode.Properties; +const RangeDecoder = lzma.decode.rangecoder.RangeDecoder; -pub const Lzma2Decoder = struct { +pub const Decoder = struct { lzma_state: DecoderState, - pub fn init(allocator: Allocator) !Lzma2Decoder { - return Lzma2Decoder{ + pub fn init(allocator: Allocator) !Decoder { + return Decoder{ .lzma_state = try DecoderState.init( allocator, - LzmaProperties{ + Properties{ .lc = 0, .lp = 0, .pb = 0, @@ -24,13 +24,13 @@ pub const Lzma2Decoder = struct { }; } - pub fn deinit(self: *Lzma2Decoder, allocator: Allocator) void { + pub fn deinit(self: *Decoder, allocator: Allocator) void { self.lzma_state.deinit(allocator); self.* = undefined; } pub fn decompress( - self: *Lzma2Decoder, + self: *Decoder, allocator: Allocator, reader: anytype, writer: anytype, @@ -53,7 +53,7 @@ pub const Lzma2Decoder = struct { } fn parseLzma( - self: *Lzma2Decoder, + self: *Decoder, allocator: Allocator, reader: anytype, writer: anytype, @@ -129,7 +129,7 @@ pub const Lzma2Decoder = struct { return error.CorruptInput; } - new_props = LzmaProperties{ .lc = lc, .lp = lp, .pb = pb }; + new_props = Properties{ .lc = lc, .lp = lp, .pb = pb }; } try self.lzma_state.resetState(allocator, new_props);