authorgravatar for fncontroloption@noreply.codeberg.orgFnControlOption <fncontroloption@noreply.codeberg.org> 2023-02-02 11:59:56-08:00
committergravatar for fncontroloption@noreply.codeberg.orgFnControlOption <fncontroloption@noreply.codeberg.org> 2023-02-02 11:59:56-08:00
log8e2af21cd99d1c033146b1ab15ab743533cbd743
treeb2c6aab52eab7dd46a56c7c1c242e0eb4ee66a79
parent6f13a725a3249c7f0a0f5258ac00003cd132bf15

Add LZMA decoder


18 files changed, 1296 insertions(+), 785 deletions(-)

build.zig+2
...@@ -122,6 +122,8 @@ pub fn build(b: *Builder) !void {...@@ -122,6 +122,8 @@ pub fn build(b: *Builder) !void {
122 "compress-gettysburg.txt",122 "compress-gettysburg.txt",
123 "compress-pi.txt",123 "compress-pi.txt",
124 "rfc1951.txt",124 "rfc1951.txt",
125 // exclude files from lib/std/compress/lzma/testdata
126 ".lzma",
125 // exclude files from lib/std/compress/xz/testdata127 // exclude files from lib/std/compress/xz/testdata
126 ".xz",128 ".xz",
127 // exclude files from lib/std/tz/129 // exclude files from lib/std/tz/
lib/std/compress.zig+4-2
...@@ -2,8 +2,9 @@ const std = @import("std.zig");...@@ -2,8 +2,9 @@ const std = @import("std.zig");
22
3pub const deflate = @import("compress/deflate.zig");3pub const deflate = @import("compress/deflate.zig");
4pub const gzip = @import("compress/gzip.zig");4pub const gzip = @import("compress/gzip.zig");
5pub const zlib = @import("compress/zlib.zig");5pub const lzma = @import("compress/lzma.zig");
6pub const xz = @import("compress/xz.zig");6pub const xz = @import("compress/xz.zig");
7pub const zlib = @import("compress/zlib.zig");
78
8pub fn HashedReader(9pub fn HashedReader(
9 comptime ReaderType: anytype,10 comptime ReaderType: anytype,
...@@ -38,6 +39,7 @@ pub fn hashedReader(...@@ -38,6 +39,7 @@ pub fn hashedReader(
38test {39test {
39 _ = deflate;40 _ = deflate;
40 _ = gzip;41 _ = gzip;
41 _ = zlib;42 _ = lzma;
42 _ = xz;43 _ = xz;
44 _ = zlib;
43}45}
lib/std/compress/lzma.zig created+36
...@@ -0,0 +1,36 @@
1const std = @import("../std.zig");
2const Allocator = std.mem.Allocator;
3const FixedBufferStream = std.io.FixedBufferStream;
4
5pub const decode = @import("lzma/decode.zig");
6pub const LzmaParams = decode.lzma.LzmaParams;
7pub const LzmaDecoder = decode.lzma.LzmaDecoder;
8pub const Lzma2Decoder = decode.lzma2.Lzma2Decoder;
9
10pub fn lzmaDecompress(
11 allocator: Allocator,
12 reader: anytype,
13 writer: anytype,
14 options: decode.Options,
15) !void {
16 const params = try LzmaParams.readHeader(reader, options);
17 var decoder = try LzmaDecoder.init(allocator, params, options.memlimit);
18 defer decoder.deinit(allocator);
19 return decoder.decompress(allocator, reader, writer);
20}
21
22pub fn lzma2Decompress(
23 allocator: Allocator,
24 reader: anytype,
25 writer: anytype,
26) !void {
27 var decoder = try Lzma2Decoder.init(allocator);
28 defer decoder.deinit(allocator);
29 return decoder.decompress(allocator, reader, writer);
30}
31
32test {
33 _ = @import("lzma/lzma_test.zig");
34 _ = @import("lzma/lzma2_test.zig");
35 _ = @import("lzma/vec2d.zig");
36}
lib/std/compress/lzma/decode.zig created+16
...@@ -0,0 +1,16 @@
1pub const lzbuffer = @import("decode/lzbuffer.zig");
2pub const lzma = @import("decode/lzma.zig");
3pub const lzma2 = @import("decode/lzma2.zig");
4pub const rangecoder = @import("decode/rangecoder.zig");
5
6pub const Options = struct {
7 unpacked_size: UnpackedSize = .read_from_header,
8 memlimit: ?usize = null,
9 allow_incomplete: bool = false,
10};
11
12pub const UnpackedSize = union(enum) {
13 read_from_header,
14 read_header_but_use_provided: ?u64,
15 use_provided: ?u64,
16};
lib/std/compress/lzma/decode/lzbuffer.zig created+226
...@@ -0,0 +1,226 @@
1const std = @import("../../../std.zig");
2const math = std.math;
3const mem = std.mem;
4const Allocator = std.mem.Allocator;
5const ArrayListUnmanaged = std.ArrayListUnmanaged;
6
7/// An accumulating buffer for LZ sequences
8pub const LzAccumBuffer = struct {
9 /// Buffer
10 buf: ArrayListUnmanaged(u8),
11
12 /// Buffer memory limit
13 memlimit: usize,
14
15 /// Total number of bytes sent through the buffer
16 len: usize,
17
18 const Self = @This();
19
20 pub fn init(memlimit: usize) Self {
21 return Self{
22 .buf = .{},
23 .memlimit = memlimit,
24 .len = 0,
25 };
26 }
27
28 pub fn appendByte(self: *Self, allocator: Allocator, byte: u8) !void {
29 try self.buf.append(allocator, byte);
30 self.len += 1;
31 }
32
33 /// Reset the internal dictionary
34 pub fn reset(self: *Self, writer: anytype) !void {
35 try writer.writeAll(self.buf.items);
36 self.buf.clearRetainingCapacity();
37 self.len = 0;
38 }
39
40 /// Retrieve the last byte or return a default
41 pub fn lastOr(self: Self, lit: u8) u8 {
42 const buf_len = self.buf.items.len;
43 return if (buf_len == 0)
44 lit
45 else
46 self.buf.items[buf_len - 1];
47 }
48
49 /// Retrieve the n-th last byte
50 pub fn lastN(self: Self, dist: usize) !u8 {
51 const buf_len = self.buf.items.len;
52 if (dist > buf_len) {
53 return error.CorruptInput;
54 }
55
56 return self.buf.items[buf_len - dist];
57 }
58
59 /// Append a literal
60 pub fn appendLiteral(
61 self: *Self,
62 allocator: Allocator,
63 lit: u8,
64 writer: anytype,
65 ) !void {
66 _ = writer;
67 if (self.len >= self.memlimit) {
68 return error.CorruptInput;
69 }
70 try self.buf.append(allocator, lit);
71 self.len += 1;
72 }
73
74 /// Fetch an LZ sequence (length, distance) from inside the buffer
75 pub fn appendLz(
76 self: *Self,
77 allocator: Allocator,
78 len: usize,
79 dist: usize,
80 writer: anytype,
81 ) !void {
82 _ = writer;
83
84 const buf_len = self.buf.items.len;
85 if (dist > buf_len) {
86 return error.CorruptInput;
87 }
88
89 var offset = buf_len - dist;
90 var i: usize = 0;
91 while (i < len) : (i += 1) {
92 const x = self.buf.items[offset];
93 try self.buf.append(allocator, x);
94 offset += 1;
95 }
96 self.len += len;
97 }
98
99 pub fn finish(self: *Self, writer: anytype) !void {
100 try writer.writeAll(self.buf.items);
101 }
102
103 pub fn deinit(self: *Self, allocator: Allocator) void {
104 self.buf.deinit(allocator);
105 self.* = undefined;
106 }
107};
108
109/// A circular buffer for LZ sequences
110pub const LzCircularBuffer = struct {
111 /// Circular buffer
112 buf: ArrayListUnmanaged(u8),
113
114 /// Length of the buffer
115 dict_size: usize,
116
117 /// Buffer memory limit
118 memlimit: usize,
119
120 /// Current position
121 cursor: usize,
122
123 /// Total number of bytes sent through the buffer
124 len: usize,
125
126 const Self = @This();
127
128 pub fn init(dict_size: usize, memlimit: usize) Self {
129 return Self{
130 .buf = .{},
131 .dict_size = dict_size,
132 .memlimit = memlimit,
133 .cursor = 0,
134 .len = 0,
135 };
136 }
137
138 pub fn get(self: Self, index: usize) u8 {
139 return if (0 <= index and index < self.buf.items.len)
140 self.buf.items[index]
141 else
142 0;
143 }
144
145 pub fn set(self: *Self, allocator: Allocator, index: usize, value: u8) !void {
146 if (index >= self.memlimit) {
147 return error.CorruptInput;
148 }
149 try self.buf.ensureTotalCapacity(allocator, index + 1);
150 while (self.buf.items.len < index) {
151 self.buf.appendAssumeCapacity(0);
152 }
153 self.buf.appendAssumeCapacity(value);
154 }
155
156 /// Retrieve the last byte or return a default
157 pub fn lastOr(self: Self, lit: u8) u8 {
158 return if (self.len == 0)
159 lit
160 else
161 self.get((self.dict_size + self.cursor - 1) % self.dict_size);
162 }
163
164 /// Retrieve the n-th last byte
165 pub fn lastN(self: Self, dist: usize) !u8 {
166 if (dist > self.dict_size or dist > self.len) {
167 return error.CorruptInput;
168 }
169
170 const offset = (self.dict_size + self.cursor - dist) % self.dict_size;
171 return self.get(offset);
172 }
173
174 /// Append a literal
175 pub fn appendLiteral(
176 self: *Self,
177 allocator: Allocator,
178 lit: u8,
179 writer: anytype,
180 ) !void {
181 try self.set(allocator, self.cursor, lit);
182 self.cursor += 1;
183 self.len += 1;
184
185 // Flush the circular buffer to the output
186 if (self.cursor == self.dict_size) {
187 try writer.writeAll(self.buf.items);
188 self.cursor = 0;
189 }
190 }
191
192 /// Fetch an LZ sequence (length, distance) from inside the buffer
193 pub fn appendLz(
194 self: *Self,
195 allocator: Allocator,
196 len: usize,
197 dist: usize,
198 writer: anytype,
199 ) !void {
200 if (dist > self.dict_size or dist > self.len) {
201 return error.CorruptInput;
202 }
203
204 var offset = (self.dict_size + self.cursor - dist) % self.dict_size;
205 var i: usize = 0;
206 while (i < len) : (i += 1) {
207 const x = self.get(offset);
208 try self.appendLiteral(allocator, x, writer);
209 offset += 1;
210 if (offset == self.dict_size) {
211 offset = 0;
212 }
213 }
214 }
215
216 pub fn finish(self: *Self, writer: anytype) !void {
217 if (self.cursor > 0) {
218 try writer.writeAll(self.buf.items[0..self.cursor]);
219 }
220 }
221
222 pub fn deinit(self: *Self, allocator: Allocator) void {
223 self.buf.deinit(allocator);
224 self.* = undefined;
225 }
226};
lib/std/compress/lzma/decode/lzma.zig created+398
...@@ -0,0 +1,398 @@
1const std = @import("../../../std.zig");
2const assert = std.debug.assert;
3const math = std.math;
4const Allocator = std.mem.Allocator;
5const ArrayListUnmanaged = std.ArrayListUnmanaged;
6const FixedBufferStream = std.io.FixedBufferStream;
7
8const LzCircularBuffer = @import("lzbuffer.zig").LzCircularBuffer;
9const Options = @import("../decode.zig").Options;
10const Vec2D = @import("../vec2d.zig").Vec2D;
11const rangecoder = @import("rangecoder.zig");
12const BitTree = rangecoder.BitTree;
13const LenDecoder = rangecoder.LenDecoder;
14const RangeDecoder = rangecoder.RangeDecoder;
15
16const ProcessingStatus = enum {
17 continue_,
18 finished,
19};
20
21pub const LzmaProperties = struct {
22 lc: u4,
23 lp: u3,
24 pb: u3,
25
26 fn validate(self: LzmaProperties) void {
27 assert(self.lc <= 8);
28 assert(self.lp <= 4);
29 assert(self.pb <= 4);
30 }
31};
32
33pub const LzmaParams = struct {
34 properties: LzmaProperties,
35 dict_size: u32,
36 unpacked_size: ?u64,
37
38 pub fn readHeader(reader: anytype, options: Options) !LzmaParams {
39 var props = try reader.readByte();
40 if (props >= 225) {
41 return error.CorruptInput;
42 }
43
44 const lc = @intCast(u4, props % 9);
45 props /= 9;
46 const lp = @intCast(u3, props % 5);
47 props /= 5;
48 const pb = @intCast(u3, props);
49
50 const dict_size_provided = try reader.readIntLittle(u32);
51 const dict_size = math.max(0x1000, dict_size_provided);
52
53 const unpacked_size = switch (options.unpacked_size) {
54 .read_from_header => blk: {
55 const unpacked_size_provided = try reader.readIntLittle(u64);
56 const marker_mandatory = unpacked_size_provided == 0xFFFF_FFFF_FFFF_FFFF;
57 break :blk if (marker_mandatory)
58 null
59 else
60 unpacked_size_provided;
61 },
62 .read_header_but_use_provided => |x| blk: {
63 _ = try reader.readIntLittle(u64);
64 break :blk x;
65 },
66 .use_provided => |x| x,
67 };
68
69 return LzmaParams{
70 .properties = LzmaProperties{ .lc = lc, .lp = lp, .pb = pb },
71 .dict_size = dict_size,
72 .unpacked_size = unpacked_size,
73 };
74 }
75};
76
77pub const DecoderState = struct {
78 lzma_props: LzmaProperties,
79 unpacked_size: ?u64,
80 literal_probs: Vec2D(u16),
81 pos_slot_decoder: [4]BitTree(6),
82 align_decoder: BitTree(4),
83 pos_decoders: [115]u16,
84 is_match: [192]u16,
85 is_rep: [12]u16,
86 is_rep_g0: [12]u16,
87 is_rep_g1: [12]u16,
88 is_rep_g2: [12]u16,
89 is_rep_0long: [192]u16,
90 state: usize,
91 rep: [4]usize,
92 len_decoder: LenDecoder,
93 rep_len_decoder: LenDecoder,
94
95 pub fn init(
96 allocator: Allocator,
97 lzma_props: LzmaProperties,
98 unpacked_size: ?u64,
99 ) !DecoderState {
100 return .{
101 .lzma_props = lzma_props,
102 .unpacked_size = unpacked_size,
103 .literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (lzma_props.lc + lzma_props.lp), 0x300 }),
104 .pos_slot_decoder = .{.{}} ** 4,
105 .align_decoder = .{},
106 .pos_decoders = .{0x400} ** 115,
107 .is_match = .{0x400} ** 192,
108 .is_rep = .{0x400} ** 12,
109 .is_rep_g0 = .{0x400} ** 12,
110 .is_rep_g1 = .{0x400} ** 12,
111 .is_rep_g2 = .{0x400} ** 12,
112 .is_rep_0long = .{0x400} ** 192,
113 .state = 0,
114 .rep = .{0} ** 4,
115 .len_decoder = .{},
116 .rep_len_decoder = .{},
117 };
118 }
119
120 pub fn deinit(self: *DecoderState, allocator: Allocator) void {
121 self.literal_probs.deinit(allocator);
122 self.* = undefined;
123 }
124
125 pub fn resetState(self: *DecoderState, allocator: Allocator, new_props: LzmaProperties) !void {
126 new_props.validate();
127 if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) {
128 self.literal_probs.fill(0x400);
129 } else {
130 self.literal_probs.deinit(allocator);
131 self.literal_probs = try Vec2D(u16).init(allocator, 0x400, .{ @as(usize, 1) << (new_props.lc + new_props.lp), 0x300 });
132 }
133
134 self.lzma_props = new_props;
135 for (self.pos_slot_decoder) |*t| t.reset();
136 self.align_decoder.reset();
137 self.pos_decoders = .{0x400} ** 115;
138 self.is_match = .{0x400} ** 192;
139 self.is_rep = .{0x400} ** 12;
140 self.is_rep_g0 = .{0x400} ** 12;
141 self.is_rep_g1 = .{0x400} ** 12;
142 self.is_rep_g2 = .{0x400} ** 12;
143 self.is_rep_0long = .{0x400} ** 192;
144 self.state = 0;
145 self.rep = .{0} ** 4;
146 self.len_decoder.reset();
147 self.rep_len_decoder.reset();
148 }
149
150 fn processNextInner(
151 self: *DecoderState,
152 allocator: Allocator,
153 reader: anytype,
154 writer: anytype,
155 buffer: anytype,
156 decoder: *RangeDecoder,
157 update: bool,
158 ) !ProcessingStatus {
159 const pos_state = buffer.len & ((@as(usize, 1) << self.lzma_props.pb) - 1);
160
161 if (!try decoder.decodeBit(
162 reader,
163 &self.is_match[(self.state << 4) + pos_state],
164 update,
165 )) {
166 const byte: u8 = try self.decodeLiteral(reader, buffer, decoder, update);
167
168 if (update) {
169 try buffer.appendLiteral(allocator, byte, writer);
170
171 self.state = if (self.state < 4)
172 0
173 else if (self.state < 10)
174 self.state - 3
175 else
176 self.state - 6;
177 }
178 return .continue_;
179 }
180
181 var len: usize = undefined;
182 if (try decoder.decodeBit(reader, &self.is_rep[self.state], update)) {
183 if (!try decoder.decodeBit(reader, &self.is_rep_g0[self.state], update)) {
184 if (!try decoder.decodeBit(
185 reader,
186 &self.is_rep_0long[(self.state << 4) + pos_state],
187 update,
188 )) {
189 if (update) {
190 self.state = if (self.state < 7) 9 else 11;
191 const dist = self.rep[0] + 1;
192 try buffer.appendLz(allocator, 1, dist, writer);
193 }
194 return .continue_;
195 }
196 } else {
197 const idx: usize = if (!try decoder.decodeBit(reader, &self.is_rep_g1[self.state], update))
198 1
199 else if (!try decoder.decodeBit(reader, &self.is_rep_g2[self.state], update))
200 2
201 else
202 3;
203 if (update) {
204 const dist = self.rep[idx];
205 var i = idx;
206 while (i > 0) : (i -= 1) {
207 self.rep[i] = self.rep[i - 1];
208 }
209 self.rep[0] = dist;
210 }
211 }
212
213 len = try self.rep_len_decoder.decode(reader, decoder, pos_state, update);
214
215 if (update) {
216 self.state = if (self.state < 7) 8 else 11;
217 }
218 } else {
219 if (update) {
220 self.rep[3] = self.rep[2];
221 self.rep[2] = self.rep[1];
222 self.rep[1] = self.rep[0];
223 }
224
225 len = try self.len_decoder.decode(reader, decoder, pos_state, update);
226
227 if (update) {
228 self.state = if (self.state < 7) 7 else 10;
229 }
230
231 const rep_0 = try self.decodeDistance(reader, decoder, len, update);
232
233 if (update) {
234 self.rep[0] = rep_0;
235 if (self.rep[0] == 0xFFFF_FFFF) {
236 if (decoder.isFinished()) {
237 return .finished;
238 }
239 return error.CorruptInput;
240 }
241 }
242 }
243
244 if (update) {
245 len += 2;
246
247 const dist = self.rep[0] + 1;
248 try buffer.appendLz(allocator, len, dist, writer);
249 }
250
251 return .continue_;
252 }
253
254 fn processNext(
255 self: *DecoderState,
256 allocator: Allocator,
257 reader: anytype,
258 writer: anytype,
259 buffer: anytype,
260 decoder: *RangeDecoder,
261 ) !ProcessingStatus {
262 return self.processNextInner(allocator, reader, writer, buffer, decoder, true);
263 }
264
265 pub fn process(
266 self: *DecoderState,
267 allocator: Allocator,
268 reader: anytype,
269 writer: anytype,
270 buffer: anytype,
271 decoder: *RangeDecoder,
272 ) !void {
273 while (true) {
274 if (self.unpacked_size) |unpacked_size| {
275 if (buffer.len >= unpacked_size) {
276 break;
277 }
278 } else if (decoder.isFinished()) {
279 break;
280 }
281
282 if (try self.processNext(allocator, reader, writer, buffer, decoder) == .finished) {
283 break;
284 }
285 }
286
287 if (self.unpacked_size) |len| {
288 if (len != buffer.len) {
289 return error.CorruptInput;
290 }
291 }
292 }
293
294 fn decodeLiteral(
295 self: *DecoderState,
296 reader: anytype,
297 buffer: anytype,
298 decoder: *RangeDecoder,
299 update: bool,
300 ) !u8 {
301 const def_prev_byte = 0;
302 const prev_byte = @as(usize, buffer.lastOr(def_prev_byte));
303
304 var result: usize = 1;
305 const lit_state = ((buffer.len & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) +
306 (prev_byte >> (8 - self.lzma_props.lc));
307 const probs = try self.literal_probs.getMut(lit_state);
308
309 if (self.state >= 7) {
310 var match_byte = @as(usize, try buffer.lastN(self.rep[0] + 1));
311
312 while (result < 0x100) {
313 const match_bit = (match_byte >> 7) & 1;
314 match_byte <<= 1;
315 const bit = @boolToInt(try decoder.decodeBit(
316 reader,
317 &probs[((@as(usize, 1) + match_bit) << 8) + result],
318 update,
319 ));
320 result = (result << 1) ^ bit;
321 if (match_bit != bit) {
322 break;
323 }
324 }
325 }
326
327 while (result < 0x100) {
328 result = (result << 1) ^ @boolToInt(try decoder.decodeBit(reader, &probs[result], update));
329 }
330
331 return @truncate(u8, result - 0x100);
332 }
333
334 fn decodeDistance(
335 self: *DecoderState,
336 reader: anytype,
337 decoder: *RangeDecoder,
338 length: usize,
339 update: bool,
340 ) !usize {
341 const len_state = if (length > 3) 3 else length;
342
343 const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(reader, decoder, update));
344 if (pos_slot < 4)
345 return pos_slot;
346
347 const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1);
348 var result = (2 ^ (pos_slot & 1)) << num_direct_bits;
349
350 if (pos_slot < 14) {
351 result += try decoder.parseReverseBitTree(
352 reader,
353 num_direct_bits,
354 &self.pos_decoders,
355 result - pos_slot,
356 update,
357 );
358 } else {
359 result += @as(usize, try decoder.get(reader, num_direct_bits - 4)) << 4;
360 result += try self.align_decoder.parseReverse(reader, decoder, update);
361 }
362
363 return result;
364 }
365};
366
367pub const LzmaDecoder = struct {
368 params: LzmaParams,
369 memlimit: usize,
370 state: DecoderState,
371
372 pub fn init(allocator: Allocator, params: LzmaParams, memlimit: ?usize) !LzmaDecoder {
373 return LzmaDecoder{
374 .params = params,
375 .memlimit = memlimit orelse math.maxInt(usize),
376 .state = try DecoderState.init(allocator, params.properties, params.unpacked_size),
377 };
378 }
379
380 pub fn deinit(self: *LzmaDecoder, allocator: Allocator) void {
381 self.state.deinit(allocator);
382 self.* = undefined;
383 }
384
385 pub fn decompress(
386 self: *LzmaDecoder,
387 allocator: Allocator,
388 reader: anytype,
389 writer: anytype,
390 ) !void {
391 var buffer = LzCircularBuffer.init(self.params.dict_size, self.memlimit);
392 defer buffer.deinit(allocator);
393
394 var decoder = try RangeDecoder.init(reader);
395 try self.state.process(allocator, reader, writer, &buffer, &decoder);
396 try buffer.finish(writer);
397 }
398};
lib/std/compress/lzma/decode/lzma2.zig created+169
...@@ -0,0 +1,169 @@
1const std = @import("../../../std.zig");
2const Allocator = std.mem.Allocator;
3
4const lzma = @import("lzma.zig");
5const DecoderState = lzma.DecoderState;
6const LzmaProperties = lzma.LzmaProperties;
7const LzAccumBuffer = @import("lzbuffer.zig").LzAccumBuffer;
8const RangeDecoder = @import("rangecoder.zig").RangeDecoder;
9
10pub const Lzma2Decoder = struct {
11 lzma_state: DecoderState,
12
13 pub fn init(allocator: Allocator) !Lzma2Decoder {
14 return Lzma2Decoder{
15 .lzma_state = try DecoderState.init(
16 allocator,
17 LzmaProperties{
18 .lc = 0,
19 .lp = 0,
20 .pb = 0,
21 },
22 null,
23 ),
24 };
25 }
26
27 pub fn deinit(self: *Lzma2Decoder, allocator: Allocator) void {
28 self.lzma_state.deinit(allocator);
29 self.* = undefined;
30 }
31
32 pub fn decompress(
33 self: *Lzma2Decoder,
34 allocator: Allocator,
35 reader: anytype,
36 writer: anytype,
37 ) !void {
38 var accum = LzAccumBuffer.init(std.math.maxInt(usize));
39 defer accum.deinit(allocator);
40
41 while (true) {
42 const status = try reader.readByte();
43
44 switch (status) {
45 0 => break,
46 1 => try parseUncompressed(allocator, reader, writer, &accum, true),
47 2 => try parseUncompressed(allocator, reader, writer, &accum, false),
48 else => try self.parseLzma(allocator, reader, writer, &accum, status),
49 }
50 }
51
52 try accum.finish(writer);
53 }
54
55 fn parseLzma(
56 self: *Lzma2Decoder,
57 allocator: Allocator,
58 reader: anytype,
59 writer: anytype,
60 accum: *LzAccumBuffer,
61 status: u8,
62 ) !void {
63 if (status & 0x80 == 0) {
64 return error.CorruptInput;
65 }
66
67 const Reset = struct {
68 dict: bool,
69 state: bool,
70 props: bool,
71 };
72
73 const reset = switch ((status >> 5) & 0x3) {
74 0 => Reset{
75 .dict = false,
76 .state = false,
77 .props = false,
78 },
79 1 => Reset{
80 .dict = false,
81 .state = true,
82 .props = false,
83 },
84 2 => Reset{
85 .dict = false,
86 .state = true,
87 .props = true,
88 },
89 3 => Reset{
90 .dict = true,
91 .state = true,
92 .props = true,
93 },
94 else => unreachable,
95 };
96
97 const unpacked_size = blk: {
98 var tmp: u64 = status & 0x1F;
99 tmp <<= 16;
100 tmp |= try reader.readIntBig(u16);
101 break :blk tmp + 1;
102 };
103
104 const packed_size = blk: {
105 const tmp: u17 = try reader.readIntBig(u16);
106 break :blk tmp + 1;
107 };
108
109 if (reset.dict) {
110 try accum.reset(writer);
111 }
112
113 if (reset.state) {
114 var new_props = self.lzma_state.lzma_props;
115
116 if (reset.props) {
117 var props = try reader.readByte();
118 if (props >= 225) {
119 return error.CorruptInput;
120 }
121
122 const lc = @intCast(u4, props % 9);
123 props /= 9;
124 const lp = @intCast(u3, props % 5);
125 props /= 5;
126 const pb = @intCast(u3, props);
127
128 if (lc + lp > 4) {
129 return error.CorruptInput;
130 }
131
132 new_props = LzmaProperties{ .lc = lc, .lp = lp, .pb = pb };
133 }
134
135 try self.lzma_state.resetState(allocator, new_props);
136 }
137
138 self.lzma_state.unpacked_size = unpacked_size + accum.len;
139
140 var counter = std.io.countingReader(reader);
141 const counter_reader = counter.reader();
142
143 var rangecoder = try RangeDecoder.init(counter_reader);
144 try self.lzma_state.process(allocator, counter_reader, writer, accum, &rangecoder);
145
146 if (counter.bytes_read != packed_size) {
147 return error.CorruptInput;
148 }
149 }
150
151 fn parseUncompressed(
152 allocator: Allocator,
153 reader: anytype,
154 writer: anytype,
155 accum: *LzAccumBuffer,
156 reset_dict: bool,
157 ) !void {
158 const unpacked_size = try reader.readIntBig(u16) + 1; // TODO: overflow
159
160 if (reset_dict) {
161 try accum.reset(writer);
162 }
163
164 var i: @TypeOf(unpacked_size) = 0;
165 while (i < unpacked_size) : (i += 1) {
166 try accum.appendByte(allocator, try reader.readByte());
167 }
168 }
169};
lib/std/compress/lzma/decode/rangecoder.zig created+184
...@@ -0,0 +1,184 @@
1const std = @import("../../../std.zig");
2const mem = std.mem;
3const Allocator = std.mem.Allocator;
4const ArrayListUnmanaged = std.ArrayListUnmanaged;
5const FixedBufferStream = std.io.FixedBufferStream;
6
7pub const RangeDecoder = struct {
8 range: u32,
9 code: u32,
10
11 pub fn init(reader: anytype) !RangeDecoder {
12 const reserved = try reader.readByte();
13 if (reserved != 0) {
14 return error.CorruptInput;
15 }
16 return RangeDecoder{
17 .range = 0xFFFF_FFFF,
18 .code = try reader.readIntBig(u32),
19 };
20 }
21
22 pub fn fromParts(
23 range: u32,
24 code: u32,
25 ) RangeDecoder {
26 return .{
27 .range = range,
28 .code = code,
29 };
30 }
31
32 pub fn set(self: *RangeDecoder, range: u32, code: u32) void {
33 self.range = range;
34 self.code = code;
35 }
36
37 pub inline fn isFinished(self: RangeDecoder) bool {
38 return self.code == 0;
39 }
40
41 inline fn normalize(self: *RangeDecoder, reader: anytype) !void {
42 if (self.range < 0x0100_0000) {
43 self.range <<= 8;
44 self.code = (self.code << 8) ^ @as(u32, try reader.readByte());
45 }
46 }
47
48 inline fn getBit(self: *RangeDecoder, reader: anytype) !bool {
49 self.range >>= 1;
50
51 const bit = self.code >= self.range;
52 if (bit)
53 self.code -= self.range;
54
55 try self.normalize(reader);
56 return bit;
57 }
58
59 pub fn get(self: *RangeDecoder, reader: anytype, count: usize) !u32 {
60 var result: u32 = 0;
61 var i: usize = 0;
62 while (i < count) : (i += 1)
63 result = (result << 1) ^ @boolToInt(try self.getBit(reader));
64 return result;
65 }
66
67 pub inline fn decodeBit(self: *RangeDecoder, reader: anytype, prob: *u16, update: bool) !bool {
68 const bound = (self.range >> 11) * prob.*;
69
70 if (self.code < bound) {
71 if (update)
72 prob.* += (0x800 - prob.*) >> 5;
73 self.range = bound;
74
75 try self.normalize(reader);
76 return false;
77 } else {
78 if (update)
79 prob.* -= prob.* >> 5;
80 self.code -= bound;
81 self.range -= bound;
82
83 try self.normalize(reader);
84 return true;
85 }
86 }
87
88 fn parseBitTree(
89 self: *RangeDecoder,
90 reader: anytype,
91 num_bits: u5,
92 probs: []u16,
93 update: bool,
94 ) !u32 {
95 var tmp: u32 = 1;
96 var i: @TypeOf(num_bits) = 0;
97 while (i < num_bits) : (i += 1) {
98 const bit = try self.decodeBit(reader, &probs[tmp], update);
99 tmp = (tmp << 1) ^ @boolToInt(bit);
100 }
101 return tmp - (@as(u32, 1) << num_bits);
102 }
103
104 pub fn parseReverseBitTree(
105 self: *RangeDecoder,
106 reader: anytype,
107 num_bits: u5,
108 probs: []u16,
109 offset: usize,
110 update: bool,
111 ) !u32 {
112 var result: u32 = 0;
113 var tmp: usize = 1;
114 var i: @TypeOf(num_bits) = 0;
115 while (i < num_bits) : (i += 1) {
116 const bit = @boolToInt(try self.decodeBit(reader, &probs[offset + tmp], update));
117 tmp = (tmp << 1) ^ bit;
118 result ^= @as(u32, bit) << i;
119 }
120 return result;
121 }
122};
123
124pub fn BitTree(comptime num_bits: usize) type {
125 return struct {
126 probs: [1 << num_bits]u16 = .{0x400} ** (1 << num_bits),
127
128 const Self = @This();
129
130 pub fn parse(
131 self: *Self,
132 reader: anytype,
133 decoder: *RangeDecoder,
134 update: bool,
135 ) !u32 {
136 return decoder.parseBitTree(reader, num_bits, &self.probs, update);
137 }
138
139 pub fn parseReverse(
140 self: *Self,
141 reader: anytype,
142 decoder: *RangeDecoder,
143 update: bool,
144 ) !u32 {
145 return decoder.parseReverseBitTree(reader, num_bits, &self.probs, 0, update);
146 }
147
148 pub fn reset(self: *Self) void {
149 mem.set(u16, &self.probs, 0x400);
150 }
151 };
152}
153
154pub const LenDecoder = struct {
155 choice: u16 = 0x400,
156 choice2: u16 = 0x400,
157 low_coder: [16]BitTree(3) = .{.{}} ** 16,
158 mid_coder: [16]BitTree(3) = .{.{}} ** 16,
159 high_coder: BitTree(8) = .{},
160
161 pub fn decode(
162 self: *LenDecoder,
163 reader: anytype,
164 decoder: *RangeDecoder,
165 pos_state: usize,
166 update: bool,
167 ) !usize {
168 if (!try decoder.decodeBit(reader, &self.choice, update)) {
169 return @as(usize, try self.low_coder[pos_state].parse(reader, decoder, update));
170 } else if (!try decoder.decodeBit(reader, &self.choice2, update)) {
171 return @as(usize, try self.mid_coder[pos_state].parse(reader, decoder, update)) + 8;
172 } else {
173 return @as(usize, try self.high_coder.parse(reader, decoder, update)) + 16;
174 }
175 }
176
177 pub fn reset(self: *LenDecoder) void {
178 self.choice = 0x400;
179 self.choice2 = 0x400;
180 for (self.low_coder) |*t| t.reset();
181 for (self.mid_coder) |*t| t.reset();
182 self.high_coder.reset();
183 }
184};
lib/std/compress/lzma/lzma2_test.zig created+27
...@@ -0,0 +1,27 @@
1const std = @import("../../std.zig");
2const lzma = @import("../lzma.zig");
3
4fn testDecompress(compressed: []const u8, writer: anytype) !void {
5 const allocator = std.testing.allocator;
6 var stream = std.io.fixedBufferStream(compressed);
7 try lzma.lzma2Decompress(allocator, stream.reader(), writer);
8}
9
10fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void {
11 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);
16}
17
18fn testDecompressError(expected: anyerror, compressed: []const u8) !void {
19 return std.testing.expectError(expected, testDecompress(compressed, std.io.null_writer));
20}
21
22test {
23 try testDecompressEqual(
24 "Hello\nWorld!\n",
25 &[_]u8{ 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00 },
26 );
27}
lib/std/compress/lzma/lzma_test.zig created+87
...@@ -0,0 +1,87 @@
1const std = @import("../../std.zig");
2const lzma = @import("../lzma.zig");
3
4fn testDecompress(compressed: []const u8, writer: anytype) !void {
5 const allocator = std.testing.allocator;
6 var stream = std.io.fixedBufferStream(compressed);
7 try lzma.lzmaDecompress(allocator, stream.reader(), writer, .{});
8}
9
10fn testDecompressEqual(expected: []const u8, compressed: []const u8) !void {
11 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);
16}
17
18fn testDecompressError(expected: anyerror, compressed: []const u8) !void {
19 return std.testing.expectError(expected, testDecompress(compressed, std.io.null_writer));
20}
21
22test "decompress empty world" {
23 try testDecompressEqual(
24 "",
25 &[_]u8{
26 0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x83, 0xff,
27 0xfb, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
28 },
29 );
30}
31
32test "decompress hello world" {
33 try testDecompressEqual(
34 "Hello world\n",
35 &[_]u8{
36 0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x19,
37 0x49, 0x98, 0x6f, 0x10, 0x19, 0xc6, 0xd7, 0x31, 0xeb, 0x36, 0x50, 0xb2, 0x98, 0x48, 0xff, 0xfe,
38 0xa5, 0xb0, 0x00,
39 },
40 );
41}
42
43test "decompress huge dict" {
44 try testDecompressEqual(
45 "Hello world\n",
46 &[_]u8{
47 0x5d, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x24, 0x19,
48 0x49, 0x98, 0x6f, 0x10, 0x19, 0xc6, 0xd7, 0x31, 0xeb, 0x36, 0x50, 0xb2, 0x98, 0x48, 0xff, 0xfe,
49 0xa5, 0xb0, 0x00,
50 },
51 );
52}
53
54test "unknown size with end of payload marker" {
55 try testDecompressEqual(
56 "Hello\nWorld!\n",
57 @embedFile("testdata/good-unknown_size-with_eopm.lzma"),
58 );
59}
60
61test "known size without end of payload marker" {
62 try testDecompressEqual(
63 "Hello\nWorld!\n",
64 @embedFile("testdata/good-known_size-without_eopm.lzma"),
65 );
66}
67
68test "known size with end of payload marker" {
69 try testDecompressEqual(
70 "Hello\nWorld!\n",
71 @embedFile("testdata/good-known_size-with_eopm.lzma"),
72 );
73}
74
75test "too big uncompressed size in header" {
76 try testDecompressError(
77 error.CorruptInput,
78 @embedFile("testdata/bad-too_big_size-with_eopm.lzma"),
79 );
80}
81
82test "too small uncompressed size in header" {
83 try testDecompressError(
84 error.CorruptInput,
85 @embedFile("testdata/bad-too_small_size-without_eopm-3.lzma"),
86 );
87}
lib/std/compress/lzma/testdata/bad-too_big_size-with_eopm.lzma created
Binary files /dev/null and b/lib/std/compress/lzma/testdata/bad-too_big_size-with_eopm.lzma differ
lib/std/compress/lzma/testdata/bad-too_small_size-without_eopm-3.lzma created
Binary files /dev/null and b/lib/std/compress/lzma/testdata/bad-too_small_size-without_eopm-3.lzma differ
lib/std/compress/lzma/testdata/good-known_size-with_eopm.lzma created
Binary files /dev/null and b/lib/std/compress/lzma/testdata/good-known_size-with_eopm.lzma differ
lib/std/compress/lzma/testdata/good-known_size-without_eopm.lzma created
Binary files /dev/null and b/lib/std/compress/lzma/testdata/good-known_size-without_eopm.lzma differ
lib/std/compress/lzma/testdata/good-unknown_size-with_eopm.lzma created
Binary files /dev/null and b/lib/std/compress/lzma/testdata/good-unknown_size-with_eopm.lzma differ
lib/std/compress/lzma/vec2d.zig created+128
...@@ -0,0 +1,128 @@
1const std = @import("../../std.zig");
2const math = std.math;
3const mem = std.mem;
4const Allocator = std.mem.Allocator;
5
6pub fn Vec2D(comptime T: type) type {
7 return struct {
8 data: []T,
9 cols: usize,
10
11 const Self = @This();
12
13 pub fn init(allocator: Allocator, value: T, size: struct { usize, usize }) !Self {
14 const len = try math.mul(usize, size[0], size[1]);
15 const data = try allocator.alloc(T, len);
16 mem.set(T, data, value);
17 return Self{
18 .data = data,
19 .cols = size[1],
20 };
21 }
22
23 pub fn deinit(self: *Self, allocator: Allocator) void {
24 allocator.free(self.data);
25 self.* = undefined;
26 }
27
28 pub fn fill(self: *Self, value: T) void {
29 mem.set(T, self.data, value);
30 }
31
32 inline fn _get(self: Self, row: usize) ![]T {
33 const start_row = try math.mul(usize, row, self.cols);
34 const end_row = try math.add(usize, start_row, self.cols);
35 return self.data[start_row..end_row];
36 }
37
38 pub fn get(self: Self, row: usize) ![]const T {
39 return self._get(row);
40 }
41
42 pub fn getMut(self: *Self, row: usize) ![]T {
43 return self._get(row);
44 }
45 };
46}
47
48const testing = std.testing;
49const expectEqualSlices = std.testing.expectEqualSlices;
50const expectError = std.testing.expectError;
51
52test "Vec2D.init" {
53 const allocator = testing.allocator;
54 var vec2d = try Vec2D(i32).init(allocator, 1, .{ 2, 3 });
55 defer vec2d.deinit(allocator);
56
57 try expectEqualSlices(i32, &.{ 1, 1, 1 }, try vec2d.get(0));
58 try expectEqualSlices(i32, &.{ 1, 1, 1 }, try vec2d.get(1));
59}
60
61test "Vec2D.init overflow" {
62 const allocator = testing.allocator;
63 try expectError(
64 error.Overflow,
65 Vec2D(i32).init(allocator, 1, .{ math.maxInt(usize), math.maxInt(usize) }),
66 );
67}
68
69test "Vec2D.fill" {
70 const allocator = testing.allocator;
71 var vec2d = try Vec2D(i32).init(allocator, 0, .{ 2, 3 });
72 defer vec2d.deinit(allocator);
73
74 vec2d.fill(7);
75
76 try expectEqualSlices(i32, &.{ 7, 7, 7 }, try vec2d.get(0));
77 try expectEqualSlices(i32, &.{ 7, 7, 7 }, try vec2d.get(1));
78}
79
80test "Vec2D.get" {
81 var data = [_]i32{ 0, 1, 2, 3, 4, 5, 6, 7 };
82 const vec2d = Vec2D(i32){
83 .data = &data,
84 .cols = 2,
85 };
86
87 try expectEqualSlices(i32, &.{ 0, 1 }, try vec2d.get(0));
88 try expectEqualSlices(i32, &.{ 2, 3 }, try vec2d.get(1));
89 try expectEqualSlices(i32, &.{ 4, 5 }, try vec2d.get(2));
90 try expectEqualSlices(i32, &.{ 6, 7 }, try vec2d.get(3));
91}
92
93test "Vec2D.getMut" {
94 var data = [_]i32{ 0, 1, 2, 3, 4, 5, 6, 7 };
95 var vec2d = Vec2D(i32){
96 .data = &data,
97 .cols = 2,
98 };
99
100 const row = try vec2d.getMut(1);
101 row[1] = 9;
102
103 try expectEqualSlices(i32, &.{ 0, 1 }, try vec2d.get(0));
104 // (1, 1) should be 9.
105 try expectEqualSlices(i32, &.{ 2, 9 }, try vec2d.get(1));
106 try expectEqualSlices(i32, &.{ 4, 5 }, try vec2d.get(2));
107 try expectEqualSlices(i32, &.{ 6, 7 }, try vec2d.get(3));
108}
109
110test "Vec2D.get multiplication overflow" {
111 const allocator = testing.allocator;
112 var matrix = try Vec2D(i32).init(allocator, 0, .{ 3, 4 });
113 defer matrix.deinit(allocator);
114
115 const row = (math.maxInt(usize) / 4) + 1;
116 try expectError(error.Overflow, matrix.get(row));
117 try expectError(error.Overflow, matrix.getMut(row));
118}
119
120test "Vec2D.get addition overflow" {
121 const allocator = testing.allocator;
122 var matrix = try Vec2D(i32).init(allocator, 0, .{ 3, 5 });
123 defer matrix.deinit(allocator);
124
125 const row = math.maxInt(usize) / 5;
126 try expectError(error.Overflow, matrix.get(row));
127 try expectError(error.Overflow, matrix.getMut(row));
128}
lib/std/compress/xz/block.zig+19-125
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("../../std.zig");1const std = @import("../../std.zig");
2const lzma = @import("lzma.zig");2const lzma = std.compress.lzma;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const ArrayListUnmanaged = std.ArrayListUnmanaged;
4const Crc32 = std.hash.Crc32;5const Crc32 = std.hash.Crc32;
5const Crc64 = std.hash.crc.Crc64Xz;6const Crc64 = std.hash.crc.Crc64Xz;
6const Sha256 = std.crypto.hash.sha2.Sha256;7const Sha256 = std.crypto.hash.sha2.Sha256;
...@@ -32,8 +33,7 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -32,8 +33,7 @@ pub fn Decoder(comptime ReaderType: type) type {
32 inner_reader: ReaderType,33 inner_reader: ReaderType,
33 check: xz.Check,34 check: xz.Check,
34 err: ?Error,35 err: ?Error,
35 accum: lzma.LzAccumBuffer,36 to_read: ArrayListUnmanaged(u8),
36 lzma_state: lzma.DecoderState,
37 block_count: usize,37 block_count: usize,
3838
39 fn init(allocator: Allocator, in_reader: ReaderType, check: xz.Check) !Self {39 fn init(allocator: Allocator, in_reader: ReaderType, check: xz.Check) !Self {
...@@ -42,15 +42,13 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -42,15 +42,13 @@ pub fn Decoder(comptime ReaderType: type) type {
42 .inner_reader = in_reader,42 .inner_reader = in_reader,
43 .check = check,43 .check = check,
44 .err = null,44 .err = null,
45 .accum = .{},45 .to_read = .{},
46 .lzma_state = try lzma.DecoderState.init(allocator),
47 .block_count = 0,46 .block_count = 0,
48 };47 };
49 }48 }
5049
51 pub fn deinit(self: *Self) void {50 pub fn deinit(self: *Self) void {
52 self.accum.deinit(self.allocator);51 self.to_read.deinit(self.allocator);
53 self.lzma_state.deinit(self.allocator);
54 }52 }
5553
56 pub fn reader(self: *Self) Reader {54 pub fn reader(self: *Self) Reader {
...@@ -59,9 +57,13 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -59,9 +57,13 @@ pub fn Decoder(comptime ReaderType: type) type {
5957
60 pub fn read(self: *Self, output: []u8) Error!usize {58 pub fn read(self: *Self, output: []u8) Error!usize {
61 while (true) {59 while (true) {
62 if (self.accum.to_read.items.len > 0) {60 if (self.to_read.items.len > 0) {
63 const n = self.accum.read(output);61 const input = self.to_read.items;
64 if (self.accum.to_read.items.len == 0 and self.err != null) {62 const n = std.math.min(input.len, output.len);
63 std.mem.copy(u8, output[0..n], input[0..n]);
64 std.mem.copy(u8, input, input[n..]);
65 self.to_read.shrinkRetainingCapacity(input.len - n);
66 if (self.to_read.items.len == 0 and self.err != null) {
65 if (self.err.? == DecodeError.EndOfStreamWithNoError) {67 if (self.err.? == DecodeError.EndOfStreamWithNoError) {
66 return n;68 return n;
67 }69 }
...@@ -77,15 +79,12 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -77,15 +79,12 @@ pub fn Decoder(comptime ReaderType: type) type {
77 }79 }
78 self.readBlock() catch |e| {80 self.readBlock() catch |e| {
79 self.err = e;81 self.err = e;
80 if (self.accum.to_read.items.len == 0) {
81 try self.accum.reset(self.allocator);
82 }
83 };82 };
84 }83 }
85 }84 }
8685
87 fn readBlock(self: *Self) Error!void {86 fn readBlock(self: *Self) Error!void {
88 const unpacked_pos = self.accum.to_read.items.len;87 const unpacked_pos = self.to_read.items.len;
8988
90 var block_counter = std.io.countingReader(self.inner_reader);89 var block_counter = std.io.countingReader(self.inner_reader);
91 const block_reader = block_counter.reader();90 const block_reader = block_counter.reader();
...@@ -156,15 +155,18 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -156,15 +155,18 @@ pub fn Decoder(comptime ReaderType: type) type {
156155
157 // Compressed Data156 // Compressed Data
158 var packed_counter = std.io.countingReader(block_reader);157 var packed_counter = std.io.countingReader(block_reader);
159 const packed_reader = packed_counter.reader();158 try lzma.lzma2Decompress(
160 while (try self.readLzma2Chunk(packed_reader)) {}159 self.allocator,
160 packed_counter.reader(),
161 self.to_read.writer(self.allocator),
162 );
161163
162 if (packed_size) |s| {164 if (packed_size) |s| {
163 if (s != packed_counter.bytes_read)165 if (s != packed_counter.bytes_read)
164 return error.CorruptInput;166 return error.CorruptInput;
165 }167 }
166168
167 const unpacked_bytes = self.accum.to_read.items[unpacked_pos..];169 const unpacked_bytes = self.to_read.items[unpacked_pos..];
168 if (unpacked_size) |s| {170 if (unpacked_size) |s| {
169 if (s != unpacked_bytes.len)171 if (s != unpacked_bytes.len)
170 return error.CorruptInput;172 return error.CorruptInput;
...@@ -205,113 +207,5 @@ pub fn Decoder(comptime ReaderType: type) type {...@@ -205,113 +207,5 @@ pub fn Decoder(comptime ReaderType: type) type {
205207
206 self.block_count += 1;208 self.block_count += 1;
207 }209 }
208
209 fn readLzma2Chunk(self: *Self, packed_reader: anytype) Error!bool {
210 const status = try packed_reader.readByte();
211 switch (status) {
212 0 => {
213 try self.accum.reset(self.allocator);
214 return false;
215 },
216 1, 2 => {
217 if (status == 1)
218 try self.accum.reset(self.allocator);
219
220 const size = try packed_reader.readIntBig(u16) + 1;
221 try self.accum.ensureUnusedCapacity(self.allocator, size);
222
223 var i: usize = 0;
224 while (i < size) : (i += 1)
225 self.accum.appendAssumeCapacity(try packed_reader.readByte());
226
227 return true;
228 },
229 else => {
230 if (status & 0x80 == 0)
231 return error.CorruptInput;
232
233 const Reset = struct {
234 dict: bool,
235 state: bool,
236 props: bool,
237 };
238
239 const reset = switch ((status >> 5) & 0x3) {
240 0 => Reset{
241 .dict = false,
242 .state = false,
243 .props = false,
244 },
245 1 => Reset{
246 .dict = false,
247 .state = true,
248 .props = false,
249 },
250 2 => Reset{
251 .dict = false,
252 .state = true,
253 .props = true,
254 },
255 3 => Reset{
256 .dict = true,
257 .state = true,
258 .props = true,
259 },
260 else => unreachable,
261 };
262
263 const unpacked_size = blk: {
264 var tmp: u64 = status & 0x1F;
265 tmp <<= 16;
266 tmp |= try packed_reader.readIntBig(u16);
267 break :blk tmp + 1;
268 };
269
270 const packed_size = blk: {
271 const tmp: u17 = try packed_reader.readIntBig(u16);
272 break :blk tmp + 1;
273 };
274
275 if (reset.dict)
276 try self.accum.reset(self.allocator);
277
278 if (reset.state) {
279 var new_props = self.lzma_state.lzma_props;
280
281 if (reset.props) {
282 var props = try packed_reader.readByte();
283 if (props >= 225)
284 return error.CorruptInput;
285
286 const lc = @intCast(u4, props % 9);
287 props /= 9;
288 const lp = @intCast(u3, props % 5);
289 props /= 5;
290 const pb = @intCast(u3, props);
291
292 if (lc + lp > 4)
293 return error.CorruptInput;
294
295 new_props = .{ .lc = lc, .lp = lp, .pb = pb };
296 }
297
298 try self.lzma_state.reset_state(self.allocator, new_props);
299 }
300
301 self.lzma_state.unpacked_size = unpacked_size + self.accum.len();
302
303 const buffer = try self.allocator.alloc(u8, packed_size);
304 defer self.allocator.free(buffer);
305
306 for (buffer) |*b|
307 b.* = try packed_reader.readByte();
308
309 var rangecoder = try lzma.RangeDecoder.init(buffer);
310 try self.lzma_state.process(self.allocator, &self.accum, &rangecoder);
311
312 return true;
313 },
314 }
315 }
316 };210 };
317}211}
lib/std/compress/xz/lzma.zig deleted-658
...@@ -1,658 +0,0 @@
1// Ported from https://github.com/gendx/lzma-rs
2
3const std = @import("../../std.zig");
4const assert = std.debug.assert;
5const Allocator = std.mem.Allocator;
6const ArrayListUnmanaged = std.ArrayListUnmanaged;
7
8const LzmaProperties = struct {
9 lc: u4,
10 lp: u3,
11 pb: u3,
12
13 fn validate(self: LzmaProperties) void {
14 assert(self.lc <= 8);
15 assert(self.lp <= 4);
16 assert(self.pb <= 4);
17 }
18};
19
20pub const DecoderState = struct {
21 lzma_props: LzmaProperties,
22 unpacked_size: ?u64,
23 literal_probs: Vec2D(u16),
24 pos_slot_decoder: [4]BitTree,
25 align_decoder: BitTree,
26 pos_decoders: [115]u16,
27 is_match: [192]u16,
28 is_rep: [12]u16,
29 is_rep_g0: [12]u16,
30 is_rep_g1: [12]u16,
31 is_rep_g2: [12]u16,
32 is_rep_0long: [192]u16,
33 state: usize,
34 rep: [4]usize,
35 len_decoder: LenDecoder,
36 rep_len_decoder: LenDecoder,
37
38 pub fn init(allocator: Allocator) !DecoderState {
39 return .{
40 .lzma_props = LzmaProperties{ .lc = 0, .lp = 0, .pb = 0 },
41 .unpacked_size = null,
42 .literal_probs = try Vec2D(u16).init(allocator, 0x400, 1, 0x300),
43 .pos_slot_decoder = .{
44 try BitTree.init(allocator, 6),
45 try BitTree.init(allocator, 6),
46 try BitTree.init(allocator, 6),
47 try BitTree.init(allocator, 6),
48 },
49 .align_decoder = try BitTree.init(allocator, 4),
50 .pos_decoders = .{0x400} ** 115,
51 .is_match = .{0x400} ** 192,
52 .is_rep = .{0x400} ** 12,
53 .is_rep_g0 = .{0x400} ** 12,
54 .is_rep_g1 = .{0x400} ** 12,
55 .is_rep_g2 = .{0x400} ** 12,
56 .is_rep_0long = .{0x400} ** 192,
57 .state = 0,
58 .rep = .{0} ** 4,
59 .len_decoder = try LenDecoder.init(allocator),
60 .rep_len_decoder = try LenDecoder.init(allocator),
61 };
62 }
63
64 pub fn deinit(self: *DecoderState, allocator: Allocator) void {
65 self.literal_probs.deinit(allocator);
66 for (self.pos_slot_decoder) |*t| t.deinit(allocator);
67 self.align_decoder.deinit(allocator);
68 self.len_decoder.deinit(allocator);
69 self.rep_len_decoder.deinit(allocator);
70 }
71
72 pub fn reset_state(self: *DecoderState, allocator: Allocator, new_props: LzmaProperties) !void {
73 new_props.validate();
74 if (self.lzma_props.lc + self.lzma_props.lp == new_props.lc + new_props.lp) {
75 self.literal_probs.fill(0x400);
76 } else {
77 self.literal_probs.deinit(allocator);
78 self.literal_probs = try Vec2D(u16).init(allocator, 0x400, @as(usize, 1) << (new_props.lc + new_props.lp), 0x300);
79 }
80
81 self.lzma_props = new_props;
82 for (self.pos_slot_decoder) |*t| t.reset();
83 self.align_decoder.reset();
84 self.pos_decoders = .{0x400} ** 115;
85 self.is_match = .{0x400} ** 192;
86 self.is_rep = .{0x400} ** 12;
87 self.is_rep_g0 = .{0x400} ** 12;
88 self.is_rep_g1 = .{0x400} ** 12;
89 self.is_rep_g2 = .{0x400} ** 12;
90 self.is_rep_0long = .{0x400} ** 192;
91 self.state = 0;
92 self.rep = .{0} ** 4;
93 self.len_decoder.reset();
94 self.rep_len_decoder.reset();
95 }
96
97 fn processNextInner(
98 self: *DecoderState,
99 allocator: Allocator,
100 output: *LzAccumBuffer,
101 rangecoder: *RangeDecoder,
102 update: bool,
103 ) !ProcessingStatus {
104 const pos_state = output.len() & ((@as(usize, 1) << self.lzma_props.pb) - 1);
105
106 if (!try rangecoder.decodeBit(
107 &self.is_match[(self.state << 4) + pos_state],
108 update,
109 )) {
110 const byte: u8 = try self.decodeLiteral(output, rangecoder, update);
111
112 if (update) {
113 try output.appendLiteral(allocator, byte);
114
115 self.state = if (self.state < 4)
116 0
117 else if (self.state < 10)
118 self.state - 3
119 else
120 self.state - 6;
121 }
122 return .continue_;
123 }
124
125 var len: usize = undefined;
126 if (try rangecoder.decodeBit(&self.is_rep[self.state], update)) {
127 if (!try rangecoder.decodeBit(&self.is_rep_g0[self.state], update)) {
128 if (!try rangecoder.decodeBit(
129 &self.is_rep_0long[(self.state << 4) + pos_state],
130 update,
131 )) {
132 if (update) {
133 self.state = if (self.state < 7) 9 else 11;
134 const dist = self.rep[0] + 1;
135 try output.appendLz(allocator, 1, dist);
136 }
137 return .continue_;
138 }
139 } else {
140 const idx: usize = if (!try rangecoder.decodeBit(&self.is_rep_g1[self.state], update))
141 1
142 else if (!try rangecoder.decodeBit(&self.is_rep_g2[self.state], update))
143 2
144 else
145 3;
146 if (update) {
147 const dist = self.rep[idx];
148 var i = idx;
149 while (i > 0) : (i -= 1) {
150 self.rep[i] = self.rep[i - 1];
151 }
152 self.rep[0] = dist;
153 }
154 }
155
156 len = try self.rep_len_decoder.decode(rangecoder, pos_state, update);
157
158 if (update) {
159 self.state = if (self.state < 7) 8 else 11;
160 }
161 } else {
162 if (update) {
163 self.rep[3] = self.rep[2];
164 self.rep[2] = self.rep[1];
165 self.rep[1] = self.rep[0];
166 }
167
168 len = try self.len_decoder.decode(rangecoder, pos_state, update);
169
170 if (update) {
171 self.state = if (self.state < 7) 7 else 10;
172 }
173
174 const rep_0 = try self.decodeDistance(rangecoder, len, update);
175
176 if (update) {
177 self.rep[0] = rep_0;
178 if (self.rep[0] == 0xFFFF_FFFF) {
179 if (rangecoder.isFinished()) {
180 return .finished;
181 }
182 return error.CorruptInput;
183 }
184 }
185 }
186
187 if (update) {
188 len += 2;
189
190 const dist = self.rep[0] + 1;
191 try output.appendLz(allocator, len, dist);
192 }
193
194 return .continue_;
195 }
196
197 fn processNext(
198 self: *DecoderState,
199 allocator: Allocator,
200 output: *LzAccumBuffer,
201 rangecoder: *RangeDecoder,
202 ) !ProcessingStatus {
203 return self.processNextInner(allocator, output, rangecoder, true);
204 }
205
206 pub fn process(
207 self: *DecoderState,
208 allocator: Allocator,
209 output: *LzAccumBuffer,
210 rangecoder: *RangeDecoder,
211 ) !void {
212 while (true) {
213 if (self.unpacked_size) |unpacked_size| {
214 if (output.len() >= unpacked_size) {
215 break;
216 }
217 } else if (rangecoder.isFinished()) {
218 break;
219 }
220
221 if (try self.processNext(allocator, output, rangecoder) == .finished) {
222 break;
223 }
224 }
225
226 if (self.unpacked_size) |len| {
227 if (len != output.len()) {
228 return error.CorruptInput;
229 }
230 }
231 }
232
233 fn decodeLiteral(
234 self: *DecoderState,
235 output: *LzAccumBuffer,
236 rangecoder: *RangeDecoder,
237 update: bool,
238 ) !u8 {
239 const def_prev_byte = 0;
240 const prev_byte = @as(usize, output.lastOr(def_prev_byte));
241
242 var result: usize = 1;
243 const lit_state = ((output.len() & ((@as(usize, 1) << self.lzma_props.lp) - 1)) << self.lzma_props.lc) +
244 (prev_byte >> (8 - self.lzma_props.lc));
245 const probs = try self.literal_probs.get(lit_state);
246
247 if (self.state >= 7) {
248 var match_byte = @as(usize, try output.lastN(self.rep[0] + 1));
249
250 while (result < 0x100) {
251 const match_bit = (match_byte >> 7) & 1;
252 match_byte <<= 1;
253 const bit = @boolToInt(try rangecoder.decodeBit(
254 &probs[((@as(usize, 1) + match_bit) << 8) + result],
255 update,
256 ));
257 result = (result << 1) ^ bit;
258 if (match_bit != bit) {
259 break;
260 }
261 }
262 }
263
264 while (result < 0x100) {
265 result = (result << 1) ^ @boolToInt(try rangecoder.decodeBit(&probs[result], update));
266 }
267
268 return @truncate(u8, result - 0x100);
269 }
270
271 fn decodeDistance(
272 self: *DecoderState,
273 rangecoder: *RangeDecoder,
274 length: usize,
275 update: bool,
276 ) !usize {
277 const len_state = if (length > 3) 3 else length;
278
279 const pos_slot = @as(usize, try self.pos_slot_decoder[len_state].parse(rangecoder, update));
280 if (pos_slot < 4)
281 return pos_slot;
282
283 const num_direct_bits = @intCast(u5, (pos_slot >> 1) - 1);
284 var result = (2 ^ (pos_slot & 1)) << num_direct_bits;
285
286 if (pos_slot < 14) {
287 result += try rangecoder.parseReverseBitTree(
288 num_direct_bits,
289 &self.pos_decoders,
290 result - pos_slot,
291 update,
292 );
293 } else {
294 result += @as(usize, try rangecoder.get(num_direct_bits - 4)) << 4;
295 result += try self.align_decoder.parseReverse(rangecoder, update);
296 }
297
298 return result;
299 }
300};
301
302const ProcessingStatus = enum {
303 continue_,
304 finished,
305};
306
307pub const LzAccumBuffer = struct {
308 to_read: ArrayListUnmanaged(u8) = .{},
309 buf: ArrayListUnmanaged(u8) = .{},
310
311 pub fn deinit(self: *LzAccumBuffer, allocator: Allocator) void {
312 self.to_read.deinit(allocator);
313 self.buf.deinit(allocator);
314 }
315
316 pub fn read(self: *LzAccumBuffer, output: []u8) usize {
317 const input = self.to_read.items;
318 const n = std.math.min(input.len, output.len);
319 std.mem.copy(u8, output[0..n], input[0..n]);
320 std.mem.copy(u8, input, input[n..]);
321 self.to_read.shrinkRetainingCapacity(input.len - n);
322 return n;
323 }
324
325 pub fn ensureUnusedCapacity(
326 self: *LzAccumBuffer,
327 allocator: Allocator,
328 additional_count: usize,
329 ) !void {
330 try self.buf.ensureUnusedCapacity(allocator, additional_count);
331 }
332
333 pub fn appendAssumeCapacity(self: *LzAccumBuffer, byte: u8) void {
334 self.buf.appendAssumeCapacity(byte);
335 }
336
337 pub fn reset(self: *LzAccumBuffer, allocator: Allocator) !void {
338 try self.to_read.appendSlice(allocator, self.buf.items);
339 self.buf.clearRetainingCapacity();
340 }
341
342 pub fn len(self: *const LzAccumBuffer) usize {
343 return self.buf.items.len;
344 }
345
346 pub fn lastOr(self: *const LzAccumBuffer, lit: u8) u8 {
347 const buf_len = self.buf.items.len;
348 return if (buf_len == 0)
349 lit
350 else
351 self.buf.items[buf_len - 1];
352 }
353
354 pub fn lastN(self: *const LzAccumBuffer, dist: usize) !u8 {
355 const buf_len = self.buf.items.len;
356 if (dist > buf_len) {
357 return error.CorruptInput;
358 }
359
360 return self.buf.items[buf_len - dist];
361 }
362
363 pub fn appendLiteral(self: *LzAccumBuffer, allocator: Allocator, lit: u8) !void {
364 try self.buf.append(allocator, lit);
365 }
366
367 pub fn appendLz(self: *LzAccumBuffer, allocator: Allocator, length: usize, dist: usize) !void {
368 const buf_len = self.buf.items.len;
369 if (dist > buf_len) {
370 return error.CorruptInput;
371 }
372
373 var offset = buf_len - dist;
374 var i: usize = 0;
375 while (i < length) : (i += 1) {
376 const x = self.buf.items[offset];
377 try self.buf.append(allocator, x);
378 offset += 1;
379 }
380 }
381};
382
383pub const RangeDecoder = struct {
384 stream: std.io.FixedBufferStream([]const u8),
385 range: u32,
386 code: u32,
387
388 pub fn init(buffer: []const u8) !RangeDecoder {
389 var dec = RangeDecoder{
390 .stream = std.io.fixedBufferStream(buffer),
391 .range = 0xFFFF_FFFF,
392 .code = 0,
393 };
394 const reader = dec.stream.reader();
395 _ = try reader.readByte();
396 dec.code = try reader.readIntBig(u32);
397 return dec;
398 }
399
400 pub fn fromParts(
401 buffer: []const u8,
402 range: u32,
403 code: u32,
404 ) RangeDecoder {
405 return .{
406 .stream = std.io.fixedBufferStream(buffer),
407 .range = range,
408 .code = code,
409 };
410 }
411
412 pub fn set(self: *RangeDecoder, range: u32, code: u32) void {
413 self.range = range;
414 self.code = code;
415 }
416
417 pub fn readInto(self: *RangeDecoder, dest: []u8) !usize {
418 return self.stream.read(dest);
419 }
420
421 pub inline fn isFinished(self: *const RangeDecoder) bool {
422 return self.code == 0 and self.isEof();
423 }
424
425 pub inline fn isEof(self: *const RangeDecoder) bool {
426 return self.stream.pos == self.stream.buffer.len;
427 }
428
429 inline fn normalize(self: *RangeDecoder) !void {
430 if (self.range < 0x0100_0000) {
431 self.range <<= 8;
432 self.code = (self.code << 8) ^ @as(u32, try self.stream.reader().readByte());
433 }
434 }
435
436 inline fn getBit(self: *RangeDecoder) !bool {
437 self.range >>= 1;
438
439 const bit = self.code >= self.range;
440 if (bit)
441 self.code -= self.range;
442
443 try self.normalize();
444 return bit;
445 }
446
447 fn get(self: *RangeDecoder, count: usize) !u32 {
448 var result: u32 = 0;
449 var i: usize = 0;
450 while (i < count) : (i += 1)
451 result = (result << 1) ^ @boolToInt(try self.getBit());
452 return result;
453 }
454
455 pub inline fn decodeBit(self: *RangeDecoder, prob: *u16, update: bool) !bool {
456 const bound = (self.range >> 11) * prob.*;
457
458 if (self.code < bound) {
459 if (update)
460 prob.* += (0x800 - prob.*) >> 5;
461 self.range = bound;
462
463 try self.normalize();
464 return false;
465 } else {
466 if (update)
467 prob.* -= prob.* >> 5;
468 self.code -= bound;
469 self.range -= bound;
470
471 try self.normalize();
472 return true;
473 }
474 }
475
476 fn parseBitTree(
477 self: *RangeDecoder,
478 num_bits: u5,
479 probs: []u16,
480 update: bool,
481 ) !u32 {
482 var tmp: u32 = 1;
483 var i: u5 = 0;
484 while (i < num_bits) : (i += 1) {
485 const bit = try self.decodeBit(&probs[tmp], update);
486 tmp = (tmp << 1) ^ @boolToInt(bit);
487 }
488 return tmp - (@as(u32, 1) << num_bits);
489 }
490
491 pub fn parseReverseBitTree(
492 self: *RangeDecoder,
493 num_bits: u5,
494 probs: []u16,
495 offset: usize,
496 update: bool,
497 ) !u32 {
498 var result: u32 = 0;
499 var tmp: usize = 1;
500 var i: u5 = 0;
501 while (i < num_bits) : (i += 1) {
502 const bit = @boolToInt(try self.decodeBit(&probs[offset + tmp], update));
503 tmp = (tmp << 1) ^ bit;
504 result ^= @as(u32, bit) << i;
505 }
506 return result;
507 }
508};
509
510fn Vec2D(comptime T: type) type {
511 return struct {
512 data: []T,
513 cols: usize,
514
515 const Self = @This();
516
517 pub fn init(allocator: Allocator, data: T, rows: usize, cols: usize) !Self {
518 const len = try std.math.mul(usize, rows, cols);
519 var vec2d = Self{
520 .data = try allocator.alloc(T, len),
521 .cols = cols,
522 };
523 vec2d.fill(data);
524 return vec2d;
525 }
526
527 pub fn deinit(self: *Self, allocator: Allocator) void {
528 allocator.free(self.data);
529 }
530
531 pub fn fill(self: *Self, value: T) void {
532 std.mem.set(T, self.data, value);
533 }
534
535 pub fn get(self: *Self, row: usize) ![]T {
536 const start_row = try std.math.mul(usize, row, self.cols);
537 return self.data[start_row .. start_row + self.cols];
538 }
539 };
540}
541
542const BitTree = struct {
543 num_bits: u5,
544 probs: ArrayListUnmanaged(u16),
545
546 pub fn init(allocator: Allocator, num_bits: u5) !BitTree {
547 var probs_len = @as(usize, 1) << num_bits;
548 var probs = try ArrayListUnmanaged(u16).initCapacity(allocator, probs_len);
549 while (probs_len > 0) : (probs_len -= 1)
550 probs.appendAssumeCapacity(0x400);
551 return .{ .num_bits = num_bits, .probs = probs };
552 }
553
554 pub fn deinit(self: *BitTree, allocator: Allocator) void {
555 self.probs.deinit(allocator);
556 }
557
558 pub fn parse(
559 self: *BitTree,
560 rangecoder: *RangeDecoder,
561 update: bool,
562 ) !u32 {
563 return rangecoder.parseBitTree(self.num_bits, self.probs.items, update);
564 }
565
566 pub fn parseReverse(
567 self: *BitTree,
568 rangecoder: *RangeDecoder,
569 update: bool,
570 ) !u32 {
571 return rangecoder.parseReverseBitTree(self.num_bits, self.probs.items, 0, update);
572 }
573
574 pub fn reset(self: *BitTree) void {
575 std.mem.set(u16, self.probs.items, 0x400);
576 }
577};
578
579const LenDecoder = struct {
580 choice: u16,
581 choice2: u16,
582 low_coder: [16]BitTree,
583 mid_coder: [16]BitTree,
584 high_coder: BitTree,
585
586 pub fn init(allocator: Allocator) !LenDecoder {
587 return .{
588 .choice = 0x400,
589 .choice2 = 0x400,
590 .low_coder = .{
591 try BitTree.init(allocator, 3),
592 try BitTree.init(allocator, 3),
593 try BitTree.init(allocator, 3),
594 try BitTree.init(allocator, 3),
595 try BitTree.init(allocator, 3),
596 try BitTree.init(allocator, 3),
597 try BitTree.init(allocator, 3),
598 try BitTree.init(allocator, 3),
599 try BitTree.init(allocator, 3),
600 try BitTree.init(allocator, 3),
601 try BitTree.init(allocator, 3),
602 try BitTree.init(allocator, 3),
603 try BitTree.init(allocator, 3),
604 try BitTree.init(allocator, 3),
605 try BitTree.init(allocator, 3),
606 try BitTree.init(allocator, 3),
607 },
608 .mid_coder = .{
609 try BitTree.init(allocator, 3),
610 try BitTree.init(allocator, 3),
611 try BitTree.init(allocator, 3),
612 try BitTree.init(allocator, 3),
613 try BitTree.init(allocator, 3),
614 try BitTree.init(allocator, 3),
615 try BitTree.init(allocator, 3),
616 try BitTree.init(allocator, 3),
617 try BitTree.init(allocator, 3),
618 try BitTree.init(allocator, 3),
619 try BitTree.init(allocator, 3),
620 try BitTree.init(allocator, 3),
621 try BitTree.init(allocator, 3),
622 try BitTree.init(allocator, 3),
623 try BitTree.init(allocator, 3),
624 try BitTree.init(allocator, 3),
625 },
626 .high_coder = try BitTree.init(allocator, 8),
627 };
628 }
629
630 pub fn deinit(self: *LenDecoder, allocator: Allocator) void {
631 for (self.low_coder) |*t| t.deinit(allocator);
632 for (self.mid_coder) |*t| t.deinit(allocator);
633 self.high_coder.deinit(allocator);
634 }
635
636 pub fn decode(
637 self: *LenDecoder,
638 rangecoder: *RangeDecoder,
639 pos_state: usize,
640 update: bool,
641 ) !usize {
642 if (!try rangecoder.decodeBit(&self.choice, update)) {
643 return @as(usize, try self.low_coder[pos_state].parse(rangecoder, update));
644 } else if (!try rangecoder.decodeBit(&self.choice2, update)) {
645 return @as(usize, try self.mid_coder[pos_state].parse(rangecoder, update)) + 8;
646 } else {
647 return @as(usize, try self.high_coder.parse(rangecoder, update)) + 16;
648 }
649 }
650
651 pub fn reset(self: *LenDecoder) void {
652 self.choice = 0x400;
653 self.choice2 = 0x400;
654 for (self.low_coder) |*t| t.reset();
655 for (self.mid_coder) |*t| t.reset();
656 self.high_coder.reset();
657 }
658};