Finished(?) decompression stuff
This commit is contained in:
+6
-8
@@ -1,11 +1,15 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
const DecompTypes = @import("decomp/types.zig");
|
||||||
|
const Decompressor = @import("decomp.zig");
|
||||||
const Inode = @import("inode.zig");
|
const Inode = @import("inode.zig");
|
||||||
|
|
||||||
const Archive = @This();
|
const Archive = @This();
|
||||||
|
|
||||||
super: Superblock,
|
super: Superblock,
|
||||||
|
|
||||||
|
stateless_decomp: Decompressor.StatelessDecomp,
|
||||||
|
|
||||||
pub fn init(fil: std.fs.File, offset: u64) !Archive {
|
pub fn init(fil: std.fs.File, offset: u64) !Archive {
|
||||||
var super: Superblock = undefined;
|
var super: Superblock = undefined;
|
||||||
var fil_rdr = fil.reader(&[0]u8{});
|
var fil_rdr = fil.reader(&[0]u8{});
|
||||||
@@ -16,6 +20,7 @@ pub fn init(fil: std.fs.File, offset: u64) !Archive {
|
|||||||
|
|
||||||
return .{
|
return .{
|
||||||
.super = super,
|
.super = super,
|
||||||
|
.stateless_decomp = DecompTypes.getStatelessFn(super.compression),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,14 +41,7 @@ pub const Superblock = packed struct {
|
|||||||
mod_time: u32,
|
mod_time: u32,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
frag_count: u32,
|
frag_count: u32,
|
||||||
compression: enum(u16) {
|
compression: DecompTypes.Enum,
|
||||||
gzip = 1, // Though officially named gzip, it actually uses zlib.
|
|
||||||
lzma,
|
|
||||||
lzo,
|
|
||||||
xz,
|
|
||||||
lz4,
|
|
||||||
zstd,
|
|
||||||
},
|
|
||||||
block_log: u16,
|
block_log: u16,
|
||||||
flags: packed struct {
|
flags: packed struct {
|
||||||
inode_uncompressed: bool,
|
inode_uncompressed: bool,
|
||||||
|
|||||||
+127
-127
@@ -1,133 +1,133 @@
|
|||||||
// const std = @import("std");
|
const std = @import("std");
|
||||||
// const Writer = std.Io.Writer;
|
const Writer = std.Io.Writer;
|
||||||
// const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
|
||||||
// const config = @import("config");
|
const config = @import("config");
|
||||||
// const squashfs = @import("zig_squashfs");
|
const squashfs = @import("zig_squashfs");
|
||||||
|
|
||||||
// //TODO: Add more options
|
//TODO: Add more options
|
||||||
// const help_mgs =
|
const help_mgs =
|
||||||
// \\
|
\\
|
||||||
// \\Usage: unsquashfs [options] <archive>
|
\\Usage: unsquashfs [options] <archive>
|
||||||
// \\
|
\\
|
||||||
// \\Options:
|
\\Options:
|
||||||
// \\ -d <location> Extract to the given location instead of "squashfs-root"
|
\\ -d <location> Extract to the given location instead of "squashfs-root"
|
||||||
// \\
|
\\
|
||||||
// \\ -o <offset> Start reading the archive at the given offset.
|
\\ -o <offset> Start reading the archive at the given offset.
|
||||||
// \\ -dx Don't set xattr values
|
\\ -dx Don't set xattr values
|
||||||
// \\ -dp Don't set permissions (includes setting uid & gid owner)
|
\\ -dp Don't set permissions (includes setting uid & gid owner)
|
||||||
// \\
|
\\
|
||||||
// \\ -p <threads> Specify how many threads to use. If no present or zero, the system's logical cores count is used.
|
\\ -p <threads> Specify how many threads to use. If no present or zero, the system's logical cores count is used.
|
||||||
// \\ -v Verbose
|
\\ -v Verbose
|
||||||
// \\
|
\\
|
||||||
// \\ --force Force extraction. If the destination already exists, it will be deleted.
|
\\ --force Force extraction. If the destination already exists, it will be deleted.
|
||||||
// \\
|
\\
|
||||||
// \\ --help Display this messages
|
\\ --help Display this messages
|
||||||
// \\ --version Display the version
|
\\ --version Display the version
|
||||||
// \\
|
\\
|
||||||
// ;
|
;
|
||||||
|
|
||||||
// const errors = error{InvalidArguments};
|
const errors = error{InvalidArguments};
|
||||||
|
|
||||||
// var archive: []const u8 = "";
|
var archive: []const u8 = "";
|
||||||
// var extLoc: []const u8 = "squashfs-root";
|
var extLoc: []const u8 = "squashfs-root";
|
||||||
// var offset: u64 = 0;
|
var offset: u64 = 0;
|
||||||
// var threads: u32 = 0;
|
var threads: u32 = 0;
|
||||||
// var verbose: bool = false;
|
var verbose: bool = false;
|
||||||
// var ignore_xattrs: bool = false;
|
var ignore_xattrs: bool = false;
|
||||||
// var ignore_permissions: bool = false;
|
var ignore_permissions: bool = false;
|
||||||
// var force: bool = false;
|
var force: bool = false;
|
||||||
|
|
||||||
// pub fn main() !void {
|
pub fn main() !void {
|
||||||
// const alloc = std.heap.smp_allocator;
|
const alloc = std.heap.smp_allocator;
|
||||||
// var stdout = std.fs.File.stdout();
|
var stdout = std.fs.File.stdout();
|
||||||
// var out = stdout.writer(&[0]u8{});
|
var out = stdout.writer(&[0]u8{});
|
||||||
// defer out.interface.flush() catch {};
|
defer out.interface.flush() catch {};
|
||||||
// try handleArgs(alloc, &out.interface);
|
try handleArgs(alloc, &out.interface);
|
||||||
// if (archive.len == 0) {
|
if (archive.len == 0) {
|
||||||
// try out.interface.print("You must provide a squashfs archive\n", .{});
|
try out.interface.print("You must provide a squashfs archive\n", .{});
|
||||||
// try out.interface.print(help_mgs, .{});
|
try out.interface.print(help_mgs, .{});
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// var fil: std.fs.File = try std.fs.cwd().openFile(archive, .{}); //TODO: Handle error gracefully.
|
var fil: std.fs.File = try std.fs.cwd().openFile(archive, .{}); //TODO: Handle error gracefully.
|
||||||
// defer fil.close();
|
defer fil.close();
|
||||||
// var arc: squashfs.Archive = try .init(fil, offset); //TODO: Update when memory size matters. //TODO: Handle error gracefully.
|
// var arc: squashfs.Archive = try .init(fil, offset); //TODO: Update when memory size matters. //TODO: Handle error gracefully.
|
||||||
// defer arc.deinit();
|
// defer arc.deinit();
|
||||||
// const options: squashfs.ExtractionOptions = .{
|
// const options: squashfs.ExtractionOptions = .{
|
||||||
// .threads = if (threads == 0) try std.Thread.getCpuCount() else threads,
|
// .threads = if (threads == 0) try std.Thread.getCpuCount() else threads,
|
||||||
// .verbose = verbose,
|
// .verbose = verbose,
|
||||||
// .verbose_writer = if (verbose) &out.interface else null,
|
// .verbose_writer = if (verbose) &out.interface else null,
|
||||||
// .ignore_xattr = ignore_xattrs,
|
// .ignore_xattr = ignore_xattrs,
|
||||||
// .ignore_permissions = ignore_permissions,
|
// .ignore_permissions = ignore_permissions,
|
||||||
// };
|
// };
|
||||||
// if (force)
|
// if (force)
|
||||||
// try std.fs.cwd().deleteTree(extLoc);
|
// try std.fs.cwd().deleteTree(extLoc);
|
||||||
// try arc.extract(alloc, extLoc, options); //TODO: Handle error gracefully.
|
// try arc.extract(alloc, extLoc, options); //TODO: Handle error gracefully.
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void {
|
fn handleArgs(alloc: std.mem.Allocator, out: *Writer) !void {
|
||||||
// var args = try std.process.argsWithAllocator(alloc);
|
var args = try std.process.argsWithAllocator(alloc);
|
||||||
// defer args.deinit();
|
defer args.deinit();
|
||||||
// _ = args.next(); // args[0] is the application launch command.
|
_ = args.next(); // args[0] is the application launch command.
|
||||||
// while (args.next()) |arg| {
|
while (args.next()) |arg| {
|
||||||
// if (std.mem.eql(u8, arg, "-o")) {
|
if (std.mem.eql(u8, arg, "-o")) {
|
||||||
// const nxt = args.next();
|
const nxt = args.next();
|
||||||
// if (nxt == null or nxt.?.len == 0) {
|
if (nxt == null or nxt.?.len == 0) {
|
||||||
// try out.print("-o must be followed by a number\n", .{});
|
try out.print("-o must be followed by a number\n", .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// }
|
}
|
||||||
// offset = std.fmt.parseInt(u64, nxt.?, 10) catch {
|
offset = std.fmt.parseInt(u64, nxt.?, 10) catch {
|
||||||
// try out.print("-o must be followed by a number\n", .{});
|
try out.print("-o must be followed by a number\n", .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// };
|
};
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "-d")) {
|
} else if (std.mem.eql(u8, arg, "-d")) {
|
||||||
// const nxt = args.next();
|
const nxt = args.next();
|
||||||
// if (nxt == null or nxt.?.len == 0) {
|
if (nxt == null or nxt.?.len == 0) {
|
||||||
// try out.print("-d must be followed by a location\n", .{});
|
try out.print("-d must be followed by a location\n", .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// }
|
}
|
||||||
// extLoc = nxt.?;
|
extLoc = nxt.?;
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "-p")) {
|
} else if (std.mem.eql(u8, arg, "-p")) {
|
||||||
// const nxt = args.next();
|
const nxt = args.next();
|
||||||
// if (nxt == null or nxt.?.len == 0) {
|
if (nxt == null or nxt.?.len == 0) {
|
||||||
// try out.print("-p must be followed by a number\n", .{});
|
try out.print("-p must be followed by a number\n", .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// }
|
}
|
||||||
// threads = std.fmt.parseInt(u32, nxt.?, 10) catch {
|
threads = std.fmt.parseInt(u32, nxt.?, 10) catch {
|
||||||
// try out.print("-p must be followed by a number\n", .{});
|
try out.print("-p must be followed by a number\n", .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// };
|
};
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "-v")) {
|
} else if (std.mem.eql(u8, arg, "-v")) {
|
||||||
// verbose = true;
|
verbose = true;
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "-dx")) {
|
} else if (std.mem.eql(u8, arg, "-dx")) {
|
||||||
// ignore_xattrs = true;
|
ignore_xattrs = true;
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "-dp")) {
|
} else if (std.mem.eql(u8, arg, "-dp")) {
|
||||||
// ignore_permissions = true;
|
ignore_permissions = true;
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "--force")) {
|
} else if (std.mem.eql(u8, arg, "--force")) {
|
||||||
// force = true;
|
force = true;
|
||||||
// continue;
|
continue;
|
||||||
// } else if (std.mem.eql(u8, arg, "--version")) {
|
} else if (std.mem.eql(u8, arg, "--version")) {
|
||||||
// try out.print("zig-unsquashfs v", .{});
|
try out.print("zig-unsquashfs v", .{});
|
||||||
// try config.version.format(out);
|
try config.version.format(out);
|
||||||
// try out.print("\nBuilt using Zig {s} in {} mode\n", .{ builtin.zig_version_string, builtin.mode });
|
try out.print("\nBuilt using Zig {s} in {} mode\n", .{ builtin.zig_version_string, builtin.mode });
|
||||||
// std.process.exit(0);
|
std.process.exit(0);
|
||||||
// return;
|
return;
|
||||||
// } else if (std.mem.eql(u8, arg, "--help")) {
|
} else if (std.mem.eql(u8, arg, "--help")) {
|
||||||
// try out.print(help_mgs, .{});
|
try out.print(help_mgs, .{});
|
||||||
// std.process.exit(0);
|
std.process.exit(0);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// if (archive.len > 0) {
|
if (archive.len > 0) {
|
||||||
// try out.print("you can only provide one file at a time\n", .{});
|
try out.print("you can only provide one file at a time\n", .{});
|
||||||
// try out.print(help_mgs, .{});
|
try out.print(help_mgs, .{});
|
||||||
// return errors.InvalidArguments;
|
return errors.InvalidArguments;
|
||||||
// }
|
}
|
||||||
// archive = arg;
|
archive = arg;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,5 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const StatelessDecomp = *const fn (std.mem.Allocator, in: []u8, out: []u8) Error!usize;
|
||||||
|
|
||||||
pub const Error = error{
|
pub const Error = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
EndOfStream,
|
EndOfStream,
|
||||||
@@ -11,14 +13,17 @@ const Decompressor = @This();
|
|||||||
|
|
||||||
alloc: std.mem.Allocator = std.heap.page_allocator,
|
alloc: std.mem.Allocator = std.heap.page_allocator,
|
||||||
vtable: *struct {
|
vtable: *struct {
|
||||||
decompress: *const fn (*Decompressor, in: []u8, out: []u8) Error!usize = defaultDecompress,
|
decompress: *const fn (*const Decompressor, in: []u8, out: []u8) Error!usize = defaultDecompress,
|
||||||
stateless: *const fn (std.mem.Allocator, in: []u8, out: []u8) Error!usize,
|
stateless: StatelessDecomp,
|
||||||
},
|
},
|
||||||
|
|
||||||
pub fn decompress(self: *Decompressor, in: []u8, out: []u8) Error!usize {
|
pub fn decompress(self: *const Decompressor, in: []u8, out: []u8) Error!usize {
|
||||||
return self.vtable.decompress(self, in, out);
|
return self.vtable.decompress(self, in, out);
|
||||||
}
|
}
|
||||||
|
pub fn stateless(self: Decompressor, alloc: std.mem.Allocator, in: []u8, out: []u8) Error!usize {
|
||||||
|
return self.vtable.stateless(alloc, in, out);
|
||||||
|
}
|
||||||
|
|
||||||
fn defaultDecompress(self: *Decompressor, in: []u8, out: []u8) Error!usize {
|
fn defaultDecompress(self: *const Decompressor, in: []u8, out: []u8) Error!usize {
|
||||||
return self.vtable.stateless(self.alloc, in, out);
|
return self.vtable.stateless(self.alloc, in, out);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const c = @import("../../c_libs.zig").c;
|
||||||
|
const Decompressor = @import("../../decomp.zig");
|
||||||
|
|
||||||
|
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
||||||
|
|
||||||
|
pub fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
|
const res = c.LZ4_decompress_safe(in.ptr, out.ptr, in.len, out.len);
|
||||||
|
if (res > 0) return @abs(res);
|
||||||
|
return Decompressor.Error.ReadFailed; // TOOD: Find out what errors can be returned.
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const c = @import("../../c_libs.zig").c;
|
||||||
|
const Decompressor = @import("../../decomp.zig");
|
||||||
|
|
||||||
|
const Lzma = @This();
|
||||||
|
|
||||||
|
streams: std.AutoHashMap(std.Thread.Id, c.lzma_stream),
|
||||||
|
|
||||||
|
interface: Decompressor,
|
||||||
|
|
||||||
|
err: ?Error = null,
|
||||||
|
|
||||||
|
pub fn init(alloc: std.mem.Allocator) !Lzma {
|
||||||
|
return .{
|
||||||
|
.streams = try .init(alloc),
|
||||||
|
.interface = &.{
|
||||||
|
.alloc = alloc,
|
||||||
|
.vtable = .{ .decompress = decompress, .stateless = stateless },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *Lzma) void {
|
||||||
|
var values = self.streams.valueIterator();
|
||||||
|
while (values.next()) |val| {
|
||||||
|
c.lzma_end(val);
|
||||||
|
}
|
||||||
|
self.streams.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn getOrCreate(self: *Lzma) !*c.lzma_stream {
|
||||||
|
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||||
|
if (res.found_existing) return res.value_ptr;
|
||||||
|
res.value_ptr.* = .{
|
||||||
|
.alloc = .{
|
||||||
|
.alloc = lzmaAlloc,
|
||||||
|
.free = lzmaFree,
|
||||||
|
.@"opaque" = &self.interface.alloc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return res.value_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decompress(decomp: *const Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
|
var self: *Lzma = @fieldParentPtr("interface", decomp);
|
||||||
|
|
||||||
|
const stream = try self.getOrCreate();
|
||||||
|
stream.next_in = in.ptr;
|
||||||
|
stream.avail_in = in.len;
|
||||||
|
stream.next_out = out.ptr;
|
||||||
|
stream.avail_out = out.len;
|
||||||
|
var res = c.lzma_alone_decoder(stream, out.len, 0);
|
||||||
|
decodeResult(res) catch |err| {
|
||||||
|
self.err = err;
|
||||||
|
lzmaErrorToDecompError(err);
|
||||||
|
};
|
||||||
|
while (true) {
|
||||||
|
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||||
|
if (res == c.LZMA_OK) continue;
|
||||||
|
if (res == c.LZMA_STREAM_END) break;
|
||||||
|
decodeResult(res) catch |err| {
|
||||||
|
self.err = err;
|
||||||
|
lzmaErrorToDecompError(err);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
|
var stream: c.lzma_stream = .{
|
||||||
|
.next_in = in.ptr,
|
||||||
|
.avail_in = in.len,
|
||||||
|
.next_out = out.ptr,
|
||||||
|
.avail_out = out.len,
|
||||||
|
.allocator = .{
|
||||||
|
.alloc = lzmaAlloc,
|
||||||
|
.free = lzmaFree,
|
||||||
|
.@"opaque" = &alloc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var res = c.lzma_alone_decoder(&stream, out.len, 0);
|
||||||
|
decodeResult(res) catch |err| lzmaErrorToDecompError(err);
|
||||||
|
while (true) {
|
||||||
|
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||||
|
if (res == c.LZMA_OK) continue;
|
||||||
|
if (res == c.LZMA_STREAM_END) break;
|
||||||
|
decodeResult(res) catch |err| lzmaErrorToDecompError(err);
|
||||||
|
}
|
||||||
|
return stream.total_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn decodeResult(res: c_uint) Error!void {
|
||||||
|
return switch (res) {
|
||||||
|
c.LZMA_OK => {},
|
||||||
|
c.LZMA_STREAM_END => {},
|
||||||
|
c.LZMA_NO_CHECK => {},
|
||||||
|
c.LZMA_UNSUPPORTED_CHECK => Error.UnsupportedCheck,
|
||||||
|
c.LZMA_MEM_ERROR => Error.OutOfMemory,
|
||||||
|
c.LZMA_MEMLIMIT_ERROR => Error.OutOfMemory,
|
||||||
|
c.LZMA_FORMAT_ERROR => Error.Format,
|
||||||
|
c.LZMA_OPTIONS_ERROR => Error.Options,
|
||||||
|
c.LZMA_DATA_ERROR => Error.Data,
|
||||||
|
c.LZMA_BUF_ERROR => Error.BufferExhausted,
|
||||||
|
c.LZMA_PROG_ERROR => Error.Programming,
|
||||||
|
c.LZMA_SEEK_NEEDED => Error.SeekNeeded,
|
||||||
|
else => Error.Unknown,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
fn lzmaErrorToDecompError(err: Error) Decompressor.Error {
|
||||||
|
switch (err) {
|
||||||
|
Error.OutOfMemory => return err,
|
||||||
|
Error.UnsupportedCheck => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.Format => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.Options => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.Data => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.BufferExhausted => return Decompressor.Error.WriteFailed,
|
||||||
|
Error.Programming => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.SeekNeeded => return Decompressor.Error.ReadFailed,
|
||||||
|
Error.Unknown => return Decompressor.Error.ReadFailed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lzmaAlloc(ptr: ?*anyopaque, _: usize, size: usize) callconv(.c) ?*anyopaque {
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(ptr);
|
||||||
|
return alloc.rawAlloc(size, .@"1", 0) catch return null;
|
||||||
|
}
|
||||||
|
fn lzmaFree(ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) callconv(.c) void {
|
||||||
|
if (alloc_ptr == null) return;
|
||||||
|
var alloc: *std.mem.Allocator = @ptrCast(ptr);
|
||||||
|
alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Error = error{
|
||||||
|
OutOfMemory,
|
||||||
|
UnsupportedCheck,
|
||||||
|
Format,
|
||||||
|
Options,
|
||||||
|
Data,
|
||||||
|
BufferExhausted,
|
||||||
|
Programming,
|
||||||
|
SeekNeeded,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const c = @import("../../c_libs.zig").c;
|
||||||
|
const Decompressor = @import("../../decomp.zig");
|
||||||
|
|
||||||
|
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
||||||
|
|
||||||
|
pub fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
|
var out_len = out.len;
|
||||||
|
const 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 => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_OUT_OF_MEMORY => Decompressor.Error.OutOfMemory,
|
||||||
|
c.LZO_E_NOT_COMPRESSIBLE => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_INPUT_OVERRUN => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_OUTPUT_OVERRUN => Decompressor.Error.WriteFailed,
|
||||||
|
c.LZO_E_LOOKBEHIND_OVERRUN => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_EOF_NOT_FOUND => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_INPUT_NOT_CONSUMED => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_NOT_YET_IMPLEMENTED => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_INVALID_ARGUMENT => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_INVALID_ALIGNMENT => Decompressor.Error.ReadFailed,
|
||||||
|
c.LZO_E_OUTPUT_NOT_CONSUMED => Decompressor.Error.WriteFailed,
|
||||||
|
c.LZO_E_INTERNAL_ERROR => Decompressor.Error.ReadFailed,
|
||||||
|
else => Decompressor.Error.ReadFailed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
+17
-4
@@ -20,6 +20,13 @@ pub fn init(alloc: std.mem.Allocator) !Xz {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn deinit(self: *Xz) void {
|
||||||
|
var values = self.streams.valueIterator();
|
||||||
|
while (values.next()) |val| {
|
||||||
|
c.lzma_end(val);
|
||||||
|
}
|
||||||
|
self.streams.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
fn getOrCreate(self: *Xz) !*c.lzma_stream {
|
fn getOrCreate(self: *Xz) !*c.lzma_stream {
|
||||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||||
@@ -34,7 +41,7 @@ fn getOrCreate(self: *Xz) !*c.lzma_stream {
|
|||||||
return res.value_ptr;
|
return res.value_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
fn decompress(decomp: *const Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
var self: *Xz = @fieldParentPtr("interface", decomp);
|
var self: *Xz = @fieldParentPtr("interface", decomp);
|
||||||
|
|
||||||
const stream = try self.getOrCreate();
|
const stream = try self.getOrCreate();
|
||||||
@@ -43,16 +50,22 @@ fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usi
|
|||||||
stream.next_out = out.ptr;
|
stream.next_out = out.ptr;
|
||||||
stream.avail_out = out.len;
|
stream.avail_out = out.len;
|
||||||
var res = c.lzma_stream_decoder(stream, out.len, 0);
|
var res = c.lzma_stream_decoder(stream, out.len, 0);
|
||||||
decodeResult(res) catch |err| xzErrorToDecompError(err);
|
decodeResult(res) catch |err| {
|
||||||
|
self.err = err;
|
||||||
|
xzErrorToDecompError(err);
|
||||||
|
};
|
||||||
while (true) {
|
while (true) {
|
||||||
res = c.lzma_code(&stream, c.LZMA_RUN);
|
res = c.lzma_code(&stream, c.LZMA_RUN);
|
||||||
if (res == c.LZMA_OK) continue;
|
if (res == c.LZMA_OK) continue;
|
||||||
if (res == c.LZMA_STREAM_END) break;
|
if (res == c.LZMA_STREAM_END) break;
|
||||||
decodeResult(res) catch |err| xzErrorToDecompError(err);
|
decodeResult(res) catch |err| {
|
||||||
|
self.err = err;
|
||||||
|
xzErrorToDecompError(err);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return stream.total_out;
|
return stream.total_out;
|
||||||
}
|
}
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
var stream: c.lzma_stream = .{
|
var stream: c.lzma_stream = .{
|
||||||
.next_in = in.ptr,
|
.next_in = in.ptr,
|
||||||
.avail_in = in.len,
|
.avail_in = in.len,
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ pub fn init(alloc: std.mem.Allocator) !Zlib {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn deinit(self: *Zlib) void {
|
||||||
|
var values = self.streams.valueIterator();
|
||||||
|
while (values.next()) |val| {
|
||||||
|
_ = c.zng_deflateEnd(val);
|
||||||
|
}
|
||||||
|
self.streams.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
fn getOrCreate(self: *Zlib) !*c.zng_stream {
|
fn getOrCreate(self: *Zlib) !*c.zng_stream {
|
||||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||||
@@ -32,7 +39,7 @@ fn getOrCreate(self: *Zlib) !*c.zng_stream {
|
|||||||
return res.value_ptr;
|
return res.value_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
fn decompress(decomp: *const Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
var self: *Zlib = @fieldParentPtr("interface", decomp);
|
var self: *Zlib = @fieldParentPtr("interface", decomp);
|
||||||
|
|
||||||
var stream = try self.getOrCreate();
|
var stream = try self.getOrCreate();
|
||||||
@@ -55,7 +62,7 @@ fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
_ = alloc;
|
_ = alloc;
|
||||||
var out_len = out.len;
|
var out_len = out.len;
|
||||||
const res = c.zng_uncompress(out.ptr, &out_len, in.ptr, in.len);
|
const res = c.zng_uncompress(out.ptr, &out_len, in.ptr, in.len);
|
||||||
|
|||||||
@@ -20,6 +20,13 @@ pub fn init(alloc: std.mem.Allocator) !Zstd {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn deinit(self: *Zstd) void {
|
||||||
|
var values = self.context.valueIterator();
|
||||||
|
while (values.next()) |val| {
|
||||||
|
_ = c.ZSTD_freeDCtx(val.*);
|
||||||
|
}
|
||||||
|
self.context.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
fn getOrCreate(self: *Zstd) !*c.ZSTD_DCtx {
|
fn getOrCreate(self: *Zstd) !*c.ZSTD_DCtx {
|
||||||
const res = try self.context.getOrPut(std.Thread.getCurrentId());
|
const res = try self.context.getOrPut(std.Thread.getCurrentId());
|
||||||
@@ -29,7 +36,7 @@ fn getOrCreate(self: *Zstd) !*c.ZSTD_DCtx {
|
|||||||
return res.value_ptr;
|
return res.value_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
fn decompress(decomp: *const Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
var self: *Zstd = @fieldParentPtr("interface", decomp);
|
var self: *Zstd = @fieldParentPtr("interface", decomp);
|
||||||
|
|
||||||
const ctx = self.getOrCreate();
|
const ctx = self.getOrCreate();
|
||||||
@@ -40,7 +47,7 @@ fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usi
|
|||||||
};
|
};
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
_ = alloc;
|
_ = alloc;
|
||||||
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||||
decodeError(res) catch |err| return ZstdErrorToDecompError(err);
|
decodeError(res) catch |err| return ZstdErrorToDecompError(err);
|
||||||
|
|||||||
+62
-6
@@ -1,8 +1,64 @@
|
|||||||
const config = @import("config");
|
const config = @import("config");
|
||||||
|
|
||||||
const Zlib = if (config.use_zig_decomp) @import("zig/zlib.zig") else @import("c/zlib.zig");
|
const Decompressor = @import("../decomp.zig");
|
||||||
const Lzma = if (config.use_zig_decomp) @import("zig/lzma.zig") else @import("c/lzma.zig");
|
|
||||||
const Lzo = if (config.use_zig_decomp) void else @import("c/lzo.zig");
|
pub fn getStatelessFn(decomp: Enum) !Decompressor.StatelessDecomp {
|
||||||
const Xz = if (config.use_zig_decomp) @import("zig/xz.zig") else @import("c/xz.zig");
|
if (config.use_zig_decomp) {
|
||||||
const Lz4 = if (config.use_zig_decomp) void else @import("c/lz4.zig");
|
return switch (decomp) {
|
||||||
const Zstd = if (config.use_zig_decomp) @import("zig/zstd.zig") else @import("c/zstd.zig");
|
.gzip => @import("zig/zlib.zig").stateless,
|
||||||
|
.lzma => @import("zig/lzma.zig").stateless,
|
||||||
|
.xz => @import("zig/xz.zig").stateless,
|
||||||
|
.zstd => @import("zig/zstd.zig").stateless,
|
||||||
|
.lz4 => error.ZigLz4Unsupported,
|
||||||
|
.lzo => error.ZigLzoUnsupported,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return switch (decomp) {
|
||||||
|
.gzip => @import("c/zlib.zig").stateless,
|
||||||
|
.lzma => @import("c/lzma.zig").stateless,
|
||||||
|
.lzo => @import("c/lzo.zig").stateless,
|
||||||
|
.xz => @import("c/xz.zig").stateless,
|
||||||
|
.lz4 => @import("c/lz4.zig").stateless,
|
||||||
|
.zstd => @import("c/zstd.zig").stateless,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Enum = enum(u16) {
|
||||||
|
gzip = 1, // Though officially named gzip, it actually uses zlib.
|
||||||
|
lzma,
|
||||||
|
lzo,
|
||||||
|
xz,
|
||||||
|
lz4,
|
||||||
|
zstd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Decomp = if (config.use_zig_decomp)
|
||||||
|
union(enum) {
|
||||||
|
gzip: @import("zig/zlib.zig"),
|
||||||
|
lzma: @import("zig/lzma.zig"),
|
||||||
|
xz: @import("zig/xz.zig"),
|
||||||
|
zstd: @import("zig/zstd.zig"),
|
||||||
|
|
||||||
|
pub fn deinit(_: *Decomp) void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
union(enum) {
|
||||||
|
gzip: @import("c/zlib.zig"),
|
||||||
|
lzma: @import("c/lzma.zig"),
|
||||||
|
lzo: @import("c/lzo.zig"),
|
||||||
|
xz: @import("c/xz.zig"),
|
||||||
|
lz4: @import("c/lz4.zig"),
|
||||||
|
zstd: @import("c/zstd.zig"),
|
||||||
|
|
||||||
|
pub fn deinit(self: *Decomp) void {
|
||||||
|
switch (self) {
|
||||||
|
.gzip => self.gzip.deinit(),
|
||||||
|
.lzma => self.lzma.deinit(),
|
||||||
|
.xz => self.xz.deinit(),
|
||||||
|
.zstd => self.zstd.deinit(),
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const lzma = std.compress.lzma;
|
||||||
|
const Reader = std.Io.Reader;
|
||||||
|
|
||||||
|
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());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
+14
-1
@@ -6,5 +6,18 @@ const Decompressor = @import("../../decomp.zig");
|
|||||||
|
|
||||||
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
||||||
|
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
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());
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Decompressor = @import("../../decomp.zig");
|
|||||||
|
|
||||||
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
||||||
|
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
const buf = try alloc.alloc(u8, out.len);
|
const buf = try alloc.alloc(u8, out.len);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
var rdr: Reader = .static(in);
|
var rdr: Reader = .static(in);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Decompressor = @import("../../decomp.zig");
|
|||||||
|
|
||||||
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
interface: Decompressor = .{ .vtable = .{ .stateless = stateless } },
|
||||||
|
|
||||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||||
const buf = try alloc.alloc(u8, out.len * 2);
|
const buf = try alloc.alloc(u8, out.len * 2);
|
||||||
defer alloc.free(buf);
|
defer alloc.free(buf);
|
||||||
var rdr: Reader = .static(in);
|
var rdr: Reader = .static(in);
|
||||||
|
|||||||
Reference in New Issue
Block a user