mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 16:45:27 +00:00
Delete redundant lzma
/lzma2
prefix in function/struct names
This commit is contained in:
parent
d57813e3e9
commit
e03d6c42ea
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
@ -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,
|
||||
|
@ -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 },
|
||||
);
|
||||
}
|
@ -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"),
|
26
lib/std/compress/lzma2.zig
Normal file
26
lib/std/compress/lzma2.zig
Normal file
@ -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);
|
||||
}
|
@ -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);
|
Loading…
Reference in New Issue
Block a user