From 06ce15e8f719756cc12d928cfdae12be99a9e4c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Mon, 23 Jan 2023 11:46:40 -0800 Subject: [PATCH] Add an xz decoder to the standard library --- build.zig | 2 + lib/std/compress/xz.zig | 5 + lib/std/compress/xz/block.zig | 319 +++++++++ lib/std/compress/xz/check.zig | 7 + lib/std/compress/xz/lzma.zig | 658 ++++++++++++++++++ lib/std/compress/xz/multibyte.zig | 23 + lib/std/compress/xz/stream.zig | 136 ++++ lib/std/compress/xz/stream_test.zig | 80 +++ lib/std/compress/xz/testdata/good-0-empty.xz | Bin 0 -> 32 bytes .../compress/xz/testdata/good-0cat-empty.xz | Bin 0 -> 64 bytes .../xz/testdata/good-0catpad-empty.xz | Bin 0 -> 68 bytes .../compress/xz/testdata/good-0pad-empty.xz | Bin 0 -> 36 bytes .../xz/testdata/good-1-3delta-lzma2.xz | Bin 0 -> 528 bytes .../xz/testdata/good-1-arm64-lzma2-1.xz | Bin 0 -> 512 bytes .../xz/testdata/good-1-arm64-lzma2-2.xz | Bin 0 -> 488 bytes .../xz/testdata/good-1-block_header-1.xz | Bin 0 -> 72 bytes .../xz/testdata/good-1-block_header-2.xz | Bin 0 -> 68 bytes .../xz/testdata/good-1-block_header-3.xz | Bin 0 -> 68 bytes .../xz/testdata/good-1-check-crc32.xz | Bin 0 -> 68 bytes .../xz/testdata/good-1-check-crc64.xz | Bin 0 -> 72 bytes .../compress/xz/testdata/good-1-check-none.xz | Bin 0 -> 64 bytes .../xz/testdata/good-1-check-sha256.xz | Bin 0 -> 96 bytes .../xz/testdata/good-1-delta-lzma2.tiff.xz | Bin 0 -> 51316 bytes .../xz/testdata/good-1-empty-bcj-lzma2.xz | Bin 0 -> 52 bytes .../compress/xz/testdata/good-1-lzma2-1.xz | Bin 0 -> 424 bytes .../compress/xz/testdata/good-1-lzma2-2.xz | Bin 0 -> 424 bytes .../compress/xz/testdata/good-1-lzma2-3.xz | Bin 0 -> 408 bytes .../compress/xz/testdata/good-1-lzma2-4.xz | Bin 0 -> 464 bytes .../compress/xz/testdata/good-1-lzma2-5.xz | Bin 0 -> 52 bytes .../xz/testdata/good-1-sparc-lzma2.xz | Bin 0 -> 612 bytes .../compress/xz/testdata/good-1-x86-lzma2.xz | Bin 0 -> 716 bytes lib/std/compress/xz/testdata/good-2-lzma2.xz | Bin 0 -> 92 bytes 32 files changed, 1230 insertions(+) create mode 100644 lib/std/compress/xz.zig create mode 100644 lib/std/compress/xz/block.zig create mode 100644 lib/std/compress/xz/check.zig create mode 100644 lib/std/compress/xz/lzma.zig create mode 100644 lib/std/compress/xz/multibyte.zig create mode 100644 lib/std/compress/xz/stream.zig create mode 100644 lib/std/compress/xz/stream_test.zig create mode 100644 lib/std/compress/xz/testdata/good-0-empty.xz create mode 100644 lib/std/compress/xz/testdata/good-0cat-empty.xz create mode 100644 lib/std/compress/xz/testdata/good-0catpad-empty.xz create mode 100644 lib/std/compress/xz/testdata/good-0pad-empty.xz create mode 100644 lib/std/compress/xz/testdata/good-1-3delta-lzma2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-arm64-lzma2-1.xz create mode 100644 lib/std/compress/xz/testdata/good-1-arm64-lzma2-2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-block_header-1.xz create mode 100644 lib/std/compress/xz/testdata/good-1-block_header-2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-block_header-3.xz create mode 100644 lib/std/compress/xz/testdata/good-1-check-crc32.xz create mode 100644 lib/std/compress/xz/testdata/good-1-check-crc64.xz create mode 100644 lib/std/compress/xz/testdata/good-1-check-none.xz create mode 100644 lib/std/compress/xz/testdata/good-1-check-sha256.xz create mode 100644 lib/std/compress/xz/testdata/good-1-delta-lzma2.tiff.xz create mode 100644 lib/std/compress/xz/testdata/good-1-empty-bcj-lzma2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-lzma2-1.xz create mode 100644 lib/std/compress/xz/testdata/good-1-lzma2-2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-lzma2-3.xz create mode 100644 lib/std/compress/xz/testdata/good-1-lzma2-4.xz create mode 100644 lib/std/compress/xz/testdata/good-1-lzma2-5.xz create mode 100644 lib/std/compress/xz/testdata/good-1-sparc-lzma2.xz create mode 100644 lib/std/compress/xz/testdata/good-1-x86-lzma2.xz create mode 100644 lib/std/compress/xz/testdata/good-2-lzma2.xz diff --git a/build.zig b/build.zig index 4161a6396e..3a7468243f 100644 --- a/build.zig +++ b/build.zig @@ -122,6 +122,8 @@ pub fn build(b: *Builder) !void { "compress-gettysburg.txt", "compress-pi.txt", "rfc1951.txt", + // exclude files from lib/std/compress/xz/testdata + ".xz", // exclude files from lib/std/tz/ ".tzif", // others diff --git a/lib/std/compress/xz.zig b/lib/std/compress/xz.zig new file mode 100644 index 0000000000..3af2d91cfb --- /dev/null +++ b/lib/std/compress/xz.zig @@ -0,0 +1,5 @@ +pub usingnamespace @import("xz/stream.zig"); + +test { + _ = @import("xz/stream.zig"); +} diff --git a/lib/std/compress/xz/block.zig b/lib/std/compress/xz/block.zig new file mode 100644 index 0000000000..27b2fc0b5f --- /dev/null +++ b/lib/std/compress/xz/block.zig @@ -0,0 +1,319 @@ +const std = @import("std"); +const check = @import("check.zig"); +const lzma = @import("lzma.zig"); +const multibyte = @import("multibyte.zig"); +const Allocator = std.mem.Allocator; +const Crc32 = std.hash.Crc32; +const Crc64 = std.hash.crc.Crc64Xz; +const Sha256 = std.crypto.hash.sha2.Sha256; + +const DecodeError = error{ + CorruptInput, + EndOfStream, + EndOfStreamWithNoError, + WrongChecksum, + Unsupported, + Overflow, +}; + +pub fn decoder(allocator: Allocator, reader: anytype, check_kind: check.Kind) !Decoder(@TypeOf(reader)) { + return Decoder(@TypeOf(reader)).init(allocator, reader, check_kind); +} + +pub fn Decoder(comptime ReaderType: type) type { + return struct { + const Self = @This(); + pub const Error = + ReaderType.Error || + DecodeError || + Allocator.Error; + pub const Reader = std.io.Reader(*Self, Error, read); + + allocator: Allocator, + inner_reader: ReaderType, + check_kind: check.Kind, + err: ?Error, + accum: lzma.LzAccumBuffer, + lzma_state: lzma.DecoderState, + block_count: usize, + + fn init(allocator: Allocator, in_reader: ReaderType, check_kind: check.Kind) !Self { + return Self{ + .allocator = allocator, + .inner_reader = in_reader, + .check_kind = check_kind, + .err = null, + .accum = .{}, + .lzma_state = try lzma.DecoderState.init(allocator), + .block_count = 0, + }; + } + + pub fn deinit(self: *Self) void { + self.accum.deinit(self.allocator); + self.lzma_state.deinit(self.allocator); + } + + pub fn reader(self: *Self) Reader { + return .{ .context = self }; + } + + pub fn read(self: *Self, output: []u8) Error!usize { + while (true) { + if (self.accum.to_read.items.len > 0) { + const n = self.accum.read(output); + if (self.accum.to_read.items.len == 0 and self.err != null) { + if (self.err.? == DecodeError.EndOfStreamWithNoError) { + return n; + } + return self.err.?; + } + return n; + } + if (self.err != null) { + if (self.err.? == DecodeError.EndOfStreamWithNoError) { + return 0; + } + return self.err.?; + } + self.readBlock() catch |e| { + self.err = e; + if (self.accum.to_read.items.len == 0) { + try self.accum.reset(self.allocator); + } + }; + } + } + + fn readBlock(self: *Self) Error!void { + const unpacked_pos = self.accum.to_read.items.len; + + var block_counter = std.io.countingReader(self.inner_reader); + const block_reader = block_counter.reader(); + + var packed_size: ?u64 = null; + var unpacked_size: ?u64 = null; + + // Block Header + { + var header_hasher = std.compress.hashedReader(block_reader, Crc32.init()); + const header_reader = header_hasher.reader(); + + const header_size = try header_reader.readByte() * 4; + if (header_size == 0) + return error.EndOfStreamWithNoError; + + const Flags = packed struct(u8) { + last_filter_index: u2, + reserved: u4, + has_packed_size: bool, + has_unpacked_size: bool, + }; + + const flags = try header_reader.readStruct(Flags); + const filter_count = @as(u3, flags.last_filter_index) + 1; + if (filter_count > 1) + return error.Unsupported; + + if (flags.has_packed_size) + packed_size = try multibyte.readInt(header_reader); + + if (flags.has_unpacked_size) + unpacked_size = try multibyte.readInt(header_reader); + + const FilterId = enum(u64) { + lzma2 = 0x21, + _, + }; + + const filter_id = @intToEnum( + FilterId, + try multibyte.readInt(header_reader), + ); + + if (@enumToInt(filter_id) >= 0x4000_0000_0000_0000) + return error.CorruptInput; + + if (filter_id != .lzma2) + return error.Unsupported; + + const properties_size = try multibyte.readInt(header_reader); + if (properties_size != 1) + return error.CorruptInput; + + // TODO: use filter properties + _ = try header_reader.readByte(); + + while (block_counter.bytes_read != header_size) { + if (try header_reader.readByte() != 0) + return error.CorruptInput; + } + + const hash_a = header_hasher.hasher.final(); + const hash_b = try header_reader.readIntLittle(u32); + if (hash_a != hash_b) + return error.WrongChecksum; + } + + // Compressed Data + var packed_counter = std.io.countingReader(block_reader); + const packed_reader = packed_counter.reader(); + while (try self.readLzma2Chunk(packed_reader)) {} + + if (packed_size) |s| { + if (s != packed_counter.bytes_read) + return error.CorruptInput; + } + + const unpacked_bytes = self.accum.to_read.items[unpacked_pos..]; + if (unpacked_size) |s| { + if (s != unpacked_bytes.len) + return error.CorruptInput; + } + + // Block Padding + while (block_counter.bytes_read % 4 != 0) { + if (try block_reader.readByte() != 0) + return error.CorruptInput; + } + + // Check + switch (self.check_kind) { + .none => {}, + .crc32 => { + const hash_a = Crc32.hash(unpacked_bytes); + const hash_b = try self.inner_reader.readIntLittle(u32); + if (hash_a != hash_b) + return error.WrongChecksum; + }, + .crc64 => { + const hash_a = Crc64.hash(unpacked_bytes); + const hash_b = try self.inner_reader.readIntLittle(u64); + if (hash_a != hash_b) + return error.WrongChecksum; + }, + .sha256 => { + var hash_a: [Sha256.digest_length]u8 = undefined; + Sha256.hash(unpacked_bytes, &hash_a, .{}); + + var hash_b: [Sha256.digest_length]u8 = undefined; + try self.inner_reader.readNoEof(&hash_b); + + if (!std.mem.eql(u8, &hash_a, &hash_b)) + return error.WrongChecksum; + }, + else => return error.Unsupported, + } + + self.block_count += 1; + } + + fn readLzma2Chunk(self: *Self, packed_reader: anytype) Error!bool { + const status = try packed_reader.readByte(); + switch (status) { + 0 => { + try self.accum.reset(self.allocator); + return false; + }, + 1, 2 => { + if (status == 1) + try self.accum.reset(self.allocator); + + const size = try packed_reader.readIntBig(u16) + 1; + try self.accum.ensureUnusedCapacity(self.allocator, size); + + var i: usize = 0; + while (i < size) : (i += 1) + self.accum.appendAssumeCapacity(try packed_reader.readByte()); + + return true; + }, + else => { + if (status & 0x80 == 0) + return error.CorruptInput; + + const Reset = struct { + dict: bool, + state: bool, + props: bool, + }; + + const reset = switch ((status >> 5) & 0x3) { + 0 => Reset{ + .dict = false, + .state = false, + .props = false, + }, + 1 => Reset{ + .dict = false, + .state = true, + .props = false, + }, + 2 => Reset{ + .dict = false, + .state = true, + .props = true, + }, + 3 => Reset{ + .dict = true, + .state = true, + .props = true, + }, + else => unreachable, + }; + + const unpacked_size = blk: { + var tmp: u64 = status & 0x1F; + tmp <<= 16; + tmp |= try packed_reader.readIntBig(u16); + break :blk tmp + 1; + }; + + const packed_size = blk: { + var tmp: u64 = try packed_reader.readIntBig(u16); + break :blk tmp + 1; + }; + + if (reset.dict) + try self.accum.reset(self.allocator); + + if (reset.state) { + var new_props = self.lzma_state.lzma_props; + + if (reset.props) { + var props = try packed_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); + + if (lc + lp > 4) + return error.CorruptInput; + + new_props = .{ .lc = lc, .lp = lp, .pb = pb }; + } + + try self.lzma_state.reset_state(self.allocator, new_props); + } + + self.lzma_state.unpacked_size = unpacked_size + self.accum.len(); + + const buffer = try self.allocator.alloc(u8, packed_size); + defer self.allocator.free(buffer); + + for (buffer) |*b| + b.* = try packed_reader.readByte(); + + var rangecoder = try lzma.RangeDecoder.init(buffer); + try self.lzma_state.process(self.allocator, &self.accum, &rangecoder); + + return true; + }, + } + } + }; +} diff --git a/lib/std/compress/xz/check.zig b/lib/std/compress/xz/check.zig new file mode 100644 index 0000000000..20151ad4cf --- /dev/null +++ b/lib/std/compress/xz/check.zig @@ -0,0 +1,7 @@ +pub const Kind = enum(u4) { + none = 0x00, + crc32 = 0x01, + crc64 = 0x04, + sha256 = 0x0A, + _, +}; diff --git a/lib/std/compress/xz/lzma.zig b/lib/std/compress/xz/lzma.zig new file mode 100644 index 0000000000..ead707e0be --- /dev/null +++ b/lib/std/compress/xz/lzma.zig @@ -0,0 +1,658 @@ +// Ported from https://github.com/gendx/lzma-rs + +const std = @import("std"); +const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const ArrayListUnmanaged = std.ArrayListUnmanaged; + +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 DecoderState = struct { + lzma_props: LzmaProperties, + unpacked_size: ?u64, + literal_probs: Vec2D(u16), + pos_slot_decoder: [4]BitTree, + align_decoder: BitTree, + 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) !DecoderState { + return .{ + .lzma_props = LzmaProperties{ .lc = 0, .lp = 0, .pb = 0 }, + .unpacked_size = null, + .literal_probs = try Vec2D(u16).init(allocator, 0x400, 1, 0x300), + .pos_slot_decoder = .{ + try BitTree.init(allocator, 6), + try BitTree.init(allocator, 6), + try BitTree.init(allocator, 6), + try BitTree.init(allocator, 6), + }, + .align_decoder = try BitTree.init(allocator, 4), + .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 = try LenDecoder.init(allocator), + .rep_len_decoder = try LenDecoder.init(allocator), + }; + } + + pub fn deinit(self: *DecoderState, allocator: Allocator) void { + self.literal_probs.deinit(allocator); + for (self.pos_slot_decoder) |*t| t.deinit(allocator); + self.align_decoder.deinit(allocator); + self.len_decoder.deinit(allocator); + self.rep_len_decoder.deinit(allocator); + } + + pub fn reset_state(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, + output: *LzAccumBuffer, + rangecoder: *RangeDecoder, + update: bool, + ) !ProcessingStatus { + const pos_state = output.len() & ((@as(usize, 1) << self.lzma_props.pb) - 1); + + if (!try rangecoder.decodeBit( + &self.is_match[(self.state << 4) + pos_state], + update, + )) { + const byte: u8 = try self.decodeLiteral(output, rangecoder, update); + + if (update) { + try output.appendLiteral(allocator, byte); + + 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 rangecoder.decodeBit(&self.is_rep[self.state], update)) { + if (!try rangecoder.decodeBit(&self.is_rep_g0[self.state], update)) { + if (!try rangecoder.decodeBit( + &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 output.appendLz(allocator, 1, dist); + } + return .continue_; + } + } else { + const idx: usize = if (!try rangecoder.decodeBit(&self.is_rep_g1[self.state], update)) + 1 + else if (!try rangecoder.decodeBit(&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(rangecoder, 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(rangecoder, pos_state, update); + + if (update) { + self.state = if (self.state < 7) 7 else 10; + } + + const rep_0 = try self.decodeDistance(rangecoder, len, update); + + if (update) { + self.rep[0] = rep_0; + if (self.rep[0] == 0xFFFF_FFFF) { + if (rangecoder.isFinished()) { + return .finished; + } + return error.CorruptInput; + } + } + } + + if (update) { + len += 2; + + const dist = self.rep[0] + 1; + try output.appendLz(allocator, len, dist); + } + + return .continue_; + } + + fn processNext( + self: *DecoderState, + allocator: Allocator, + output: *LzAccumBuffer, + rangecoder: *RangeDecoder, + ) !ProcessingStatus { + return self.processNextInner(allocator, output, rangecoder, true); + } + + pub fn process( + self: *DecoderState, + allocator: Allocator, + output: *LzAccumBuffer, + rangecoder: *RangeDecoder, + ) !void { + while (true) { + if (self.unpacked_size) |unpacked_size| { + if (output.len() >= unpacked_size) { + break; + } + } else if (rangecoder.isFinished()) { + break; + } + + if (try self.processNext(allocator, output, rangecoder) == .finished) { + break; + } + } + + if (self.unpacked_size) |len| { + if (len != output.len()) { + return error.CorruptInput; + } + } + } + + fn decodeLiteral( + self: *DecoderState, + output: *LzAccumBuffer, + rangecoder: *RangeDecoder, + update: bool, + ) !u8 { + const def_prev_byte = 0; + const prev_byte = @as(usize, output.lastOr(def_prev_byte)); + + var result: usize = 1; + const lit_state = ((output.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.get(lit_state); + + if (self.state >= 7) { + var match_byte = @as(usize, try output.lastN(self.rep[0] + 1)); + + while (result < 0x100) { + const match_bit = (match_byte >> 7) & 1; + match_byte <<= 1; + const bit = @boolToInt(try rangecoder.decodeBit( + &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 rangecoder.decodeBit(&probs[result], update)); + } + + return @truncate(u8, result - 0x100); + } + + fn decodeDistance( + self: *DecoderState, + rangecoder: *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(rangecoder, 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 rangecoder.parseReverseBitTree( + num_direct_bits, + &self.pos_decoders, + result - pos_slot, + update, + ); + } else { + result += @as(usize, try rangecoder.get(num_direct_bits - 4)) << 4; + result += try self.align_decoder.parseReverse(rangecoder, update); + } + + return result; + } +}; + +const ProcessingStatus = enum { + continue_, + finished, +}; + +pub const LzAccumBuffer = struct { + to_read: ArrayListUnmanaged(u8) = .{}, + buf: ArrayListUnmanaged(u8) = .{}, + + pub fn deinit(self: *LzAccumBuffer, allocator: Allocator) void { + self.to_read.deinit(allocator); + self.buf.deinit(allocator); + } + + pub fn read(self: *LzAccumBuffer, output: []u8) usize { + const input = self.to_read.items; + const n = std.math.min(input.len, output.len); + std.mem.copy(u8, output[0..n], input[0..n]); + std.mem.copy(u8, input, input[n..]); + self.to_read.shrinkRetainingCapacity(input.len - n); + return n; + } + + pub fn ensureUnusedCapacity( + self: *LzAccumBuffer, + allocator: Allocator, + additional_count: usize, + ) !void { + try self.buf.ensureUnusedCapacity(allocator, additional_count); + } + + pub fn appendAssumeCapacity(self: *LzAccumBuffer, byte: u8) void { + self.buf.appendAssumeCapacity(byte); + } + + pub fn reset(self: *LzAccumBuffer, allocator: Allocator) !void { + try self.to_read.appendSlice(allocator, self.buf.items); + self.buf.clearRetainingCapacity(); + } + + pub fn len(self: *const LzAccumBuffer) usize { + return self.buf.items.len; + } + + pub fn lastOr(self: *const LzAccumBuffer, lit: u8) u8 { + const buf_len = self.buf.items.len; + return if (buf_len == 0) + lit + else + self.buf.items[buf_len - 1]; + } + + pub fn lastN(self: *const LzAccumBuffer, dist: usize) !u8 { + const buf_len = self.buf.items.len; + if (dist > buf_len) { + return error.CorruptInput; + } + + return self.buf.items[buf_len - dist]; + } + + pub fn appendLiteral(self: *LzAccumBuffer, allocator: Allocator, lit: u8) !void { + try self.buf.append(allocator, lit); + } + + pub fn appendLz(self: *LzAccumBuffer, allocator: Allocator, length: usize, dist: usize) !void { + const buf_len = self.buf.items.len; + if (dist > buf_len) { + return error.CorruptInput; + } + + var offset = buf_len - dist; + var i: usize = 0; + while (i < length) : (i += 1) { + const x = self.buf.items[offset]; + try self.buf.append(allocator, x); + offset += 1; + } + } +}; + +pub const RangeDecoder = struct { + stream: std.io.FixedBufferStream([]const u8), + range: u32, + code: u32, + + pub fn init(buffer: []const u8) !RangeDecoder { + var dec = RangeDecoder{ + .stream = std.io.fixedBufferStream(buffer), + .range = 0xFFFF_FFFF, + .code = 0, + }; + const reader = dec.stream.reader(); + _ = try reader.readByte(); + dec.code = try reader.readIntBig(u32); + return dec; + } + + pub fn fromParts( + buffer: []const u8, + range: u32, + code: u32, + ) RangeDecoder { + return .{ + .stream = std.io.fixedBufferStream(buffer), + .range = range, + .code = code, + }; + } + + pub fn set(self: *RangeDecoder, range: u32, code: u32) void { + self.range = range; + self.code = code; + } + + pub fn readInto(self: *RangeDecoder, dest: []u8) !usize { + return self.stream.read(dest); + } + + pub inline fn isFinished(self: *const RangeDecoder) bool { + return self.code == 0 and self.isEof(); + } + + pub inline fn isEof(self: *const RangeDecoder) bool { + return self.stream.pos == self.stream.buffer.len; + } + + inline fn normalize(self: *RangeDecoder) !void { + if (self.range < 0x0100_0000) { + self.range <<= 8; + self.code = (self.code << 8) ^ @as(u32, try self.stream.reader().readByte()); + } + } + + inline fn getBit(self: *RangeDecoder) !bool { + self.range >>= 1; + + const bit = self.code >= self.range; + if (bit) + self.code -= self.range; + + try self.normalize(); + return bit; + } + + fn get(self: *RangeDecoder, count: usize) !u32 { + var result: u32 = 0; + var i: usize = 0; + while (i < count) : (i += 1) + result = (result << 1) ^ @boolToInt(try self.getBit()); + return result; + } + + pub inline fn decodeBit(self: *RangeDecoder, prob: *u16, update: bool) !bool { + const bound = (self.range >> 11) * prob.*; + + if (self.code < bound) { + if (update) + prob.* += (0x800 - prob.*) >> 5; + self.range = bound; + + try self.normalize(); + return false; + } else { + if (update) + prob.* -= prob.* >> 5; + self.code -= bound; + self.range -= bound; + + try self.normalize(); + return true; + } + } + + fn parseBitTree( + self: *RangeDecoder, + num_bits: u5, + probs: []u16, + update: bool, + ) !u32 { + var tmp: u32 = 1; + var i: u5 = 0; + while (i < num_bits) : (i += 1) { + const bit = try self.decodeBit(&probs[tmp], update); + tmp = (tmp << 1) ^ @boolToInt(bit); + } + return tmp - (@as(u32, 1) << num_bits); + } + + pub fn parseReverseBitTree( + self: *RangeDecoder, + num_bits: u5, + probs: []u16, + offset: usize, + update: bool, + ) !u32 { + var result: u32 = 0; + var tmp: usize = 1; + var i: u5 = 0; + while (i < num_bits) : (i += 1) { + const bit = @boolToInt(try self.decodeBit(&probs[offset + tmp], update)); + tmp = (tmp << 1) ^ bit; + result ^= @as(u32, bit) << i; + } + return result; + } +}; + +fn Vec2D(comptime T: type) type { + return struct { + data: []T, + cols: usize, + + const Self = @This(); + + pub fn init(allocator: Allocator, data: T, rows: usize, cols: usize) !Self { + const len = try std.math.mul(usize, rows, cols); + var vec2d = Self{ + .data = try allocator.alloc(T, len), + .cols = cols, + }; + vec2d.fill(data); + return vec2d; + } + + pub fn deinit(self: *Self, allocator: Allocator) void { + allocator.free(self.data); + } + + pub fn fill(self: *Self, value: T) void { + std.mem.set(T, self.data, value); + } + + pub fn get(self: *Self, row: usize) ![]T { + const start_row = try std.math.mul(usize, row, self.cols); + return self.data[start_row .. start_row + self.cols]; + } + }; +} + +const BitTree = struct { + num_bits: u5, + probs: ArrayListUnmanaged(u16), + + pub fn init(allocator: Allocator, num_bits: u5) !BitTree { + var probs_len = @as(usize, 1) << num_bits; + var probs = try ArrayListUnmanaged(u16).initCapacity(allocator, probs_len); + while (probs_len > 0) : (probs_len -= 1) + probs.appendAssumeCapacity(0x400); + return .{ .num_bits = num_bits, .probs = probs }; + } + + pub fn deinit(self: *BitTree, allocator: Allocator) void { + self.probs.deinit(allocator); + } + + pub fn parse( + self: *BitTree, + rangecoder: *RangeDecoder, + update: bool, + ) !u32 { + return rangecoder.parseBitTree(self.num_bits, self.probs.items, update); + } + + pub fn parseReverse( + self: *BitTree, + rangecoder: *RangeDecoder, + update: bool, + ) !u32 { + return rangecoder.parseReverseBitTree(self.num_bits, self.probs.items, 0, update); + } + + pub fn reset(self: *BitTree) void { + std.mem.set(u16, self.probs.items, 0x400); + } +}; + +const LenDecoder = struct { + choice: u16, + choice2: u16, + low_coder: [16]BitTree, + mid_coder: [16]BitTree, + high_coder: BitTree, + + pub fn init(allocator: Allocator) !LenDecoder { + return .{ + .choice = 0x400, + .choice2 = 0x400, + .low_coder = .{ + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + }, + .mid_coder = .{ + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + try BitTree.init(allocator, 3), + }, + .high_coder = try BitTree.init(allocator, 8), + }; + } + + pub fn deinit(self: *LenDecoder, allocator: Allocator) void { + for (self.low_coder) |*t| t.deinit(allocator); + for (self.mid_coder) |*t| t.deinit(allocator); + self.high_coder.deinit(allocator); + } + + pub fn decode( + self: *LenDecoder, + rangecoder: *RangeDecoder, + pos_state: usize, + update: bool, + ) !usize { + if (!try rangecoder.decodeBit(&self.choice, update)) { + return @as(usize, try self.low_coder[pos_state].parse(rangecoder, update)); + } else if (!try rangecoder.decodeBit(&self.choice2, update)) { + return @as(usize, try self.mid_coder[pos_state].parse(rangecoder, update)) + 8; + } else { + return @as(usize, try self.high_coder.parse(rangecoder, update)) + 16; + } + } + + pub fn reset(self: *LenDecoder) void { + self.choice = 0x400; + self.choice2 = 0x400; + for (self.low_coder) |*t| t.reset(); + for (self.mid_coder) |*t| t.reset(); + self.high_coder.reset(); + } +}; diff --git a/lib/std/compress/xz/multibyte.zig b/lib/std/compress/xz/multibyte.zig new file mode 100644 index 0000000000..1226ffcfb2 --- /dev/null +++ b/lib/std/compress/xz/multibyte.zig @@ -0,0 +1,23 @@ +const Multibyte = packed struct(u8) { + value: u7, + more: bool, +}; + +pub fn readInt(reader: anytype) !u64 { + const max_size = 9; + + var chunk = try reader.readStruct(Multibyte); + var num: u64 = chunk.value; + var i: u6 = 0; + + while (chunk.more) { + chunk = try reader.readStruct(Multibyte); + i += 1; + if (i >= max_size or @bitCast(u8, chunk) == 0x00) + return error.CorruptInput; + + num |= @as(u64, chunk.value) << (i * 7); + } + + return num; +} diff --git a/lib/std/compress/xz/stream.zig b/lib/std/compress/xz/stream.zig new file mode 100644 index 0000000000..33916e20df --- /dev/null +++ b/lib/std/compress/xz/stream.zig @@ -0,0 +1,136 @@ +const std = @import("std"); +const block = @import("block.zig"); +const check = @import("check.zig"); +const multibyte = @import("multibyte.zig"); +const Allocator = std.mem.Allocator; +const Crc32 = std.hash.Crc32; + +test { + _ = @import("stream_test.zig"); +} + +const Flags = packed struct(u16) { + reserved1: u8, + check_kind: check.Kind, + reserved2: u4, +}; + +pub fn stream(allocator: Allocator, reader: anytype) !Stream(@TypeOf(reader)) { + return Stream(@TypeOf(reader)).init(allocator, reader); +} + +pub fn Stream(comptime ReaderType: type) type { + return struct { + const Self = @This(); + + pub const Error = ReaderType.Error || block.Decoder(ReaderType).Error; + pub const Reader = std.io.Reader(*Self, Error, read); + + allocator: Allocator, + block_decoder: block.Decoder(ReaderType), + in_reader: ReaderType, + + fn init(allocator: Allocator, source: ReaderType) !Self { + const Header = extern struct { + magic: [6]u8, + flags: Flags, + crc32: u32, + }; + + const header = try source.readStruct(Header); + + if (!std.mem.eql(u8, &header.magic, &.{ 0xFD, '7', 'z', 'X', 'Z', 0x00 })) + return error.BadHeader; + + if (header.flags.reserved1 != 0 or header.flags.reserved2 != 0) + return error.BadHeader; + + const hash = Crc32.hash(std.mem.asBytes(&header.flags)); + if (hash != header.crc32) + return error.WrongChecksum; + + return Self{ + .allocator = allocator, + .block_decoder = try block.decoder(allocator, source, header.flags.check_kind), + .in_reader = source, + }; + } + + pub fn deinit(self: *Self) void { + self.block_decoder.deinit(); + } + + pub fn reader(self: *Self) Reader { + return .{ .context = self }; + } + + pub fn read(self: *Self, buffer: []u8) Error!usize { + if (buffer.len == 0) + return 0; + + const r = try self.block_decoder.read(buffer); + if (r != 0) + return r; + + const index_size = blk: { + var hasher = std.compress.hashedReader(self.in_reader, Crc32.init()); + hasher.hasher.update(&[1]u8{0x00}); + + var counter = std.io.countingReader(hasher.reader()); + counter.bytes_read += 1; + + const counting_reader = counter.reader(); + + const record_count = try multibyte.readInt(counting_reader); + if (record_count != self.block_decoder.block_count) + return error.CorruptInput; + + var i: usize = 0; + while (i < record_count) : (i += 1) { + // TODO: validate records + _ = try multibyte.readInt(counting_reader); + _ = try multibyte.readInt(counting_reader); + } + + while (counter.bytes_read % 4 != 0) { + if (try counting_reader.readByte() != 0) + return error.CorruptInput; + } + + const hash_a = hasher.hasher.final(); + const hash_b = try counting_reader.readIntLittle(u32); + if (hash_a != hash_b) + return error.WrongChecksum; + + break :blk counter.bytes_read; + }; + + const Footer = extern struct { + crc32: u32, + backward_size: u32, + flags: Flags, + magic: [2]u8, + }; + + const footer = try self.in_reader.readStruct(Footer); + const backward_size = (footer.backward_size + 1) * 4; + if (backward_size != index_size) + return error.CorruptInput; + + if (footer.flags.reserved1 != 0 or footer.flags.reserved2 != 0) + return error.CorruptInput; + + var hasher = Crc32.init(); + hasher.update(std.mem.asBytes(&footer.backward_size)); + hasher.update(std.mem.asBytes(&footer.flags)); + const hash = hasher.final(); + if (hash != footer.crc32) + return error.WrongChecksum; + + if (!std.mem.eql(u8, &footer.magic, &.{ 'Y', 'Z' })) + return error.CorruptInput; + + return 0; + } + }; +} diff --git a/lib/std/compress/xz/stream_test.zig b/lib/std/compress/xz/stream_test.zig new file mode 100644 index 0000000000..beaeedf535 --- /dev/null +++ b/lib/std/compress/xz/stream_test.zig @@ -0,0 +1,80 @@ +const std = @import("std"); +const testing = std.testing; +const stream = @import("stream.zig").stream; + +fn decompress(data: []const u8) ![]u8 { + var in_stream = std.io.fixedBufferStream(data); + + var xz_stream = try stream(testing.allocator, in_stream.reader()); + defer xz_stream.deinit(); + + return xz_stream.reader().readAllAlloc(testing.allocator, std.math.maxInt(usize)); +} + +fn testReader(data: []const u8, comptime expected: []const u8) !void { + const buf = try decompress(data); + defer testing.allocator.free(buf); + + try testing.expectEqualSlices(u8, expected, buf); +} + +test "compressed data" { + try testReader(@embedFile("testdata/good-0-empty.xz"), ""); + + inline for ([_][]const u8{ + "good-1-check-none.xz", + "good-1-check-crc32.xz", + "good-1-check-crc64.xz", + "good-1-check-sha256.xz", + "good-2-lzma2.xz", + "good-1-block_header-1.xz", + "good-1-block_header-2.xz", + "good-1-block_header-3.xz", + }) |filename| { + try testReader(@embedFile("testdata/" ++ filename), + \\Hello + \\World! + \\ + ); + } + + inline for ([_][]const u8{ + "good-1-lzma2-1.xz", + "good-1-lzma2-2.xz", + "good-1-lzma2-3.xz", + "good-1-lzma2-4.xz", + }) |filename| { + try testReader(@embedFile("testdata/" ++ filename), + \\Lorem ipsum dolor sit amet, consectetur adipisicing + \\elit, sed do eiusmod tempor incididunt ut + \\labore et dolore magna aliqua. Ut enim + \\ad minim veniam, quis nostrud exercitation ullamco + \\laboris nisi ut aliquip ex ea commodo + \\consequat. Duis aute irure dolor in reprehenderit + \\in voluptate velit esse cillum dolore eu + \\fugiat nulla pariatur. Excepteur sint occaecat cupidatat + \\non proident, sunt in culpa qui officia + \\deserunt mollit anim id est laborum. + \\ + ); + } + + try testReader(@embedFile("testdata/good-1-lzma2-5.xz"), ""); +} + +test "unsupported" { + inline for ([_][]const u8{ + "good-1-delta-lzma2.tiff.xz", + "good-1-x86-lzma2.xz", + "good-1-sparc-lzma2.xz", + "good-1-arm64-lzma2-1.xz", + "good-1-arm64-lzma2-2.xz", + "good-1-3delta-lzma2.xz", + "good-1-empty-bcj-lzma2.xz", + }) |filename| { + try testing.expectError( + error.Unsupported, + decompress(@embedFile("testdata/" ++ filename)), + ); + } +} diff --git a/lib/std/compress/xz/testdata/good-0-empty.xz b/lib/std/compress/xz/testdata/good-0-empty.xz new file mode 100644 index 0000000000000000000000000000000000000000..83b95e05bc814cb60f759a30e89d243960797b60 GIT binary patch literal 32 lcmexsUKJ6=z`&TPbkB@|fq_BhzKh}nr6abP~2aW&$ literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-0cat-empty.xz b/lib/std/compress/xz/testdata/good-0cat-empty.xz new file mode 100644 index 0000000000000000000000000000000000000000..e6fc31461db459ae9075e704581317d910b4afee GIT binary patch literal 64 ncmexsUKJ6=z`&TPbkB@|fq_BhzKh}nr6d`#47H$t4 literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-0catpad-empty.xz b/lib/std/compress/xz/testdata/good-0catpad-empty.xz new file mode 100644 index 0000000000000000000000000000000000000000..4f86b7d152d477b0da914aff1590000e89bf1183 GIT binary patch literal 68 pcmexsUKJ6=z`&TPbkB@|fq_BhzKh}nr6o?|E1^_gs4;ugg literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-0pad-empty.xz b/lib/std/compress/xz/testdata/good-0pad-empty.xz new file mode 100644 index 0000000000000000000000000000000000000000..c51e3a69c0de7e68ad78338a6c86cb2980eb1a2f GIT binary patch literal 36 ncmexsUKJ6=z`&TPbkB@|fq_BhzKh}nr6o>)q!W@bhPW=2M4MkYl@4hDujqN&Fi8Bh2qZ*O_TS?K?3*TV0C z$sB9eeTs16O?$V3@oa)#N5u8K+qP;9tRH``H%S*iFyH>?A6`D@CC}DpZcLizKHd4S zzWd_EUs<9K%(i7b6K(Zt^C6$P{^5UjuMhsu_W$ehz_=xIlDBM0`tH6UAaDI+?x4fV z%@2flGVa{+-#VUU{cepj|65WD_Ziq%vG1zK;;Fk= z7_e;(N?88oqqyi#$F8vYv zTWoMk;9s-O{D4pDx{jFrdz>CtA2jv)x^J;qk_pr5t!QTiS3H;&zaw+$+|X^m*}b>S zV$bt_5iB8+Rz|MeJ{uMbW{3x37xcXcoqOFuXf(H!GKC$j@H!vpXH{ r?qM-uU|?X_#P0G^+}OK?f$=5tNoEFyNx%2**?1)VHxo#bB{B*CoooD1 literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-arm64-lzma2-1.xz b/lib/std/compress/xz/testdata/good-1-arm64-lzma2-1.xz new file mode 100644 index 0000000000000000000000000000000000000000..78169f14e55bab6df64b171e02d275d1c878f095 GIT binary patch literal 512 zcmexsUKJ6=z`&TPbkB^5k&8i*k%M8;jk=Ey6zdre=P@v3D0dVlALRHYEw8p>rPUTka!@ocN5E0q6@Y`X*>GOgMtFnFX z)vw;#D0!)Ub6@0{wMJiyXHDRpS?d-Wv_O>kxy*;@{_78RpVBT%K6d#|#?AdK3R1ES zsv6A(MvGIPsNFpvcCCAZpn1pMM>qHAZg;gg6~(_wZN}W4KO`21o?XXep#CXo1uw6H z@5Y8z9+PTj%#7;ekN*)-7hh@i`G(DV<|_eO+fQ2AEPHL-b^UkGKEumpMS9tt^6DiI znZC!$MLx)Xc=ycD38&Q~7c9=7R@`*nw@^{eZ~yrVnw!pt%Gk#hO!M) zk_&pK#MjF=|CB$M;_tfmhj3H{kJSAq+;?`d8@~x&`P=a6nZxZK_lw=d?&mmoq8QITJUX}a&K1eXt+wmGE;*kj^f&q+SJk`kiH%%r zoUx|`j^=0hzkNIXxVikjT-`%z3!Y7pU^~3x0Kd;;8LrvP-vzccuI`Fm$Fpk1>W!(P z^~OQpl=;^vE;;(qW$uIRmbtnf3O$X10SWIHG8Eo?yw(42_%^;j4jz{o7#7q#yu!eE ao4LW6fx-EBXR@6EZ#NSI0|NtNWE22KhV}3O literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-arm64-lzma2-2.xz b/lib/std/compress/xz/testdata/good-1-arm64-lzma2-2.xz new file mode 100644 index 0000000000000000000000000000000000000000..e0302fe99e994db8e02e58b5deebb0059c90bdf4 GIT binary patch literal 488 zcmexsUKJ6=z`&TPbkB^Lk&A`l!~g$^j2sNpK9ko^&0KHQr*)o_f1LMVSl{uFHT-$Zj@DHc z5}vuH$5W18m0UfOwLe8O+VU~i0hwo+U#iYICbnQ9S*UC%N4$&LzU6Z|OJ+^$ zm&yCG%5paH-Lfeyoc=;ddxN}Dr+{R{j~|C}XP2-)^^fQIz~)gNanuyV=4vf>&^-10_>u7LRge3R yg*0xFV)4&YDxVW|U-$w80|Uc?nuk{y7!NTwI5RK^ObKweGvMuJ0!c7NMgagB9p=jb literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-block_header-1.xz b/lib/std/compress/xz/testdata/good-1-block_header-1.xz new file mode 100644 index 0000000000000000000000000000000000000000..fea5ad2f9980d5d9145700561a980e6e106b4e32 GIT binary patch literal 72 zcmexsUKJ6=z`&TPbkB_WfFQ3TBL@Qr)Zepw&B(yxk(!f}&lR3ul#`;!1rm2&yhxOR VQI)q)^2oLcPBVEKL4u5tQ2?t(5zGJp literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-block_header-2.xz b/lib/std/compress/xz/testdata/good-1-block_header-2.xz new file mode 100644 index 0000000000000000000000000000000000000000..6b5dcb347b24d1a5abf4150b1e3c9039b1b65a0d GIT binary patch literal 68 zcmexsUKJ6=z`&TPbkB^*K~RyAgMq=yr{f_b1CK{)PEI~ocz#h%iXs;S0|SHe;zgni WjEcOacUD}Q;53t$5hTbM83h1n(h+X} literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-block_header-3.xz b/lib/std/compress/xz/testdata/good-1-block_header-3.xz new file mode 100644 index 0000000000000000000000000000000000000000..156531206342a87baa8029915aae0c940301c5ed GIT binary patch literal 68 zcmexsUKJ6=z`&TPbkB^bfme}{gMlGXurZR6fyW~?CnujPJijO>MUjhvfq}t!@gh+M WMn&GzJ1Z_taGJ@>2ohwBi~;~w3lR7K literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-check-crc32.xz b/lib/std/compress/xz/testdata/good-1-check-crc32.xz new file mode 100644 index 0000000000000000000000000000000000000000..6c89593d447a258c120488d5e389e81d587893e8 GIT binary patch literal 68 zcmexsUKJ6=z`&TPbkB^5L6MPzfq~%$zp^kR1FJ`BPEI}-69Zd#eo;<}A{T@6;zgni Yj4Hea8u!;vaGJ@>$iTqBz!(_?03VqTYXATM literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-check-crc64.xz b/lib/std/compress/xz/testdata/good-1-check-crc64.xz new file mode 100644 index 0000000000000000000000000000000000000000..5a9915d2f9fc4711b26ed2d399027583bf824340 GIT binary patch literal 72 zcmexsUKJ6=z`*kC+7>q^21P~=1_p*3{K~?N46GihIXU@UObl${`9(P?id+ou^*RLS c+D|*hz^K7%lb*#azwL7^BLf2i150ES0K_m7*Z=?k literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-check-none.xz b/lib/std/compress/xz/testdata/good-1-check-none.xz new file mode 100644 index 0000000000000000000000000000000000000000..1e85faf3d06eff1bc420925a1af096762b00db51 GIT binary patch literal 64 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 H7#Rfs=AY4L literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-empty-bcj-lzma2.xz b/lib/std/compress/xz/testdata/good-1-empty-bcj-lzma2.xz new file mode 100644 index 0000000000000000000000000000000000000000..94016d8b66e129400653eb2ee2bd8797b601a41d GIT binary patch literal 52 zcmexsUKJ6=z`&TPbkB^5k(EJ_k%6K9!N(H}Fu*9tU_C9qc!JYRUPh1@V`LNnO79CL literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-lzma2-1.xz b/lib/std/compress/xz/testdata/good-1-lzma2-1.xz new file mode 100644 index 0000000000000000000000000000000000000000..d8d6489c872156e67ba5efb74bb5215524017c90 GIT binary patch literal 424 zcmexsUKJ6=z`&TPbkB^5L6MPzfq~%$zq0THhDQwBVj0w=Pr0Q>eJbBk+jhh8Hmm8` z=A|`4OIdGE*sCvcxv*&3imuw0u)^Lfr5UT|*-mKCJs!s+6m;31ougW2N%?2t9pVSx zO>DH>-2UM|!{)3Y$G3VLKBY`wGHYJ)!gZ1*yeqFp=e*naK<7^4ozrvM&Of}vRn;gG zf5G8I9q)9Pb6XGn(TU{P&)jh5x=Y{YE4ufdiYex~H?84_yzwMWGx6%hU!KVm1nm?q ztbBA;r17Tmg?{ICuAyd`s~8S2JY`tR&Cv64u7mc4TG^TJp4>?;NpV}Uz$+zn(>K3^ zCo<-%hpgSb%*3Yr4ZogrpOgC2jQt5;xUD|SHhg{G{>J*Hp_ANLBa}G%S0r$7FMesa zXN%bFh?g7aw-a+{fE9XRGMS=a(u1y{~Fs_-QJ2H1eJbBk+jhh8Hmm8` z=A|`4OIdGE*sCvcxv*&3imuw0u)^Lfr5UT|*-mKCJs!s+6m;31ougW2N%?2t9pVSx zO>DH>-2UM|!{)3Y$G3VLKBY`wGHYJ)!gZ1*yeqFp=e*naK<7^4ozrvM&Of}vRn;gG zf5G8I9q)9Pb6XGn(TU{P&)jh5x=Y{YE4ufdiYex~H?84_yzwMWGx6%hU!KVm1nm?q ztbBA;r17Tmg?{ICuAyd`s~8qAJY`tV(DQMwLv544N|DINxhb jWMKI1?s1!ev6=ZKGXulA>z73B40yYl7#J8B7$c(qIPJuK literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-lzma2-3.xz b/lib/std/compress/xz/testdata/good-1-lzma2-3.xz new file mode 100644 index 0000000000000000000000000000000000000000..c4c72be6561465781670b5a9b6067b1cfa016f7a GIT binary patch literal 408 zcmexsUKJ6=z`&TPbkB^5L6MPzfq~%$zp^kRgNaXmQEIM2Wab}4^ zVs2`QjzV&NUU6!2Noq-HkwRihWtE-u?$ADIdej;>rKu1`Q7}g z%p*6ZrqbV@Wxd70+y3U>K6U%13-?C7eZt#zt$6hLZE46IM};%{&7u`%#_}sJWLrE< zcl-1?AFBU766(z zyMO0T?ftBnrO|MrFShac9`Or0lecnA-NiSlDQ(^V9n1{B-92tIFn(b=$;`lzet4># QodIt*69WSS17lq^21P~=1_p*3{K~=)7rr&w%U6>vz-MjkCWV+>ISN(M}^(!;`Uz&G%{5w=?=%DpSSmI?`zxd?A^!ftnZk4KauCi3v&*y zdxy%zc6j*B+Zh}nZ`}Msb3yuvG^=_gp`_pLPxgEXnQ*dG7@ literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-lzma2-5.xz b/lib/std/compress/xz/testdata/good-1-lzma2-5.xz new file mode 100644 index 0000000000000000000000000000000000000000..339d1c30c17f6358c7004c9ec071d81558b650c4 GIT binary patch literal 52 zcmexsUKJ6=z`&TPbkB^5L6K2_fq`K~L0=mK3@{2ZSWk;Dp5Qc-mk}h!7#RfsF$xMp literal 0 HcmV?d00001 diff --git a/lib/std/compress/xz/testdata/good-1-sparc-lzma2.xz b/lib/std/compress/xz/testdata/good-1-sparc-lzma2.xz new file mode 100644 index 0000000000000000000000000000000000000000..4532bc61c1a3fd3ba55726bff542230dbfa3de10 GIT binary patch literal 612 zcmexsUKJ6=z`*kC+7>q^MotDrMh*s^RjFih zdpgChudnQAHS5W{YGab6xxiJu)j4Q=;5_fRc_s({_Z{5(kms6WK%9uRW=N{Wgd#uP z)Iie-s%6^~yXJooDYaa+u2g)r=54cY>y9y5SxsimXv*#ExX5X3j zD_`%&!Xu~h)N4xQHC|Me*&m*yqS$wt`;hQgp>x(!lHpT-&9%QLcBw*uQOZg1X7zzS zor?LVo!7q$TfC0BV7u_9c{-&XSQ`;o~@nYaI$Y-qXgchlSa1BY(ik97@U zi1#zyaPOVFIaivDP3HTHwU(u>M?9n27S*}#?6Z`0Ul46|LuL94@rK5;&rUeGrv?~5 z$)34jwtS5cNP@GdR3)nBeTsh}voWA^vY2@e)r{-X5q z{Y9k}&78A^gVzYXN*$z`(%peJ?wgu2s=52F86X XH#iv>9q^MivG|Mh=EcJ4;SKV9jRgie<2$=-QHDeed21Z{{1O!Am9< zFMcX57cJ}ck?r8R%2%#QWjvZ^z31nhE!-*kp&{a4;WvxWsTY4Ue^|*<*mm@q_jdks zHk!*>Q%%p${a+<8_mt1LTO{|= zg>TnZXLz3|eKPeqb7rUg2KEDy{;$+p&8pfDx0i5jEPrahcH@8RHA`%3)_h-fbk9HI zFB{a>e`E+h5g+yS+VV*MWl^@78xJ;EN~gEQy{#~3bLDIOEO@ApVbYQ`X_-6uMn+PRX3KuF#N_XVZ$)QVId5OQ$F}5&gvsYX{g@e{ ztIu*&>o?5n^}M-#hv}59Z^YJGOV`cPUE0#~XS1(8TkwS1U^|J6sT(Fvo*rH^@AA5p zxj{G1zo_|ibn~3=|3lwPPl$TRd`O|ar|%;}6_?wiqNVBw^4rgu@3xA)JjcJV=JL6X zk1yvbr}y6e#*((GAh!6zM5U;oTiUc1%CM|E`c#Bf@blR{|NTVgHw7ljWbav5DQ3~3 zGp%ig?2~9gE5mS^XVYHnUdXk0$;t&YjC=MfS@hYtsYxx3?ugkbTZ-{>% zI5mUq4TsdX)k_l&s!qFc!7_>C#@am7>xWGY@