Compare commits
1 Commits
re-do_again
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 4b2b7021c7 |
+8
-24
@@ -30,24 +30,7 @@ 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),
|
||||
};
|
||||
}
|
||||
},
|
||||
decomp: @import("decomp/types.zig").Decomp,
|
||||
|
||||
/// 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 {
|
||||
@@ -63,16 +46,16 @@ pub fn init(alloc: std.mem.Allocator, fil: File, offset: u64) !Archive {
|
||||
switch (super.compression) {
|
||||
.lz4 => return error.Lz4Unsupported,
|
||||
.lzo => return error.LzoUnsupported,
|
||||
.gzip => Decomp.gzip,
|
||||
.lzma => Decomp.lzma,
|
||||
.xz => Decomp.xz,
|
||||
.zstd => Decomp.zstd,
|
||||
.gzip => .{ .gzip = .{} },
|
||||
.lzma => .{ .lzma = .{} },
|
||||
.xz => .{ .xz = .{} },
|
||||
.zstd => .{ .zstd = .{} },
|
||||
}
|
||||
else switch (super.compression) {
|
||||
.gzip => .{ .gzip = .init(alloc) },
|
||||
.zstd => .{ .zstd = .init(alloc) },
|
||||
.xz => .{ .xz = .init(alloc, true) },
|
||||
.lzma => .{ .lzma = .init(alloc, false) },
|
||||
.xz => .{ .xz = .init(alloc) },
|
||||
.lzma => .{ .lzma = .init(alloc) },
|
||||
.lzo => .{ .lzo = .{} },
|
||||
.lz4 => .{ .lz4 = .{} },
|
||||
},
|
||||
@@ -82,6 +65,7 @@ pub fn init(alloc: std.mem.Allocator, fil: File, offset: u64) !Archive {
|
||||
pub fn deinit(self: *Archive) void {
|
||||
if (self.tables != null)
|
||||
self.tables.?.deinit();
|
||||
self.decomp.deinit();
|
||||
}
|
||||
|
||||
pub fn inode(self: *Archive, alloc: std.mem.Allocator, num: u32) !Inode {
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
const std = @import("std");
|
||||
const Reader = std.Io.Reader;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const config = @import("config");
|
||||
|
||||
pub const c = @cImport({
|
||||
@cInclude("zlib-ng.h");
|
||||
@cInclude("lzma.h");
|
||||
@@ -0,0 +1,14 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const res = c.LZ4_decompress_fast(in.ptr, out.ptr, @intCast(out.len));
|
||||
if (res < 0) return Decompressor.Error.ReadFailed;
|
||||
return @abs(res);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
streams: std.AutoHashMap(std.Thread.Id, c.lzma_stream),
|
||||
|
||||
interface: Decompressor,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.streams = .init(alloc),
|
||||
.interface = .{
|
||||
.vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.streams.deinit();
|
||||
}
|
||||
|
||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
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 = c.lzma_alone_decoder(strm, out.len * 2);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(strm, c.LZMA_RUN);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var strm: c.lzma_stream = .{
|
||||
.allocator = &.{
|
||||
.alloc = lzmaAlloc,
|
||||
.free = lzmaFree,
|
||||
.@"opaque" = @ptrCast(@constCast(&alloc)),
|
||||
},
|
||||
.next_in = in.ptr,
|
||||
.avail_in = in.len,
|
||||
.next_out = out.ptr,
|
||||
.avail_out = out.len,
|
||||
};
|
||||
var res = c.lzma_alone_decoder(&strm, out.len * 2);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(&strm, c.LZMA_RUN);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
|
||||
inline fn getOrCreate(self: *Self) !*c.lzma_stream {
|
||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) return res.value_ptr;
|
||||
res.value_ptr.* = .{ .allocator = &.{
|
||||
.alloc = lzmaAlloc,
|
||||
.free = lzmaFree,
|
||||
.@"opaque" = @ptrCast(&self.alloc),
|
||||
} };
|
||||
return res.value_ptr;
|
||||
}
|
||||
inline fn decodeResult(res: usize) Error!void {
|
||||
return switch (res) {
|
||||
c.LZMA_OK, c.LZMA_STREAM_END => {},
|
||||
c.LZMA_NO_CHECK => Error.NoCheck,
|
||||
c.LZMA_UNSUPPORTED_CHECK => Error.UnsupportedCheck,
|
||||
c.LZMA_GET_CHECK => Error.GetCheck,
|
||||
c.LZMA_MEM_ERROR, 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.Buffer,
|
||||
c.LZMA_PROG_ERROR => Error.Program,
|
||||
c.LZMA_SEEK_NEEDED => Error.SeekNeeded,
|
||||
else => Error.Unknown,
|
||||
};
|
||||
}
|
||||
inline fn lzmaErrToDecompErr(err: Error) Decompressor.Error {
|
||||
return switch (err) {
|
||||
Error.OutOfMemory => Decompressor.Error.OutOfMemory,
|
||||
Error.NoCheck => Decompressor.Error.ReadFailed,
|
||||
Error.UnsupportedCheck => Decompressor.Error.ReadFailed,
|
||||
Error.GetCheck => Decompressor.Error.ReadFailed,
|
||||
Error.Format => Decompressor.Error.ReadFailed,
|
||||
Error.Options => Decompressor.Error.ReadFailed,
|
||||
Error.Data => Decompressor.Error.ReadFailed,
|
||||
Error.Buffer => Decompressor.Error.WriteFailed,
|
||||
Error.Program => Decompressor.Error.ReadFailed,
|
||||
Error.SeekNeeded => Decompressor.Error.ReadFailed,
|
||||
else => Decompressor.Error.ReadFailed,
|
||||
};
|
||||
}
|
||||
|
||||
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
return alloc.rawAlloc(size, .@"1", 0);
|
||||
}
|
||||
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||
}
|
||||
|
||||
const Error = error{
|
||||
OutOfMemory,
|
||||
NoCheck,
|
||||
UnsupportedCheck,
|
||||
GetCheck,
|
||||
Format,
|
||||
Options,
|
||||
Data,
|
||||
Buffer,
|
||||
Program,
|
||||
SeekNeeded,
|
||||
Unknown,
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var out_len: usize = out.len;
|
||||
const res = c.lzo1x_decompress(in.ptr, in.len, out.ptr, &out_len, null);
|
||||
decodeError(res) catch |err| return lzoErrToDecompErr(err);
|
||||
return out_len;
|
||||
}
|
||||
|
||||
inline fn decodeError(res: c_int) Error!void {
|
||||
return switch (res) {
|
||||
c.LZO_E_OK => {},
|
||||
c.LZO_E_EOF_NOT_FOUND => Error.EofNotFound,
|
||||
c.LZO_E_INPUT_NOT_CONSUMED => Error.InputNotConsumed,
|
||||
c.LZO_E_INPUT_OVERRUN => Error.InputOverrun,
|
||||
c.LZO_E_INTERNAL_ERROR => Error.InternalError,
|
||||
c.LZO_E_INVALID_ALIGNMENT => Error.InvalidAlignment,
|
||||
c.LZO_E_INVALID_ARGUMENT => Error.InvalidArgument,
|
||||
c.LZO_E_LOOKBEHIND_OVERRUN => Error.LookbehindOverrun,
|
||||
c.LZO_E_NOT_COMPRESSIBLE => Error.NotCompressible,
|
||||
c.LZO_E_NOT_YET_IMPLEMENTED => Error.NotYetImplemented,
|
||||
c.LZO_E_OUTPUT_NOT_CONSUMED => Error.OutputNotConsumed,
|
||||
c.LZO_E_OUTPUT_OVERRUN => Error.OutputOverrun,
|
||||
c.LZO_E_OUT_OF_MEMORY => Error.OutOfMemory,
|
||||
else => Error.Unknown,
|
||||
};
|
||||
}
|
||||
inline fn lzoErrToDecompErr(err: Error) Decompressor.Error {
|
||||
return switch (err) {
|
||||
Error.EofNotFound => Decompressor.Error.ReadFailed,
|
||||
Error.InputNotConsumed => Decompressor.Error.ReadFailed,
|
||||
Error.InputOverrun => Decompressor.Error.ReadFailed,
|
||||
Error.InternalError => Decompressor.Error.ReadFailed,
|
||||
Error.InvalidAlignment => Decompressor.Error.ReadFailed,
|
||||
Error.InvalidArgument => Decompressor.Error.ReadFailed,
|
||||
Error.LookbehindOverrun => Decompressor.Error.ReadFailed,
|
||||
Error.NotCompressible => Decompressor.Error.ReadFailed,
|
||||
Error.NotYetImplemented => Decompressor.Error.ReadFailed,
|
||||
Error.OutputNotConsumed => Decompressor.Error.WriteFailed,
|
||||
Error.OutputOverrun => Decompressor.Error.WriteFailed,
|
||||
Error.OutOfMemory => Decompressor.Error.OutOfMemory,
|
||||
else => Decompressor.Error.ReadFailed,
|
||||
};
|
||||
}
|
||||
|
||||
const Error = error{
|
||||
EofNotFound,
|
||||
InputNotConsumed,
|
||||
InputOverrun,
|
||||
InternalError,
|
||||
InvalidAlignment,
|
||||
InvalidArgument,
|
||||
LookbehindOverrun,
|
||||
NotCompressible,
|
||||
NotYetImplemented,
|
||||
OutputNotConsumed,
|
||||
OutputOverrun,
|
||||
OutOfMemory,
|
||||
Unknown,
|
||||
};
|
||||
@@ -0,0 +1,127 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
streams: std.AutoHashMap(std.Thread.Id, c.lzma_stream),
|
||||
|
||||
interface: Decompressor,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.streams = .init(alloc),
|
||||
.interface = .{
|
||||
.vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.streams.deinit();
|
||||
}
|
||||
|
||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
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 = c.lzma_stream_decoder(strm, out.len * 2, 0);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(strm, c.LZMA_RUN);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var strm: c.lzma_stream = .{
|
||||
.allocator = &.{
|
||||
.alloc = lzmaAlloc,
|
||||
.free = lzmaFree,
|
||||
.@"opaque" = @ptrCast(@constCast(&alloc)),
|
||||
},
|
||||
.next_in = in.ptr,
|
||||
.avail_in = in.len,
|
||||
.next_out = out.ptr,
|
||||
.avail_out = out.len,
|
||||
};
|
||||
var res = c.lzma_stream_decoder(&strm, out.len * 2, 0);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(&strm, c.LZMA_RUN);
|
||||
decodeResult(res) catch |err| return lzmaErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
|
||||
inline fn getOrCreate(self: *Self) !*c.lzma_stream {
|
||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) return res.value_ptr;
|
||||
res.value_ptr.* = .{ .allocator = &.{
|
||||
.alloc = lzmaAlloc,
|
||||
.free = lzmaFree,
|
||||
.@"opaque" = @ptrCast(&self.alloc),
|
||||
} };
|
||||
return res.value_ptr;
|
||||
}
|
||||
inline fn decodeResult(res: usize) Error!void {
|
||||
return switch (res) {
|
||||
c.LZMA_OK, c.LZMA_STREAM_END => {},
|
||||
c.LZMA_NO_CHECK => Error.NoCheck,
|
||||
c.LZMA_UNSUPPORTED_CHECK => Error.UnsupportedCheck,
|
||||
c.LZMA_GET_CHECK => Error.GetCheck,
|
||||
c.LZMA_MEM_ERROR, 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.Buffer,
|
||||
c.LZMA_PROG_ERROR => Error.Program,
|
||||
c.LZMA_SEEK_NEEDED => Error.SeekNeeded,
|
||||
else => Error.Unknown,
|
||||
};
|
||||
}
|
||||
inline fn lzmaErrToDecompErr(err: Error) Decompressor.Error {
|
||||
return switch (err) {
|
||||
Error.OutOfMemory => Decompressor.Error.OutOfMemory,
|
||||
Error.NoCheck => Decompressor.Error.ReadFailed,
|
||||
Error.UnsupportedCheck => Decompressor.Error.ReadFailed,
|
||||
Error.GetCheck => Decompressor.Error.ReadFailed,
|
||||
Error.Format => Decompressor.Error.ReadFailed,
|
||||
Error.Options => Decompressor.Error.ReadFailed,
|
||||
Error.Data => Decompressor.Error.ReadFailed,
|
||||
Error.Buffer => Decompressor.Error.WriteFailed,
|
||||
Error.Program => Decompressor.Error.ReadFailed,
|
||||
Error.SeekNeeded => Decompressor.Error.ReadFailed,
|
||||
else => Decompressor.Error.ReadFailed,
|
||||
};
|
||||
}
|
||||
|
||||
fn lzmaAlloc(ptr: ?*anyopaque, size: usize, _: usize) callconv(.c) ?*anyopaque {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
return alloc.rawAlloc(size, .@"1", 0);
|
||||
}
|
||||
fn lzmaFree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||
}
|
||||
|
||||
const Error = error{
|
||||
OutOfMemory,
|
||||
NoCheck,
|
||||
UnsupportedCheck,
|
||||
GetCheck,
|
||||
Format,
|
||||
Options,
|
||||
Data,
|
||||
Buffer,
|
||||
Program,
|
||||
SeekNeeded,
|
||||
Unknown,
|
||||
};
|
||||
@@ -0,0 +1,112 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
streams: std.AutoHashMap(std.Thread.Id, c.zng_stream),
|
||||
|
||||
interface: Decompressor,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.streams = .init(alloc),
|
||||
.interface = .{
|
||||
.vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.streams.deinit();
|
||||
}
|
||||
|
||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
var strm = try self.getOrCreate();
|
||||
strm.next_in = in.ptr;
|
||||
strm.avail_in = @truncate(in.len);
|
||||
strm.next_out = out.ptr;
|
||||
strm.total_out = out.len;
|
||||
var res = c.zng_inflateReset(strm);
|
||||
decodeError(res) catch |err| return zlibErrToDecompErr(err);
|
||||
|
||||
res = c.zng_inflate(strm, c.Z_FULL_FLUSH);
|
||||
decodeError(res) catch |err| return zlibErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var strm: c.zng_stream = .{
|
||||
.zalloc = zalloc,
|
||||
.zfree = zfree,
|
||||
.@"opaque" = @constCast(&alloc),
|
||||
|
||||
.next_in = in.ptr,
|
||||
.avail_in = @truncate(in.len),
|
||||
.next_out = out.ptr,
|
||||
.total_out = out.len,
|
||||
};
|
||||
var res = c.zng_inflateInit(&strm);
|
||||
decodeError(res) catch |err| return zlibErrToDecompErr(err);
|
||||
|
||||
res = c.zng_inflate(&strm, c.Z_FULL_FLUSH);
|
||||
decodeError(res) catch |err| return zlibErrToDecompErr(err);
|
||||
return strm.total_out;
|
||||
}
|
||||
|
||||
fn getOrCreate(self: *Self) !*c.zng_stream {
|
||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) return res.value_ptr;
|
||||
res.value_ptr.* = .{
|
||||
.zalloc = zalloc,
|
||||
.zfree = zfree,
|
||||
.@"opaque" = &self.alloc,
|
||||
};
|
||||
return res.value_ptr;
|
||||
}
|
||||
|
||||
fn zalloc(ptr: ?*anyopaque, size: c_uint, len: c_uint) callconv(.c) ?*anyopaque {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
return alloc.rawAlloc(size * len, .@"1", 0);
|
||||
}
|
||||
fn zfree(ptr: ?*anyopaque, mem_ptr: ?*anyopaque) callconv(.c) void {
|
||||
var alloc: *std.mem.Allocator = @ptrCast(@alignCast(@constCast(ptr)));
|
||||
alloc.rawFree(@ptrCast(mem_ptr), .@"1", 0);
|
||||
}
|
||||
|
||||
inline fn decodeError(res: i32) Error!void {
|
||||
if (res >= 0) return;
|
||||
return switch (res) {
|
||||
c.Z_STREAM_ERROR => Error.Stream,
|
||||
c.Z_DATA_ERROR => Error.Data,
|
||||
c.Z_MEM_ERROR => Error.OutOfMemory,
|
||||
c.Z_BUF_ERROR => Error.Buffer,
|
||||
c.Z_VERSION_ERROR => Error.Version,
|
||||
else => Error.Misc,
|
||||
};
|
||||
}
|
||||
inline fn zlibErrToDecompErr(err: Error) Decompressor.Error {
|
||||
return switch (err) {
|
||||
Error.OutOfMemory => Decompressor.Error.OutOfMemory,
|
||||
Error.Misc => Decompressor.Error.ReadFailed,
|
||||
Error.Stream => Decompressor.Error.ReadFailed,
|
||||
Error.Data => Decompressor.Error.ReadFailed,
|
||||
Error.Buffer => Decompressor.Error.WriteFailed,
|
||||
Error.Version => Decompressor.Error.ReadFailed,
|
||||
};
|
||||
}
|
||||
|
||||
const Error = error{
|
||||
OutOfMemory,
|
||||
Misc,
|
||||
Stream,
|
||||
Data,
|
||||
Buffer,
|
||||
Version,
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
const std = @import("std");
|
||||
|
||||
const c = @import("../../c.zig").c;
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
ctx: std.AutoHashMap(std.Thread.Id, ?*c.ZSTD_DCtx),
|
||||
|
||||
interface: Decompressor,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.ctx = .init(alloc),
|
||||
.interface = .{
|
||||
.vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.ctx.deinit();
|
||||
}
|
||||
|
||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
const ctx = try self.getOrCreate();
|
||||
const res = c.ZSTD_decompressDCtx(ctx, out.ptr, out.len, in.ptr, in.len);
|
||||
decodeError(res) catch |err| return zstdErrToDecompErr(err);
|
||||
return res;
|
||||
}
|
||||
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||
decodeError(res) catch |err| return zstdErrToDecompErr(err);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline fn getOrCreate(self: *Self) !?*c.ZSTD_DCtx {
|
||||
const res = try self.ctx.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) return res.value_ptr.*;
|
||||
res.value_ptr.* = c.ZSTD_createDCtx();
|
||||
return res.value_ptr.*;
|
||||
}
|
||||
|
||||
inline fn decodeError(res: usize) Error!void {
|
||||
if (c.ZSTD_isError(res) == 0) return;
|
||||
return switch (c.ZSTD_getErrorCode(res)) {
|
||||
c.ZSTD_error_prefix_unknown => Error.PrefixUnknown,
|
||||
c.ZSTD_error_version_unsupported => Error.VersionUnsupported,
|
||||
c.ZSTD_error_frameParameter_unsupported => Error.FrameParameterUnsupported,
|
||||
c.ZSTD_error_frameParameter_windowTooLarge => Error.FrameParameterWindowTooLarge,
|
||||
c.ZSTD_error_corruption_detected => Error.CorruptionDetected,
|
||||
c.ZSTD_error_checksum_wrong => Error.ChecksumWrong,
|
||||
c.ZSTD_error_literals_headerWrong => Error.LiteralsHeaderWrong,
|
||||
c.ZSTD_error_dictionary_corrupted => Error.DictionaryCorrupted,
|
||||
c.ZSTD_error_dictionary_wrong => Error.DictionaryWrong,
|
||||
c.ZSTD_error_dictionaryCreation_failed => Error.DictionaryCreationFailed,
|
||||
c.ZSTD_error_parameter_unsupported => Error.ParameterUnsupported,
|
||||
c.ZSTD_error_parameter_combination_unsupported => Error.ParameterCombinationUnsupported,
|
||||
c.ZSTD_error_parameter_outOfBound => Error.ParameterOutOfBound,
|
||||
c.ZSTD_error_tableLog_tooLarge => Error.TableLogTooLarge,
|
||||
c.ZSTD_error_maxSymbolValue_tooLarge => Error.MaxSymbolValueTooLarge,
|
||||
c.ZSTD_error_maxSymbolValue_tooSmall => Error.MaxSymbolValueTooSmall,
|
||||
c.ZSTD_error_cannotProduce_uncompressedBlock => Error.CannotProduceUncompressedBlock,
|
||||
c.ZSTD_error_stabilityCondition_notRespected => Error.StabilityConditionNotRespected,
|
||||
c.ZSTD_error_stage_wrong => Error.StageWrong,
|
||||
c.ZSTD_error_init_missing => Error.InitMissing,
|
||||
c.ZSTD_error_memory_allocation => Error.MemoryAllocation,
|
||||
c.ZSTD_error_workSpace_tooSmall => Error.WorkSpaceTooSmall,
|
||||
c.ZSTD_error_dstSize_tooSmall => Error.DstSizeTooSmall,
|
||||
c.ZSTD_error_srcSize_wrong => Error.SrcSizeWrong,
|
||||
c.ZSTD_error_dstBuffer_null => Error.DstBufferNull,
|
||||
c.ZSTD_error_noForwardProgress_destFull => Error.NoForwardProgressDestFull,
|
||||
c.ZSTD_error_noForwardProgress_inputEmpty => Error.NoForwardProgressInputEmpty,
|
||||
c.ZSTD_error_frameIndex_tooLarge => Error.FrameIndexTooLarge,
|
||||
c.ZSTD_error_seekableIO => Error.SeekableIo,
|
||||
c.ZSTD_error_dstBuffer_wrong => Error.DstBufferWrong,
|
||||
c.ZSTD_error_srcBuffer_wrong => Error.SrcBufferWrong,
|
||||
c.ZSTD_error_sequenceProducer_failed => Error.SequenceProducerFailed,
|
||||
c.ZSTD_error_externalSequences_invalid => Error.ExternalSequencesInvalid,
|
||||
else => Error.Generic,
|
||||
};
|
||||
}
|
||||
inline fn zstdErrToDecompErr(err: Error) Decompressor.Error {
|
||||
return switch (err) {
|
||||
Error.OutOfMemory => Decompressor.Error.OutOfMemory,
|
||||
Error.Generic => Decompressor.Error.ReadFailed,
|
||||
Error.PrefixUnknown => Decompressor.Error.ReadFailed,
|
||||
Error.VersionUnsupported => Decompressor.Error.ReadFailed,
|
||||
Error.FrameParameterUnsupported => Decompressor.Error.ReadFailed,
|
||||
Error.FrameParameterWindowTooLarge => Decompressor.Error.ReadFailed,
|
||||
Error.CorruptionDetected => Decompressor.Error.ReadFailed,
|
||||
Error.ChecksumWrong => Decompressor.Error.ReadFailed,
|
||||
Error.LiteralsHeaderWrong => Decompressor.Error.ReadFailed,
|
||||
Error.DictionaryCorrupted => Decompressor.Error.ReadFailed,
|
||||
Error.DictionaryWrong => Decompressor.Error.ReadFailed,
|
||||
Error.DictionaryCreationFailed => Decompressor.Error.ReadFailed,
|
||||
Error.ParameterUnsupported => Decompressor.Error.ReadFailed,
|
||||
Error.ParameterCombinationUnsupported => Decompressor.Error.ReadFailed,
|
||||
Error.ParameterOutOfBound => Decompressor.Error.ReadFailed,
|
||||
Error.TableLogTooLarge => Decompressor.Error.ReadFailed,
|
||||
Error.MaxSymbolValueTooLarge => Decompressor.Error.ReadFailed,
|
||||
Error.MaxSymbolValueTooSmall => Decompressor.Error.ReadFailed,
|
||||
Error.CannotProduceUncompressedBlock => Decompressor.Error.ReadFailed,
|
||||
Error.StabilityConditionNotRespected => Decompressor.Error.ReadFailed,
|
||||
Error.StageWrong => Decompressor.Error.ReadFailed,
|
||||
Error.InitMissing => Decompressor.Error.ReadFailed,
|
||||
Error.MemoryAllocation => Decompressor.Error.OutOfMemory,
|
||||
Error.WorkSpaceTooSmall => Decompressor.Error.WriteFailed,
|
||||
Error.DstSizeTooSmall => Decompressor.Error.WriteFailed,
|
||||
Error.SrcSizeWrong => Decompressor.Error.ReadFailed,
|
||||
Error.DstBufferNull => Decompressor.Error.WriteFailed,
|
||||
Error.NoForwardProgressDestFull => Decompressor.Error.WriteFailed,
|
||||
Error.NoForwardProgressInputEmpty => Decompressor.Error.ReadFailed,
|
||||
Error.FrameIndexTooLarge => Decompressor.Error.ReadFailed,
|
||||
Error.SeekableIo => Decompressor.Error.ReadFailed,
|
||||
Error.DstBufferWrong => Decompressor.Error.WriteFailed,
|
||||
Error.SrcBufferWrong => Decompressor.Error.ReadFailed,
|
||||
Error.SequenceProducerFailed => Decompressor.Error.ReadFailed,
|
||||
Error.ExternalSequencesInvalid => Decompressor.Error.ReadFailed,
|
||||
};
|
||||
}
|
||||
|
||||
const Error = error{
|
||||
OutOfMemory,
|
||||
Generic,
|
||||
PrefixUnknown,
|
||||
VersionUnsupported,
|
||||
FrameParameterUnsupported,
|
||||
FrameParameterWindowTooLarge,
|
||||
CorruptionDetected,
|
||||
ChecksumWrong,
|
||||
LiteralsHeaderWrong,
|
||||
DictionaryCorrupted,
|
||||
DictionaryWrong,
|
||||
DictionaryCreationFailed,
|
||||
ParameterUnsupported,
|
||||
ParameterCombinationUnsupported,
|
||||
ParameterOutOfBound,
|
||||
TableLogTooLarge,
|
||||
MaxSymbolValueTooLarge,
|
||||
MaxSymbolValueTooSmall,
|
||||
CannotProduceUncompressedBlock,
|
||||
StabilityConditionNotRespected,
|
||||
StageWrong,
|
||||
InitMissing,
|
||||
MemoryAllocation,
|
||||
WorkSpaceTooSmall,
|
||||
DstSizeTooSmall,
|
||||
SrcSizeWrong,
|
||||
DstBufferNull,
|
||||
NoForwardProgressDestFull,
|
||||
NoForwardProgressInputEmpty,
|
||||
FrameIndexTooLarge,
|
||||
SeekableIo,
|
||||
DstBufferWrong,
|
||||
SrcBufferWrong,
|
||||
SequenceProducerFailed,
|
||||
ExternalSequencesInvalid,
|
||||
};
|
||||
@@ -1,114 +0,0 @@
|
||||
const std = @import("std");
|
||||
const Reader = std.Io.Reader;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const zng_stream = c.zng_stream;
|
||||
|
||||
const ZlibErrors = error{
|
||||
OutOfMemory,
|
||||
OutputBufferTooSmall,
|
||||
BadData,
|
||||
StreamError,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
|
||||
streams: std.AutoHashMap(std.Thread.Id, zng_stream),
|
||||
interface: Decompressor = .{ .vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
} },
|
||||
|
||||
err: ?ZlibErrors = null,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) !Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.streams = .init(alloc),
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: Self) void {
|
||||
var iter = self.streams.keyIterator();
|
||||
while (iter.next()) |key| {
|
||||
_ = c.inflateEnd(self.streams.getPtr(key).?);
|
||||
}
|
||||
self.streams.deinit(self.alloc);
|
||||
}
|
||||
|
||||
fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
var stream = try self.getOrCreate();
|
||||
stream.next_in = in.ptr;
|
||||
stream.avail_in = @truncate(in.len);
|
||||
stream.next_out = out.ptr;
|
||||
stream.avail_out = @truncate(out.len);
|
||||
var res = c.zng_inflateReset(stream);
|
||||
switch (res) {
|
||||
c.Z_OK => {},
|
||||
c.Z_STREAM_ERROR => {
|
||||
self.err = ZlibErrors.StreamError;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
else => {
|
||||
self.err = ZlibErrors.Unknown;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
}
|
||||
res = c.zng_inflate(stream, c.Z_FINISH);
|
||||
switch (res) {
|
||||
c.Z_OK => return stream.total_out,
|
||||
c.Z_MEM_ERROR => {
|
||||
self.err = ZlibErrors.OutOfMemory;
|
||||
return Decompressor.Error.OutOfMemory;
|
||||
},
|
||||
c.Z_BUF_ERROR => {
|
||||
self.err = ZlibErrors.OutputBufferTooSmall;
|
||||
return Decompressor.Error.OutputTooSmall;
|
||||
},
|
||||
c.Z_DATA_ERROR => {
|
||||
self.err = ZlibErrors.BadData;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
else => {
|
||||
self.err = ZlibErrors.Unknown;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
}
|
||||
}
|
||||
inline fn getOrCreate(self: *Self) Decompressor.Error!*zng_stream {
|
||||
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) return res.value_ptr;
|
||||
res.value_ptr.* = .{
|
||||
.zalloc = zalloc,
|
||||
.zfree = zfree,
|
||||
.@"opaque" = @ptrCast(self),
|
||||
};
|
||||
return res.value_ptr;
|
||||
}
|
||||
|
||||
fn zalloc(self_ptr: ?*anyopaque, items: c_uint, size: c_uint) callconv(.c) ?*anyopaque {
|
||||
var self: *Self = @ptrCast(@alignCast(self_ptr));
|
||||
return self.alloc.rawAlloc(items * size, .@"1", 0);
|
||||
}
|
||||
fn zfree(self_ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) callconv(.c) void {
|
||||
var self: *Self = @ptrCast(@alignCast(self_ptr));
|
||||
self.alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0);
|
||||
}
|
||||
|
||||
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var out_len = 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 => Decompressor.Error.OutOfMemory,
|
||||
c.Z_BUF_ERROR => Decompressor.Error.OutputTooSmall,
|
||||
c.Z_DATA_ERROR => Decompressor.Error.BadInput,
|
||||
else => Decompressor.Error.BadInput,
|
||||
};
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
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,
|
||||
interface: Decompressor = .{ .vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
} },
|
||||
|
||||
err: ?LzmaError = null,
|
||||
|
||||
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(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
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 => {
|
||||
self.err = LzmaError.LzmaMemoryError;
|
||||
return Decompressor.Error.OutOfMemory;
|
||||
},
|
||||
c.LZMA_PROG_ERROR => {
|
||||
self.err = LzmaError.LzmaProgramError;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
else => {
|
||||
self.err = LzmaError.Unknown;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
}
|
||||
while (res == c.LZMA_OK)
|
||||
res = c.lzma_code(strm, c.LZMA_RUN);
|
||||
switch (res) {
|
||||
c.LZMA_STREAM_END => return strm.total_out,
|
||||
c.LZMA_MEM_ERROR => {
|
||||
self.err = LzmaError.LzmaMemoryError;
|
||||
return Decompressor.Error.OutOfMemory;
|
||||
},
|
||||
c.LZMA_MEMLIMIT_ERROR => {
|
||||
self.err = LzmaError.LzmaMemoryLimit;
|
||||
return Decompressor.Error.OutOfMemory;
|
||||
},
|
||||
c.LZMA_FORMAT_ERROR => {
|
||||
self.err = LzmaError.LzmaBadFormat;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.LZMA_DATA_ERROR => {
|
||||
self.err = LzmaError.LzmaDataCorrupt;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.LZMA_BUF_ERROR => {
|
||||
self.err = LzmaError.LzmaCannotProgress;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.LZMA_PROG_ERROR => {
|
||||
self.err = LzmaError.LzmaProgramError;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
else => {
|
||||
self.err = LzmaError.Unknown;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var strm = c.lzma_stream{
|
||||
.next_in = in.ptr,
|
||||
.avail_in = in.len,
|
||||
.next_out = out.ptr,
|
||||
.avail_out = out.len,
|
||||
};
|
||||
|
||||
var res = c.lzma_auto_decoder(&strm, out.len * 2, 0);
|
||||
switch (res) {
|
||||
c.LZMA_OK => {},
|
||||
c.LZMA_MEM_ERROR => return Decompressor.Error.OutOfMemory,
|
||||
c.LZMA_PROG_ERROR => return Decompressor.Error.BadInput,
|
||||
else => return Decompressor.Error.BadInput,
|
||||
}
|
||||
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 => Decompressor.Error.OutOfMemory,
|
||||
c.LZMA_MEMLIMIT_ERROR => Decompressor.Error.OutOfMemory,
|
||||
c.LZMA_FORMAT_ERROR => Decompressor.Error.BadInput,
|
||||
c.LZMA_DATA_ERROR => Decompressor.Error.BadInput,
|
||||
c.LZMA_BUF_ERROR => Decompressor.Error.BadInput,
|
||||
c.LZMA_PROG_ERROR => Decompressor.Error.BadInput,
|
||||
else => Decompressor.Error.BadInput,
|
||||
};
|
||||
}
|
||||
|
||||
inline fn getOrCreate(self: *Self) Decompressor.Error!*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,
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
const std = @import("std");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
const c = @import("c.zig").c;
|
||||
|
||||
pub const Lzo = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = lzo } },
|
||||
};
|
||||
|
||||
fn lzo(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var res = c.lzo_init();
|
||||
if (res != 0) return Decompressor.Error.BadInput;
|
||||
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_OUT_OF_MEMORY => Decompressor.Error.OutOfMemory,
|
||||
c.LZO_E_ERROR,
|
||||
c.LZO_E_INPUT_OVERRUN,
|
||||
c.LZO_E_LOOKBEHIND_OVERRUN,
|
||||
c.LZO_E_EOF_NOT_FOUND,
|
||||
c.LZO_E_NOT_YET_IMPLEMENTED,
|
||||
c.LZO_E_INVALID_ARGUMENT,
|
||||
c.LZO_E_INVALID_ALIGNMENT,
|
||||
=> Decompressor.Error.BadInput,
|
||||
c.LZO_E_INPUT_NOT_CONSUMED,
|
||||
c.LZO_E_OUTPUT_NOT_CONSUMED,
|
||||
c.LZO_E_OUTPUT_OVERRUN,
|
||||
=> Decompressor.Error.OutputTooSmall,
|
||||
else => Decompressor.Error.BadInput,
|
||||
};
|
||||
}
|
||||
|
||||
pub const Lz4 = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = lz4 } },
|
||||
};
|
||||
|
||||
fn lz4(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const res = c.LZ4_decompress_safe(in.ptr, out.ptr, @intCast(in.len), @intCast(out.len));
|
||||
if (res > 0) return @abs(res);
|
||||
return Decompressor.Error.BadInput; // TODO: Find out what error values it can return.
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
const config = @import("config");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
const cLz4 = @import("c/lz4.zig");
|
||||
const cLzma = @import("c/lzma.zig");
|
||||
const cLzo = @import("c/lzo.zig");
|
||||
const cXz = @import("c/xz.zig");
|
||||
const cZlib = @import("c/zlib.zig");
|
||||
const cZstd = @import("c/zstd.zig");
|
||||
const zigLzma = @import("zig/lzma.zig");
|
||||
const zigXz = @import("zig/xz.zig");
|
||||
const zigZlib = @import("zig/zstd.zig");
|
||||
const zigZstd = @import("zig/zstd.zig");
|
||||
|
||||
pub const Decomp = union(enum) {
|
||||
gzip: if (config.use_zig_decomp) zigZlib else cZlib,
|
||||
lzma: if (config.use_zig_decomp) zigLzma else cLzma,
|
||||
lzo: if (config.use_zig_decomp) void else cLzo,
|
||||
xz: if (config.use_zig_decomp) zigXz else cXz,
|
||||
lz4: if (config.use_zig_decomp) void else cLz4,
|
||||
zstd: if (config.use_zig_decomp) zigZstd else cZstd,
|
||||
|
||||
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 => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decompressor(self: *Decomp) *Decompressor {
|
||||
return switch (self) {
|
||||
.gzip => &self.gzip.interface,
|
||||
.lzma => &self.lzma.interface,
|
||||
.lzo => &self.lzo.interface,
|
||||
.xz => &self.xz.interface,
|
||||
.lz4 => &self.lz4.interface,
|
||||
.zstd => &self.zstd.interface,
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
const std = @import("std");
|
||||
const lzma = std.compress.lzma;
|
||||
const Reader = std.Io.Reader;
|
||||
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var rdr: Reader = .fixed(in);
|
||||
var decomp = try lzma.decompress(alloc, rdr.adaptToOldInterface());
|
||||
defer decomp.deinit();
|
||||
return decomp.read(out) catch |err| switch (err) {
|
||||
error.CorruptInput, error.EndOfStream, error.Overflow => return Decompressor.Error.ReadFailed,
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
const std = @import("std");
|
||||
const xz = std.compress.xz;
|
||||
const Reader = std.Io.Reader;
|
||||
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var rdr: Reader = .fixed(in);
|
||||
var decomp = try xz.decompress(alloc, rdr.adaptToOldInterface());
|
||||
defer decomp.deinit();
|
||||
return decomp.read(out) catch |err| switch (err) {
|
||||
error.CorruptInput,
|
||||
error.EndOfStream,
|
||||
error.EndOfStreamWithNoError,
|
||||
error.WrongChecksum,
|
||||
error.Unsupported,
|
||||
error.Overflow,
|
||||
=> Decompressor.Error.ReadFailed,
|
||||
else => return err,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
const std = @import("std");
|
||||
const Reader = std.Io.Reader;
|
||||
const flate = std.compress.flate;
|
||||
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const buf = try alloc.alloc(u8, out.len);
|
||||
defer alloc.free(buf);
|
||||
var rdr: Reader = .fixed(in);
|
||||
|
||||
var decomp = flate.Decompress.init(&rdr, .zlib, buf);
|
||||
return decomp.reader.readSliceShort(out);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
const std = @import("std");
|
||||
const Reader = std.Io.Reader;
|
||||
const zstd = std.compress.zstd;
|
||||
|
||||
const Decompressor = @import("../../decomp.zig");
|
||||
|
||||
const Self = @This();
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = stateless } },
|
||||
|
||||
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const buf = try alloc.alloc(u8, out.len * 2);
|
||||
defer alloc.free(buf);
|
||||
var rdr: Reader = .fixed(in);
|
||||
|
||||
var decomp = zstd.Decompress.init(&rdr, buf, .{ .window_len = @min(out.len, zstd.default_window_len) });
|
||||
return decomp.reader.readSliceShort(out);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
const std = @import("std");
|
||||
const Reader = std.Io.Reader;
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
|
||||
pub const Gzip = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = gzip } },
|
||||
};
|
||||
|
||||
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 const Lzma = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = lzma } },
|
||||
};
|
||||
|
||||
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 const Xz = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = xz } },
|
||||
};
|
||||
|
||||
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 const Zstd = struct {
|
||||
interface: Decompressor = .{ .vtable = &.{ .stateless = zstd } },
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Decompressor = @import("../decomp.zig");
|
||||
const c = @import("c.zig").c;
|
||||
const DCtx = c.ZSTD_DCtx;
|
||||
|
||||
const Self = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
ctx: std.AutoHashMap(std.Thread.Id, *DCtx),
|
||||
|
||||
interface: Decompressor = .{ .vtable = &.{
|
||||
.decompress = decompress,
|
||||
.stateless = stateless,
|
||||
} },
|
||||
err: ?ZstdError = null,
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator) !Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.ctx = .init(alloc),
|
||||
};
|
||||
}
|
||||
pub fn deinit(self: Self) void {
|
||||
var iter = self.ctx.keyIterator();
|
||||
while (iter.next()) |key| {
|
||||
_ = c.ZSTD_freeDCtx(self.ctx.getPtr(key));
|
||||
}
|
||||
self.ctx.deinit(self.alloc);
|
||||
}
|
||||
|
||||
pub fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
var self: *Self = @fieldParentPtr("interface", decomp);
|
||||
|
||||
const ctx = try self.getOrCreate();
|
||||
const res = c.ZSTD_decompressDCtx(ctx, out.ptr, out.len, in.ptr, in.len);
|
||||
try self.checkError(res);
|
||||
return res;
|
||||
}
|
||||
inline fn getOrCreate(self: *Self) Decompressor.Error!*DCtx {
|
||||
const res = try self.ctx.getOrPut(std.Thread.getCurrentId());
|
||||
if (res.found_existing) {
|
||||
try self.checkError(c.ZSTD_DCtx_reset(res.value_ptr.*, c.ZSTD_reset_session_only));
|
||||
return res.value_ptr.*;
|
||||
}
|
||||
res.value_ptr.* = c.ZSTD_createDCtx() orelse return Decompressor.Error.OutOfMemory;
|
||||
return res.value_ptr.*;
|
||||
}
|
||||
|
||||
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
|
||||
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
|
||||
if (c.ZSTD_isError(res) == 0) return res;
|
||||
return switch (c.ZSTD_getErrorCode(res)) {
|
||||
c.ZSTD_error_memory_allocation => Decompressor.Error.OutOfMemory,
|
||||
c.ZSTD_error_workSpace_tooSmall,
|
||||
c.ZSTD_error_dstSize_tooSmall,
|
||||
c.ZSTD_error_dstBuffer_null,
|
||||
c.ZSTD_error_noForwardProgress_destFull,
|
||||
=> Decompressor.Error.OutputTooSmall,
|
||||
else => Decompressor.Error.BadInput,
|
||||
};
|
||||
}
|
||||
|
||||
inline fn checkError(self: *Self, res: usize) Decompressor.Error!void {
|
||||
if (res == 0) return;
|
||||
if (c.ZSTD_isError(res) == 0) return;
|
||||
switch (c.ZSTD_getErrorCode(res)) {
|
||||
c.ZSTD_error_prefix_unknown => {
|
||||
self.err = ZstdError.PrefixUnknown;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_version_unsupported => {
|
||||
self.err = ZstdError.VersionUnsupported;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_frameParameter_unsupported => {
|
||||
self.err = ZstdError.FrameParameterUnsupported;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_frameParameter_windowTooLarge => {
|
||||
self.err = ZstdError.FrameParameterWindowTooLarge;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_corruption_detected => {
|
||||
self.err = ZstdError.CorruptionDetected;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_checksum_wrong => {
|
||||
self.err = ZstdError.ChecksumWrong;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_literals_headerWrong => {
|
||||
self.err = ZstdError.LiteralsHeaderWrong;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_dictionary_corrupted => {
|
||||
self.err = ZstdError.DictionaryCorrupted;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_dictionary_wrong => {
|
||||
self.err = ZstdError.DictionaryWrong;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_dictionaryCreation_failed => {
|
||||
self.err = ZstdError.DictionaryCreationFailed;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_parameter_unsupported => {
|
||||
self.err = ZstdError.ParameterUnsupported;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_parameter_combination_unsupported => {
|
||||
self.err = ZstdError.ParameterCombinationUnsupported;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_parameter_outOfBound => {
|
||||
self.err = ZstdError.ParameterOutOfBound;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_tableLog_tooLarge => {
|
||||
self.err = ZstdError.TableLogTooLarge;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_maxSymbolValue_tooLarge => {
|
||||
self.err = ZstdError.MaxSymbolValueTooLarge;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_maxSymbolValue_tooSmall => {
|
||||
self.err = ZstdError.MaxSymbolValueTooSmall;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_stabilityCondition_notRespected => {
|
||||
self.err = ZstdError.StabilityConditionNotRespected;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_stage_wrong => {
|
||||
self.err = ZstdError.StageWrong;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_init_missing => {
|
||||
self.err = ZstdError.InitMissing;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_memory_allocation => {
|
||||
self.err = ZstdError.MemoryAllocation;
|
||||
return Decompressor.Error.OutOfMemory;
|
||||
},
|
||||
c.ZSTD_error_workSpace_tooSmall => {
|
||||
self.err = ZstdError.WorkSpaceTooSmall;
|
||||
return Decompressor.Error.OutputTooSmall;
|
||||
},
|
||||
c.ZSTD_error_dstSize_tooSmall => {
|
||||
self.err = ZstdError.DstSizeTooSmall;
|
||||
return Decompressor.Error.OutputTooSmall;
|
||||
},
|
||||
c.ZSTD_error_srcSize_wrong => {
|
||||
self.err = ZstdError.SrcSizeWrong;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
c.ZSTD_error_dstBuffer_null => {
|
||||
self.err = ZstdError.DstBufferNull;
|
||||
return Decompressor.Error.OutputTooSmall;
|
||||
},
|
||||
c.ZSTD_error_noForwardProgress_destFull => {
|
||||
self.err = ZstdError.NoForwardProgressDestFull;
|
||||
return Decompressor.Error.OutputTooSmall;
|
||||
},
|
||||
c.ZSTD_error_noForwardProgress_inputEmpty => {
|
||||
self.err = ZstdError.NoForwardProgressInputEmpty;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
else => {
|
||||
self.err = ZstdError.Generic;
|
||||
return Decompressor.Error.BadInput;
|
||||
},
|
||||
}
|
||||
}
|
||||
pub const ZstdError = error{
|
||||
OutOfMemory,
|
||||
Generic,
|
||||
PrefixUnknown,
|
||||
VersionUnsupported,
|
||||
FrameParameterUnsupported,
|
||||
FrameParameterWindowTooLarge,
|
||||
CorruptionDetected,
|
||||
ChecksumWrong,
|
||||
LiteralsHeaderWrong,
|
||||
DictionaryCorrupted,
|
||||
DictionaryWrong,
|
||||
DictionaryCreationFailed,
|
||||
ParameterUnsupported,
|
||||
ParameterCombinationUnsupported,
|
||||
ParameterOutOfBound,
|
||||
TableLogTooLarge,
|
||||
MaxSymbolValueTooLarge,
|
||||
MaxSymbolValueTooSmall,
|
||||
CannotProduceUncompressedBlock,
|
||||
StabilityConditionNotRespected,
|
||||
StageWrong,
|
||||
InitMissing,
|
||||
MemoryAllocation,
|
||||
WorkSpaceTooSmall,
|
||||
DstSizeTooSmall,
|
||||
SrcSizeWrong,
|
||||
DstBufferNull,
|
||||
NoForwardProgressDestFull,
|
||||
NoForwardProgressInputEmpty,
|
||||
FrameIndexTooLarge,
|
||||
SeekableIo,
|
||||
DstBufferWrong,
|
||||
SrcBufferWrong,
|
||||
SequenceProducerFailed,
|
||||
ExternalSequencesInvalid,
|
||||
MaxCode,
|
||||
};
|
||||
+3
-2
@@ -8,6 +8,7 @@ const Superblock = @import("super.zig").Superblock;
|
||||
const MetadataReader = @import("util/metadata.zig");
|
||||
const OffsetFile = @import("util/offset_file.zig");
|
||||
const XattrTable = @import("xattr.zig");
|
||||
const Decompressor = @import("decomp.zig");
|
||||
|
||||
/// Information about a fragment section. Multiple fragments are contained in the block described by a single FragEntry.
|
||||
/// The offset into the block and fragment size is stored in the file's inode.
|
||||
@@ -48,7 +49,7 @@ pub fn Table(T: anytype) type {
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
fil: OffsetFile,
|
||||
decomp: DecompFn,
|
||||
decomp: *Decompressor,
|
||||
tab_start: u64,
|
||||
|
||||
tab: std.AutoHashMap(u32, []T),
|
||||
@@ -56,7 +57,7 @@ pub fn Table(T: anytype) type {
|
||||
|
||||
mut: Mutex = .{},
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, decomp: DecompFn, tab_start: u64, values: u32) !Self {
|
||||
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, decomp: *Decompressor, tab_start: u64, values: u32) !Self {
|
||||
return .{
|
||||
.alloc = alloc,
|
||||
.fil = fil,
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
const std = @import("std");
|
||||
|
||||
const DecompFn = @import("decomp.zig").DecompFn;
|
||||
const Decompressor = @import("decomp.zig");
|
||||
const Table = @import("tables.zig").Table;
|
||||
const MetadataReader = @import("util/metadata.zig");
|
||||
const OffsetFile = @import("util/offset_file.zig");
|
||||
@@ -38,14 +38,14 @@ const XattrTable = @This();
|
||||
|
||||
alloc: std.mem.Allocator,
|
||||
fil: OffsetFile,
|
||||
decomp: DecompFn,
|
||||
decomp: *Decompressor,
|
||||
|
||||
count: u32,
|
||||
start: u64,
|
||||
|
||||
table: Table(Entry),
|
||||
|
||||
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, decomp: DecompFn, table_start: u64) !XattrTable {
|
||||
pub fn init(alloc: std.mem.Allocator, fil: OffsetFile, decomp: *Decompressor, table_start: u64) !XattrTable {
|
||||
var info = packed struct {
|
||||
start: u64 = undefined,
|
||||
count: u32 = undefined,
|
||||
|
||||
Reference in New Issue
Block a user