From 54aaf30ea515b13431d22196a78ad0e8214e04a9 Mon Sep 17 00:00:00 2001 From: "Caleb J. Gardner" Date: Sat, 21 Mar 2026 02:13:36 -0500 Subject: [PATCH] Working on re-doing decompression --- build.zig | 21 +++-- build.zig.zon | 3 + src/archive.zig | 56 ++++++++---- src/decomp.zig | 187 -------------------------------------- src/decomp/c.zig | 8 +- src/decomp/gzip.zig | 19 +--- src/decomp/lzma.zig | 79 ++++++++++++++++ src/decomp/misc_c.zig | 32 +++++++ src/decomp/zig_decomp.zig | 35 +++++++ src/super.zig | 10 +- src/tables.zig | 1 - 11 files changed, 213 insertions(+), 238 deletions(-) delete mode 100644 src/decomp.zig create mode 100644 src/decomp/lzma.zig create mode 100644 src/decomp/misc_c.zig create mode 100644 src/decomp/zig_decomp.zig diff --git a/build.zig b/build.zig index 01bb42f..65cd0ad 100644 --- a/build.zig +++ b/build.zig @@ -2,13 +2,13 @@ const std = @import("std"); pub fn build(b: *std.Build) !void { const use_zig_decomp = b.option(bool, "use_zig_decomp", "Use zig standard library for decompression.") orelse false; - const allow_lzo = b.option(bool, "allow_lzo", "Compile with lzo support") orelse false; + // const allow_lzo = b.option(bool, "allow_lzo", "Compile with lzo support") orelse false; const debug = b.option(bool, "debug", "Enable options to make debugging easier.") orelse false; const version_string_option = b.option([]const u8, "version", "Version of the library/binary"); const zig_squashfs_options = b.addOptions(); zig_squashfs_options.addOption(bool, "use_zig_decomp", use_zig_decomp); - zig_squashfs_options.addOption(bool, "allow_lzo", allow_lzo); + // zig_squashfs_options.addOption(bool, "allow_lzo", allow_lzo); const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); @@ -30,8 +30,12 @@ pub fn build(b: *std.Build) !void { mod.linkLibrary(zlib_ng.artifact("zng")); mod.linkSystemLibrary("lzma", .{ .preferred_link_mode = .static }); - if (allow_lzo == true) - mod.linkSystemLibrary("minilzo", .{ .preferred_link_mode = .static }); + + var minilzo = b.dependency("minilzo", .{ + .target = target, + .optimize = optimize, + }); + mod.linkLibrary(minilzo.artifact("minilzo")); var lz4 = b.dependency("lz4", .{ .target = target, @@ -85,15 +89,14 @@ pub fn build(b: *std.Build) !void { const mod_tests = b.addTest(.{ .root_module = mod, + .test_runner = .{ + .mode = .simple, + .path = b.path("src/test.zig"), + }, }); const run_mod_tests = b.addRunArtifact(mod_tests); - const exe_tests = b.addTest(.{ - .root_module = exe.root_module, - }); - const run_exe_tests = b.addRunArtifact(exe_tests); const test_step = b.step("test", "Run tests"); test_step.dependOn(&run_mod_tests.step); - test_step.dependOn(&run_exe_tests.step); // zls build check steps const lib_check = b.addLibrary(.{ diff --git a/build.zig.zon b/build.zig.zon index fd6278a..9ae548b 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -16,6 +16,9 @@ .url = "git+https://github.com/allyourcodebase/lz4.git?ref=1.10.0-6#41f52ab227caf9d48cf88c89a4d2946caa12b102", .hash = "lz4-1.10.0-6-ewyzw-4NAAAWDpY4xpiqr4LQhZQAC0x_rGnW2iPh6jk2", }, + .minilzo = .{ + .path = "../zig-minilzo", + }, }, .paths = .{ "build.zig", diff --git a/src/archive.zig b/src/archive.zig index 1285435..010f3dc 100644 --- a/src/archive.zig +++ b/src/archive.zig @@ -5,7 +5,10 @@ const std = @import("std"); const File = std.fs.File; const builtin = @import("builtin"); -const Decomp = @import("decomp.zig"); +const config = @import("config"); + +const cDecomp = @import("decomp/misc_c.zig"); +const Decomp = @import("decomp/zig_decomp.zig"); const ExtractionOptions = @import("options.zig"); const Inode = @import("inode.zig"); const InodeRef = Inode.Ref; @@ -17,22 +20,35 @@ const MetadataReader = @import("util/metadata.zig"); const OffsetFile = @import("util/offset_file.zig"); const XattrTable = @import("xattr.zig"); -const config = if (builtin.is_test) .{ - .use_zig_decomp = !builtin.link_libc, - .allow_lzo = false, -} else @import("config"); - const Archive = @This(); alloc: std.mem.Allocator, fil: OffsetFile, -decomp: Decomp.DecompFn, super: Superblock, tables: ?Tables = null, +decomp: if (config.use_zig_decomp) Decomp.DecompFn else union(enum) { + gzip: @import("decomp/gzip.zig"), + lzma: @import("decomp/lzma.zig"), + lzo: void, + xz: @import("decomp/lzma.zig"), + lz4: void, + zstd: @import("decomp/zstd.zig"), + + pub fn decomp(self: @This(), in: []u8, out: []u8) !usize { + return switch (self) { + .gzip => |*g| g.decompress(in, out), + .zstd => |*z| z.decompress(in, out), + .lzma, .xz => |*d| d.decompress(in, out), + .lz4 => cDecomp.lz4(in, out), + .lzo => cDecomp.lzo(in, out), + }; + } +}, + /// Default settings using std.Thread.getCpuCount() threads and the minimum of 4gb or half of system memory for memory usage. pub fn init(alloc: std.mem.Allocator, fil: File, offset: u64) !Archive { var super: Superblock = undefined; @@ -40,18 +56,26 @@ pub fn init(alloc: std.mem.Allocator, fil: File, offset: u64) !Archive { std.debug.assert(red == @sizeOf(Superblock)); try super.validate(); const off_fil: OffsetFile = .init(fil, offset); - const decomp: Decomp.DecompFn = switch (super.compression) { - .gzip => Decomp.gzipDecompress, - .lzma => Decomp.lzmaDecompress, - .xz => Decomp.xzDecompress, - .zstd => Decomp.zstdDecompress, - .lz4 => if (!config.use_zig_decomp) Decomp.cLz4 else return error.Lz4Unsupported, - .lzo => if (!config.use_zig_decomp and config.allow_lzo) Decomp.lzoDecompress else return error.LzoUnsupported, - }; return .{ .alloc = alloc, .fil = off_fil, - .decomp = decomp, + .decomp = if (config.use_zig_decomp) + switch (super.compression) { + .lz4 => return error.Lz4Unsupported, + .lzo => return error.LzoUnsupported, + .gzip => Decomp.gzip, + .lzma => Decomp.lzma, + .xz => Decomp.xz, + .zstd => Decomp.zstd, + } + else switch (super.compression) { + .gzip => .{ .gzip = .init(alloc) }, + .zstd => .{ .zstd = .init(alloc) }, + .xz => .{ .xz = .init(alloc, true) }, + .lzma => .{ .lzma = .init(alloc, false) }, + .lzo => .{ .lzo = .{} }, + .lz4 => .{ .lz4 = .{} }, + }, .super = super, }; } diff --git a/src/decomp.zig b/src/decomp.zig deleted file mode 100644 index 8705a80..0000000 --- a/src/decomp.zig +++ /dev/null @@ -1,187 +0,0 @@ -//! Implementations for decompression. -//! TODO: change to vtable interface to allow for shared decompressors for better performance/resource usage. - -const std = @import("std"); -const Reader = std.Io.Reader; -const builtin = @import("builtin"); - -const config = if (builtin.is_test) .{ - .use_zig_decomp = !builtin.link_libc, - .allow_lzo = false, // Change once LZO compilation is fixed -} else @import("config"); - -const c = @cImport({ - @cInclude("zlib-ng.h"); - @cInclude("lzma.h"); - @cInclude("lz4.h"); - @cInclude("zstd.h"); - @cInclude("zstd_errors.h"); - if (config.allow_lzo) - @cInclude("lzo/minilzo.h"); -}); - -pub const CompressionType = enum(u16) { - gzip = 1, - lzma, - lzo, - xz, - lz4, - zstd, -}; - -pub const DecompFn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize; // TODO: replace anyerror to definitive error types. - -pub const gzipDecompress = if (!config.use_zig_decomp) cGzip else zigGzip; - -fn zigGzip(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - var rdr: Reader = .fixed(in); - const buf = try alloc.alloc(u8, out.len); - defer alloc.free(buf); - var decomp = std.compress.flate.Decompress.init(&rdr, .zlib, buf); - return decomp.reader.readSliceShort(out); -} -fn cGzip(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - var out_len: usize = out.len; - const res = c.zng_uncompress(out.ptr, &out_len, in.ptr, in.len); - return switch (res) { - c.Z_OK => out_len, - c.Z_MEM_ERROR => error.NotEnoughMemory, - c.Z_BUF_ERROR => error.OutBufferTooSmall, - c.Z_DATA_ERROR => error.BadData, - else => error.UnknownResult, - }; -} - -pub const lzmaDecompress = if (!config.use_zig_decomp) cLzma else zigLzma; - -fn zigLzma(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - var rdr: Reader = .fixed(in); - var decomp = try std.compress.lzma.decompress(alloc, rdr.adaptToOldInterface()); - return decomp.read(out); -} -fn cLzma(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - var stream: c.lzma_stream = .{ - .next_in = in.ptr, - .avail_in = in.len, - .next_out = out.ptr, - .avail_out = out.len, - }; - var res = c.lzma_alone_decoder(&stream, in.len * 2); - switch (res) { - c.LZMA_OK => {}, - c.LZMA_MEM_ERROR => return error.LzmaMemoryError, - c.LZMA_PROG_ERROR => return error.LzmaProgramError, - else => return error.UnknownResult, - } - defer c.lzma_end(&stream); - while (res == c.LZMA_OK) - res = c.lzma_code(&stream, c.LZMA_RUN); - return switch (res) { - c.LZMA_STREAM_END => stream.total_out, - c.LZMA_MEM_ERROR => error.LzmaMemoryError, - c.LZMA_MEMLIMIT_ERROR => error.LzmaMemoryLimit, - c.LZMA_FORMAT_ERROR => error.LzmaBadFormat, - c.LZMA_DATA_ERROR => error.LzmaDataCorrupt, - c.LZMA_BUF_ERROR => error.LzmaCannotProgress, - c.LZMA_PROG_ERROR => error.LzmaProgramError, - else => error.UnknownResult, - }; -} - -// pub const lzoDecompress = if (!config.use_zig_decomp) cLzo else zigLzo; - -// fn zigLzo(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { -// _ = alloc; -// _ = in; -// _ = out; -// return error.LzoUnsupported; -// } -pub fn cLzo(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - var res = c.lzo_init(); - if (res != 0) return error.LzoInitFailed; - var out_len: usize = out.len; - res = c.lzo1x_decompress(in.ptr, in.len, out.ptr, &out_len, null); - return switch (res) { - c.LZO_E_OK => out_len, - c.LZO_E_ERROR => error.LzoError, - c.LZO_E_OUT_OF_MEMORY => error.LzoOutOfMemory, - c.LZO_E_NOT_COMPRESSIBLE => error.LzoNotCompressible, - c.LZO_E_INPUT_OVERRUN => error.LzoInputOverrun, - c.LZO_E_OUTPUT_OVERRUN => error.LzoOutputOverrun, - c.LZO_E_LOOKBEHIND_OVERRUN => error.LzoLookbehindOverrun, - c.LZO_E_EOF_NOT_FOUND => error.LzoEofNotFound, - c.LZO_E_INPUT_NOT_CONSUMED => error.LzoInputNotConsumed, - c.LZO_E_NOT_YET_IMPLEMENTED => error.LzoNotYetImplemented, - c.LZO_E_INVALID_ARGUMENT => error.LzoInvalidArgument, - c.LZO_E_INVALID_ALIGNMENT => error.LzoInvalidAlignment, - c.LZO_E_OUTPUT_NOT_CONSUMED => error.LzoOutputNotConsumed, - c.LZO_E_INTERNAL_ERROR => error.LzoInternalError, - else => error.UnknownResult, - }; -} - -pub const xzDecompress = if (!config.use_zig_decomp) cXz else zigXz; - -fn zigXz(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - var rdr: Reader = .fixed(in); - var decomp = try std.compress.xz.decompress(alloc, rdr.adaptToOldInterface()); - return decomp.read(out); -} -fn cXz(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - var stream: c.lzma_stream = .{ - .next_in = in.ptr, - .avail_in = in.len, - .next_out = out.ptr, - .avail_out = out.len, - // .allocator = _, TODO: create a custom allocator based on alloc, - }; - var res = c.lzma_stream_decoder(&stream, in.len * 2, 0); - switch (res) { - c.LZMA_OK => {}, - c.LZMA_MEM_ERROR => return error.LzmaMemoryError, - c.LZMA_PROG_ERROR => return error.LzmaProgramError, - else => return error.UnknownResult, - } - defer c.lzma_end(&stream); - while (res == c.LZMA_OK) - res = c.lzma_code(&stream, c.LZMA_RUN); - return switch (res) { - c.LZMA_STREAM_END => stream.total_out, - c.LZMA_MEM_ERROR => error.LzmaMemoryError, - c.LZMA_MEMLIMIT_ERROR => error.LzmaMemoryLimit, - c.LZMA_FORMAT_ERROR => error.LzmaBadFormat, - c.LZMA_DATA_ERROR => error.LzmaDataCorrupt, - c.LZMA_BUF_ERROR => error.LzmaCannotProgress, - c.LZMA_PROG_ERROR => error.LzmaProgramError, - else => error.UnknownResult, - }; -} - -// pub const lz4Decompress = if (!config.use_zig_decomp) cLz4 else zigLz4; - -// fn zigLz4(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { -// _ = alloc; -// _ = in; -// _ = out; -// return error.Lz4Unsupported; -// } -pub fn cLz4(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - const res = c.LZ4_decompress_safe(in.ptr, out.ptr, @intCast(in.len), @intCast(out.len)); - if (res > 0) return @abs(res); // TODO: Find out what error values it can return. - return error.Lz4DecompressFailed; -} - -pub fn zigZstd(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - var rdr: Reader = .fixed(in); - const buf = try alloc.alloc(u8, 1024 * 1024); - defer alloc.free(buf); - var decomp = std.compress.zstd.Decompress.init(&rdr, buf, .{}); - return decomp.reader.readSliceShort(out) catch |err| { - return decomp.err orelse err; - }; -} diff --git a/src/decomp/c.zig b/src/decomp/c.zig index 2a74c9a..d6acdbd 100644 --- a/src/decomp/c.zig +++ b/src/decomp/c.zig @@ -2,10 +2,7 @@ const std = @import("std"); const Reader = std.Io.Reader; const builtin = @import("builtin"); -const config = if (builtin.is_test) .{ - .use_zig_decomp = !builtin.link_libc, - .allow_lzo = false, // Change once LZO compilation is fixed -} else @import("config"); +const config = @import("config"); pub const c = @cImport({ @cInclude("zlib-ng.h"); @@ -13,6 +10,5 @@ pub const c = @cImport({ @cInclude("lz4.h"); @cInclude("zstd.h"); @cInclude("zstd_errors.h"); - if (config.allow_lzo) - @cInclude("lzo/minilzo.h"); + @cInclude("lzo/minilzo.h"); }); diff --git a/src/decomp/gzip.zig b/src/decomp/gzip.zig index c2d0929..c19a5ba 100644 --- a/src/decomp/gzip.zig +++ b/src/decomp/gzip.zig @@ -15,14 +15,12 @@ const ZlibErrors = error{ const Self = @This(); alloc: std.mem.Allocator, -window_size: i16, streams: std.AutoHashMap(std.Thread.Id, zng_stream), -pub fn init(alloc: std.mem.Allocator, window_size: i16) !Self { +pub fn init(alloc: std.mem.Allocator) !Self { return .{ .alloc = alloc, - .window_size = window_size, .streams = .init(alloc), }; } @@ -40,7 +38,7 @@ pub fn decompress(self: *Self, in: []u8, out: []u8) ZlibErrors!usize { stream.avail_in = in.len; stream.next_out = out.ptr; stream.avail_out = out.len; - var res = c.zng_inflateReset2(stream, self.window_size); + var res = c.zng_inflateReset(stream); switch (res) { c.Z_OK => {}, c.Z_STREAM_ERROR => return ZlibErrors.StreamError, @@ -74,16 +72,3 @@ fn zfree(self_ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) ?*anyopaque { var self: *Self = @ptrCast(self_ptr); self.alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0); } - -pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { - _ = alloc; - var out_len: usize = out.len; - const res = c.zng_uncompress(out.ptr, &out_len, in.ptr, in.len); - return switch (res) { - c.Z_OK => out_len, - c.Z_MEM_ERROR => ZlibErrors.NotEnoughMemory, - c.Z_BUF_ERROR => ZlibErrors.OutputBufferTooSmall, - c.Z_DATA_ERROR => ZlibErrors.BadData, - else => ZlibErrors.Unknown, - }; -} diff --git a/src/decomp/lzma.zig b/src/decomp/lzma.zig new file mode 100644 index 0000000..cc6afbf --- /dev/null +++ b/src/decomp/lzma.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const builtin = @import("builtin"); + +const c = @import("c.zig").c; +const stream = c.lzma_stream; + +const Self = @This(); + +alloc: std.mem.Allocator, +streams: std.AutoHashMap(std.Thread.Id, stream), + +xz: bool, + +pub fn init(alloc: std.mem.Allocator, xz: bool) !Self { + return .{ + .alloc = alloc, + .streams = .init(alloc), + .xz = xz, + }; +} +pub fn deinit(self: Self) void { + var iter = self.streams.keyIterator(); + while (iter.next()) |key| + c.lzma_end(self.streams.getPtr(key)); + self.streams.deinit(); +} + +pub fn decompress(self: *Self, in: []u8, out: []u8) LzmaError!usize { + var strm = try self.getOrCreate(); + strm.next_in = in.ptr; + strm.avail_in = in.len; + strm.next_out = out.ptr; + strm.avail_out = out.len; + + var res = if (self.xz) + c.lzma_stream_decoder(strm, in.len * 2, 0) + else + c.lzma_alone_decoder(strm, in.len * 2); + switch (res) { + c.LZMA_OK => {}, + c.LZMA_MEM_ERROR => return LzmaError.LzmaMemoryError, + c.LZMA_PROG_ERROR => return LzmaError.LzmaProgramError, + else => return LzmaError.UnknownResult, + } + while (res == c.LZMA_OK) + res = c.lzma_code(strm, c.LZMA_RUN); + return switch (res) { + c.LZMA_STREAM_END => strm.total_out, + c.LZMA_MEM_ERROR => LzmaError.LzmaMemoryError, + c.LZMA_MEMLIMIT_ERROR => LzmaError.LzmaMemoryLimit, + c.LZMA_FORMAT_ERROR => LzmaError.LzmaBadFormat, + c.LZMA_DATA_ERROR => LzmaError.LzmaDataCorrupt, + c.LZMA_BUF_ERROR => LzmaError.LzmaCannotProgress, + c.LZMA_PROG_ERROR => LzmaError.LzmaProgramError, + else => LzmaError.UnknownResult, + }; +} + +inline fn getOrCreate(self: *Self) LzmaError!*stream { + const res = try self.streams.getOrPut(std.Thread.getCurrentId()); + if (res.found_existing) return res.value_ptr; + + // Ideally, the zero value should be LZMA_STREAM_INIT, but translate-c can't handle it properly. + // According to lzma, setting it to entirely zero values *should* work. + // res.value_ptr.* = c.LZMA_STREAM_INIT; + res.value_ptr.* = std.mem.zeroInit(stream, .{}); + return res.value_ptr; +} + +pub const LzmaError = error{ + OutOfMemory, + LzmaMemoryError, + LzmaMemoryLimit, + LzmaBadFormat, + LzmaDataCorrupt, + LzmaCannotProgress, + LzmaProgramError, + Unknown, +}; diff --git a/src/decomp/misc_c.zig b/src/decomp/misc_c.zig new file mode 100644 index 0000000..280cbd4 --- /dev/null +++ b/src/decomp/misc_c.zig @@ -0,0 +1,32 @@ +const c = @import("c.zig").c; + +pub fn lzo(in: []u8, out: []u8) anyerror!usize { + var res = c.lzo_init(); + if (res != 0) return error.LzoInitFailed; + var out_len: usize = out.len; + res = c.lzo1x_decompress(in.ptr, in.len, out.ptr, &out_len, null); + + return switch (res) { + c.LZO_E_OK => out_len, + c.LZO_E_ERROR => error.LzoError, + c.LZO_E_OUT_OF_MEMORY => error.LzoOutOfMemory, + c.LZO_E_NOT_COMPRESSIBLE => error.LzoNotCompressible, + c.LZO_E_INPUT_OVERRUN => error.LzoInputOverrun, + c.LZO_E_OUTPUT_OVERRUN => error.LzoOutputOverrun, + c.LZO_E_LOOKBEHIND_OVERRUN => error.LzoLookbehindOverrun, + c.LZO_E_EOF_NOT_FOUND => error.LzoEofNotFound, + c.LZO_E_INPUT_NOT_CONSUMED => error.LzoInputNotConsumed, + c.LZO_E_NOT_YET_IMPLEMENTED => error.LzoNotYetImplemented, + c.LZO_E_INVALID_ARGUMENT => error.LzoInvalidArgument, + c.LZO_E_INVALID_ALIGNMENT => error.LzoInvalidAlignment, + c.LZO_E_OUTPUT_NOT_CONSUMED => error.LzoOutputNotConsumed, + c.LZO_E_INTERNAL_ERROR => error.LzoInternalError, + else => error.UnknownResult, + }; +} + +pub fn lz4(in: []u8, out: []u8) anyerror!usize { + const res = c.LZ4_decompress_safe(in.ptr, out.ptr, @intCast(in.len), @intCast(out.len)); + if (res > 0) return @abs(res); // TODO: Find out what error values it can return. + return error.Lz4DecompressFailed; +} diff --git a/src/decomp/zig_decomp.zig b/src/decomp/zig_decomp.zig new file mode 100644 index 0000000..aba437d --- /dev/null +++ b/src/decomp/zig_decomp.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const Reader = std.Io.Reader; +const builtin = @import("builtin"); + +pub const DecompFn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize; // TODO: replace anyerror to definitive error types. + +pub fn gzip(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { + var rdr: Reader = .fixed(in); + const buf = try alloc.alloc(u8, out.len); + defer alloc.free(buf); + var decomp = std.compress.flate.Decompress.init(&rdr, .zlib, buf); + return decomp.reader.readSliceShort(out); +} + +pub fn lzma(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { + var rdr: Reader = .fixed(in); + var decomp = try std.compress.lzma.decompress(alloc, rdr.adaptToOldInterface()); + return decomp.read(out); +} + +pub fn xz(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { + var rdr: Reader = .fixed(in); + var decomp = try std.compress.xz.decompress(alloc, rdr.adaptToOldInterface()); + return decomp.read(out); +} + +pub fn zstd(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize { + var rdr: Reader = .fixed(in); + const buf = try alloc.alloc(u8, 1024 * 1024); + defer alloc.free(buf); + var decomp = std.compress.zstd.Decompress.init(&rdr, buf, .{}); + return decomp.reader.readSliceShort(out) catch |err| { + return decomp.err orelse err; + }; +} diff --git a/src/super.zig b/src/super.zig index c1b6c65..29ec002 100644 --- a/src/super.zig +++ b/src/super.zig @@ -1,7 +1,6 @@ const std = @import("std"); const math = std.math; -const CompressionType = @import("decomp.zig").CompressionType; const InodeRef = @import("inode.zig").Ref; const SQUASHFS_MAGIC: u32 = std.mem.readInt(u32, "hsqs", .little); @@ -20,7 +19,14 @@ pub const Superblock = packed struct { mod_time: u32, block_size: u32, frag_count: u32, - compression: CompressionType, + compression: enum(u16) { + gzip = 1, + lzma, + lzo, + xz, + lz4, + zstd, + }, block_log: u16, flags: packed struct { inode_uncompressed: bool, diff --git a/src/tables.zig b/src/tables.zig index 700d3b6..ae4016b 100644 --- a/src/tables.zig +++ b/src/tables.zig @@ -2,7 +2,6 @@ const std = @import("std"); const Mutex = std.Thread.Mutex; const Archive = @import("archive.zig"); -const DecompFn = @import("decomp.zig").DecompFn; const BlockSize = @import("inode_data/file.zig").BlockSize; const InodeRef = @import("inode.zig").Ref; const Superblock = @import("super.zig").Superblock;