structstd.compress.lzma.decode.DecoderState[src]

Fields

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

Functions

Functioninit[src]

pub fn init( allocator: Allocator, lzma_props: Properties, unpacked_size: ?u64, ) !DecoderState

Parameters

allocator: Allocator
lzma_props: Properties
unpacked_size: ?u64

Source Code

Source code
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 = @splat(.{}),
        .align_decoder = .{},
        .pos_decoders = @splat(0x400),
        .is_match = @splat(0x400),
        .is_rep = @splat(0x400),
        .is_rep_g0 = @splat(0x400),
        .is_rep_g1 = @splat(0x400),
        .is_rep_g2 = @splat(0x400),
        .is_rep_0long = @splat(0x400),
        .state = 0,
        .rep = @splat(0),
        .len_decoder = .{},
        .rep_len_decoder = .{},
    };
}

Functiondeinit[src]

pub fn deinit(self: *DecoderState, allocator: Allocator) void

Parameters

allocator: Allocator

Source Code

Source code
pub fn deinit(self: *DecoderState, allocator: Allocator) void {
    self.literal_probs.deinit(allocator);
    self.* = undefined;
}

FunctionresetState[src]

pub fn resetState(self: *DecoderState, allocator: Allocator, new_props: Properties) !void

Parameters

allocator: Allocator
new_props: Properties

Source Code

Source code
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 = @splat(0x400);
    self.is_match = @splat(0x400);
    self.is_rep = @splat(0x400);
    self.is_rep_g0 = @splat(0x400);
    self.is_rep_g1 = @splat(0x400);
    self.is_rep_g2 = @splat(0x400);
    self.is_rep_0long = @splat(0x400);
    self.state = 0;
    self.rep = @splat(0);
    self.len_decoder.reset();
    self.rep_len_decoder.reset();
}

Functionprocess[src]

pub fn process( self: *DecoderState, allocator: Allocator, reader: anytype, writer: anytype, buffer: anytype, decoder: *RangeDecoder, ) !ProcessingStatus

Parameters

allocator: Allocator
decoder: *RangeDecoder

Source Code

Source code
pub fn process(
    self: *DecoderState,
    allocator: Allocator,
    reader: anytype,
    writer: anytype,
    buffer: anytype,
    decoder: *RangeDecoder,
) !ProcessingStatus {
    process_next: {
        if (self.unpacked_size) |unpacked_size| {
            if (buffer.len >= unpacked_size) {
                break :process_next;
            }
        } else if (decoder.isFinished()) {
            break :process_next;
        }

        switch (try self.processNext(allocator, reader, writer, buffer, decoder)) {
            .continue_ => return .continue_,
            .finished => break :process_next,
        }
    }

    if (self.unpacked_size) |unpacked_size| {
        if (buffer.len != unpacked_size) {
            return error.CorruptInput;
        }
    }

    return .finished;
}

Source Code

Source code
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 = @splat(.{}),
            .align_decoder = .{},
            .pos_decoders = @splat(0x400),
            .is_match = @splat(0x400),
            .is_rep = @splat(0x400),
            .is_rep_g0 = @splat(0x400),
            .is_rep_g1 = @splat(0x400),
            .is_rep_g2 = @splat(0x400),
            .is_rep_0long = @splat(0x400),
            .state = 0,
            .rep = @splat(0),
            .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 = @splat(0x400);
        self.is_match = @splat(0x400);
        self.is_rep = @splat(0x400);
        self.is_rep_g0 = @splat(0x400);
        self.is_rep_g1 = @splat(0x400);
        self.is_rep_g2 = @splat(0x400);
        self.is_rep_0long = @splat(0x400);
        self.state = 0;
        self.rep = @splat(0);
        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,
    ) !ProcessingStatus {
        process_next: {
            if (self.unpacked_size) |unpacked_size| {
                if (buffer.len >= unpacked_size) {
                    break :process_next;
                }
            } else if (decoder.isFinished()) {
                break :process_next;
            }

            switch (try self.processNext(allocator, reader, writer, buffer, decoder)) {
                .continue_ => return .continue_,
                .finished => break :process_next,
            }
        }

        if (self.unpacked_size) |unpacked_size| {
            if (buffer.len != unpacked_size) {
                return error.CorruptInput;
            }
        }

        return .finished;
    }

    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 = @intFromBool(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) ^ @intFromBool(try decoder.decodeBit(reader, &probs[result], update));
        }

        return @as(u8, @truncate(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 = @as(u5, @intCast((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;
    }
}