diff --git a/.gitignore b/.gitignore index 3400e46..194b300 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ testing/ .zig-cache/ zig-out/ +zig-pkg/ diff --git a/build.zig b/build.zig index 6c2d769..a749687 100644 --- a/build.zig +++ b/build.zig @@ -1,7 +1,7 @@ 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 use_zig_decomp = b.option(bool, "use_zig_decomp", "Use zig standard library for decompression.") orelse true; // 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"); @@ -16,13 +16,21 @@ pub fn build(b: *std.Build) !void { .root_source_file = b.path("src/root.zig"), .target = target, .optimize = if (debug == true) .Debug else optimize, - .link_libc = !use_zig_decomp, .valgrind = debug, .error_tracing = debug, .strip = if (debug == true) false else null, }); mod.addOptions("config", zig_squashfs_options); if (!use_zig_decomp) { + mod.link_libc = true; + + const c_imports = b.addTranslateC(.{ + .optimize = optimize, + .target = target, + .root_source_file = b.path("src/imports.c"), + }); + mod.addImport("c", c_imports.createModule()); + var zlib_ng = b.dependency("zlib_ng", .{ .target = target, .optimize = optimize, diff --git a/build.zig.zon b/build.zig.zon index ccb6f95..a8638c2 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -2,7 +2,7 @@ .name = .squashfs, .version = "0.0.6", .fingerprint = 0x37ba29474b87f145, // Changing this has security and trust implications. - .minimum_zig_version = "0.15.2", + .minimum_zig_version = "0.16.0", .dependencies = .{ .zlib_ng = .{ // .url = "git+https://github.com/CalebQ42/zig-zlib-ng#5f2f02dfb28acca2517dacbbd09e9b987f57b133", @@ -22,10 +22,10 @@ // .hash = "minilzo-2.10.0-Ij7BO8wLAADeWI4Pe4jp8XTDsDaquZR14oZ7_9yKKDWP", .path = "../zig-minilzo", }, - .fastlzma2 = .{ - .url = "git+https://github.com/allyourcodebase/fast-lzma2#d7615e0c957a62fcd6691b3fe9519a091885bfa2", - .hash = "fastlzma2-0.0.0-gNWHgVeLAAD0Tlak3xhNcgpPSYcjyJppq0tlGmPKCC_V", - }, + // .fastlzma2 = .{ + // .url = "git+https://github.com/allyourcodebase/fast-lzma2#d7615e0c957a62fcd6691b3fe9519a091885bfa2", + // .hash = "fastlzma2-0.0.0-gNWHgVeLAAD0Tlak3xhNcgpPSYcjyJppq0tlGmPKCC_V", + // }, }, .paths = .{ "build.zig", diff --git a/src/archive.zig b/src/archive.zig index 4344589..f26ddea 100644 --- a/src/archive.zig +++ b/src/archive.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Io = std.Io; const DecompTypes = @import("decomp/types.zig"); const Decompressor = @import("decomp.zig"); @@ -27,9 +28,9 @@ super: Superblock, stateless_decomp: Decompressor, /// Create an Archive from a File. -pub fn init(fil: std.fs.File, offset: u64) !Archive { +pub fn init(io: Io, fil: Io.File, offset: u64) !Archive { var super: Superblock = undefined; - var fil_rdr = fil.reader(&[0]u8{}); + var fil_rdr = fil.reader(io, &[0]u8{}); if (offset > 0) try fil_rdr.seekTo(offset); try fil_rdr.interface.readSliceEndian(Superblock, @ptrCast(&super), .little); diff --git a/src/bin/unsquashfs.zig b/src/bin/unsquashfs.zig index 0d85644..5681c2e 100644 --- a/src/bin/unsquashfs.zig +++ b/src/bin/unsquashfs.zig @@ -1,5 +1,6 @@ const std = @import("std"); -const Writer = std.Io.Writer; +const Io = std.Io; +const Writer = Io.Writer; const builtin = @import("builtin"); const config = @import("config"); @@ -38,20 +39,22 @@ var ignore_xattrs: bool = false; var ignore_permissions: bool = false; var force: bool = false; -pub fn main() !void { - const alloc = std.heap.smp_allocator; - var stdout = std.fs.File.stdout(); - var out = stdout.writer(&[0]u8{}); +pub fn main(init: std.process.Init) !void { + const alloc = init.gpa; + const io = init.io; + + var stdout = std.Io.File.stdout(); + var out = stdout.writer(io, &[0]u8{}); defer out.interface.flush() catch {}; - try handleArgs(alloc, &out.interface); + try handleArgs(init.minimal.args, &out.interface); if (archive.len == 0) { try out.interface.print("You must provide a squashfs archive\n", .{}); try out.interface.print(help_mgs, .{}); return; } - var fil: std.fs.File = try std.fs.cwd().openFile(archive, .{}); //TODO: Handle error gracefully. - defer fil.close(); - var arc: squashfs.Archive = try .init(fil, offset); //TODO: Handle error gracefully. + var fil: Io.File = try Io.Dir.cwd().openFile(io, archive, .{}); //TODO: Handle error gracefully. + defer fil.close(io); + var arc: squashfs.Archive = try .init(io, fil, offset); //TODO: Handle error gracefully. const options: squashfs.ExtractionOptions = .{ .threads = if (threads == 0) try std.Thread.getCpuCount() else threads, .verbose = verbose, @@ -60,17 +63,17 @@ pub fn main() !void { .ignore_permissions = ignore_permissions, }; if (force) - try std.fs.cwd().deleteTree(extLoc); + try Io.Dir.cwd().deleteTree(io, extLoc); try arc.extract(alloc, extLoc, options); //TODO: Handle error gracefully. } -fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { - var args = try std.process.argsWithAllocator(alloc); - defer args.deinit(); - _ = args.next(); // args[0] is the application launch command. - while (args.next()) |arg| { +fn handleArgs(args: std.process.Args, out: *Writer) !void { + var arg_iter = args.iterate(); + defer arg_iter.deinit(); + _ = arg_iter.next(); // args[0] is the application launch command. + while (arg_iter.next()) |arg| { if (std.mem.eql(u8, arg, "-o")) { - const nxt = args.next(); + const nxt = arg_iter.next(); if (nxt == null or nxt.?.len == 0) { try out.print("-o must be followed by a number\n", .{}); return errors.InvalidArguments; @@ -81,7 +84,7 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { }; continue; } else if (std.mem.eql(u8, arg, "-d")) { - const nxt = args.next(); + const nxt = arg_iter.next(); if (nxt == null or nxt.?.len == 0) { try out.print("-d must be followed by a location\n", .{}); return errors.InvalidArguments; @@ -89,7 +92,7 @@ fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void { extLoc = nxt.?; continue; } else if (std.mem.eql(u8, arg, "-p")) { - const nxt = args.next(); + const nxt = arg_iter.next(); if (nxt == null or nxt.?.len == 0) { try out.print("-p must be followed by a number\n", .{}); return errors.InvalidArguments; diff --git a/src/c_libs.zig b/src/c_libs.zig deleted file mode 100644 index a20cbc0..0000000 --- a/src/c_libs.zig +++ /dev/null @@ -1,7 +0,0 @@ -pub const c = @cImport({ - @cInclude("zlib-ng.h"); - @cInclude("lzo/minilzo.h"); - @cInclude("lz4.h"); - @cInclude("zstd.h"); - @cInclude("lzma.h"); -}); diff --git a/src/decomp/c/lz4.zig b/src/decomp/c/lz4.zig index 928378f..c3b78e6 100644 --- a/src/decomp/c/lz4.zig +++ b/src/decomp/c/lz4.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, diff --git a/src/decomp/c/lzma.zig b/src/decomp/c/lzma.zig index b06afd1..94b8e4a 100644 --- a/src/decomp/c/lzma.zig +++ b/src/decomp/c/lzma.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); const Lzma = @This(); @@ -120,12 +120,12 @@ fn lzmaErrorToDecompError(err: Error) Decompressor.Error { } fn lzmaAlloc(ptr: ?*anyopaque, _: usize, size: usize) callconv(.c) ?*anyopaque { - var alloc: *std.mem.Allocator = @alignCast(@ptrCast(ptr)); + var alloc: *std.mem.Allocator = @ptrCast(@alignCast(ptr)); return alloc.rawAlloc(size, .@"1", 0); } fn lzmaFree(ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) callconv(.c) void { if (alloc_ptr == null) return; - var alloc: *std.mem.Allocator = @alignCast(@ptrCast(ptr)); + var alloc: *std.mem.Allocator = @ptrCast(@alignCast(ptr)); alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0); } diff --git a/src/decomp/c/lzo.zig b/src/decomp/c/lzo.zig index f373e27..a10c1c5 100644 --- a/src/decomp/c/lzo.zig +++ b/src/decomp/c/lzo.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, diff --git a/src/decomp/c/xz.zig b/src/decomp/c/xz.zig index 9d8cb52..f9ed703 100644 --- a/src/decomp/c/xz.zig +++ b/src/decomp/c/xz.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); const Xz = @This(); @@ -120,12 +120,12 @@ fn xzErrorToDecompError(err: Error) Decompressor.Error { } fn lzmaAlloc(ptr: ?*anyopaque, _: usize, size: usize) callconv(.c) ?*anyopaque { - var alloc: *std.mem.Allocator = @alignCast(@ptrCast(ptr)); + var alloc: *std.mem.Allocator = @ptrCast(@alignCast(ptr)); return alloc.rawAlloc(size, .@"1", 0); } fn lzmaFree(ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) callconv(.c) void { if (alloc_ptr == null) return; - var alloc: *std.mem.Allocator = @alignCast(@ptrCast(ptr)); + var alloc: *std.mem.Allocator = @ptrCast(@alignCast(ptr)); alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0); } diff --git a/src/decomp/c/zlib.zig b/src/decomp/c/zlib.zig index 459b69f..531a33b 100644 --- a/src/decomp/c/zlib.zig +++ b/src/decomp/c/zlib.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); const Zlib = @This(); diff --git a/src/decomp/c/zstd.zig b/src/decomp/c/zstd.zig index 9556183..3fb2429 100644 --- a/src/decomp/c/zstd.zig +++ b/src/decomp/c/zstd.zig @@ -1,6 +1,6 @@ const std = @import("std"); -const c = @import("../../c_libs.zig").c; +const c = @import("c"); const Decompressor = @import("../../decomp.zig"); const Zstd = @This(); diff --git a/src/decomp/zig/lzma.zig b/src/decomp/zig/lzma.zig index 4f0a128..64161c9 100644 --- a/src/decomp/zig/lzma.zig +++ b/src/decomp/zig/lzma.zig @@ -7,12 +7,17 @@ const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize { - var rdr: Reader = .static(in); - var decomp = try lzma.decompress(alloc, rdr.adaptToOldInterface()); + var rdr: Reader = .fixed(in); + const buf = try alloc.alloc(u8, in.len); + defer alloc.free(buf); + + var decomp = lzma.Decompress.initOptions(&rdr, alloc, buf, .{}, out.len) catch |err| + return switch (err) { + error.Overflow => Decompressor.Error.ReadFailed, + error.CorruptInput => Decompressor.Error.ReadFailed, + error.InvalidRangeCode => Decompressor.Error.ReadFailed, + else => @errorCast(err), + }; defer decomp.deinit(); - const len = decomp.read(out) catch |err| return switch (err) { - error.CorruptInput, error.EndOfStream, error.Overflow => Decompressor.Error.ReadFailed, - else => err, - }; - return len; + return decomp.reader.readSliceShort(out); } diff --git a/src/decomp/zig/xz.zig b/src/decomp/zig/xz.zig index 72db802..febe468 100644 --- a/src/decomp/zig/xz.zig +++ b/src/decomp/zig/xz.zig @@ -7,17 +7,16 @@ const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize { - var rdr: Reader = .static(in); - var decomp = try xz.decompress(alloc, rdr.adaptToOldInterface()); + var rdr: Reader = .fixed(in); + const buf = try alloc.alloc(u8, in.len); + defer alloc.free(buf); + + var decomp = xz.Decompress.init(&rdr, alloc, buf) catch |err| + return switch (err) { + error.WrongChecksum => Decompressor.Error.ReadFailed, + error.NotXzStream => Decompressor.Error.ReadFailed, + else => @errorCast(err), + }; defer decomp.deinit(); - const len = decomp.read(out) catch |err| return switch (err) { - error.CorruptInput => Decompressor.Error.ReadFailed, - error.EndOfStream => Decompressor.Error.ReadFailed, - error.EndOfStreamWithNoError => Decompressor.Error.ReadFailed, - error.WrongChecksum => Decompressor.Error.ReadFailed, - error.Unsupported => Decompressor.Error.ReadFailed, - error.Overflow => Decompressor.Error.WriteFailed, - else => err, - }; - return len; + return decomp.reader.readSliceShort(out); } diff --git a/src/decomp/zig/zlib.zig b/src/decomp/zig/zlib.zig index 450a777..11e6a46 100644 --- a/src/decomp/zig/zlib.zig +++ b/src/decomp/zig/zlib.zig @@ -7,9 +7,10 @@ const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize { + var rdr: Reader = .fixed(in); const buf = try alloc.alloc(u8, out.len); defer alloc.free(buf); - var rdr: Reader = .static(in); + var decomp = flate.Decompress.init(&rdr, .zlib, buf); return decomp.reader.readSliceShort(out); } diff --git a/src/decomp/zig/zstd.zig b/src/decomp/zig/zstd.zig index 4aec25f..8c195ed 100644 --- a/src/decomp/zig/zstd.zig +++ b/src/decomp/zig/zstd.zig @@ -7,9 +7,10 @@ const Decompressor = @import("../../decomp.zig"); interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } }, pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize { + var rdr: Reader = .fixed(in); const buf = try alloc.alloc(u8, out.len * 2); defer alloc.free(buf); - var rdr: Reader = .static(in); - var decomp = zstd.Decompress.init(&rdr, buf, .{ .window_len = out.len * 2 }); + + var decomp = zstd.Decompress.init(&rdr, buf, .{ .window_len = @truncate(out.len) }); return decomp.reader.readSliceShort(out); } diff --git a/src/file.zig b/src/file.zig index 7baa55b..d1547e0 100644 --- a/src/file.zig +++ b/src/file.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Io = std.Io; const Archive = @import("archive.zig"); const Decompressor = @import("decomp.zig"); diff --git a/src/imports.c b/src/imports.c new file mode 100644 index 0000000..b72f476 --- /dev/null +++ b/src/imports.c @@ -0,0 +1,5 @@ +#include +#include +#include +#include +#include diff --git a/src/util/offset_file.zig b/src/util/offset_file.zig index 312ee5c..4b20a0a 100644 --- a/src/util/offset_file.zig +++ b/src/util/offset_file.zig @@ -1,18 +1,19 @@ const std = @import("std"); -const FileReader = std.fs.File.Reader; +const Io = std.Io; +const FileReader = Io.File.Reader; const OffsetFile = @This(); -fil: std.fs.File, +fil: Io.File, offset: u64 = 0, -pub fn readerAt(self: OffsetFile, offset: u64, buf: []u8) !FileReader { - var rdr = self.fil.reader(buf); +pub fn readerAt(self: OffsetFile, io: Io, offset: u64, buf: []u8) !FileReader { + var rdr = self.fil.reader(io, buf); try rdr.seekTo(self.offset + offset); return rdr; } -pub fn valueAt(self: OffsetFile, comptime T: type, offset: u64) !T { - var rdr = self.fil.reader(&[0]u8{}); +pub fn valueAt(self: OffsetFile, comptime T: type, io: Io, offset: u64) !T { + var rdr = self.fil.reader(io, &[0]u8{}); try rdr.seekTo(self.offset + offset); var new: T = undefined; try rdr.interface.readSliceEndian(T, @ptrCast(&new), .little);