Working on re-doing decompression

This commit is contained in:
Caleb J. Gardner
2026-03-21 02:13:36 -05:00
parent df22cf6529
commit 54aaf30ea5
11 changed files with 213 additions and 238 deletions
+2 -6
View File
@@ -2,10 +2,7 @@ const std = @import("std");
const Reader = std.Io.Reader;
const builtin = @import("builtin");
const config = if (builtin.is_test) .{
.use_zig_decomp = !builtin.link_libc,
.allow_lzo = false, // Change once LZO compilation is fixed
} else @import("config");
const config = @import("config");
pub const c = @cImport({
@cInclude("zlib-ng.h");
@@ -13,6 +10,5 @@ pub const c = @cImport({
@cInclude("lz4.h");
@cInclude("zstd.h");
@cInclude("zstd_errors.h");
if (config.allow_lzo)
@cInclude("lzo/minilzo.h");
@cInclude("lzo/minilzo.h");
});
+2 -17
View File
@@ -15,14 +15,12 @@ const ZlibErrors = error{
const Self = @This();
alloc: std.mem.Allocator,
window_size: i16,
streams: std.AutoHashMap(std.Thread.Id, zng_stream),
pub fn init(alloc: std.mem.Allocator, window_size: i16) !Self {
pub fn init(alloc: std.mem.Allocator) !Self {
return .{
.alloc = alloc,
.window_size = window_size,
.streams = .init(alloc),
};
}
@@ -40,7 +38,7 @@ pub fn decompress(self: *Self, in: []u8, out: []u8) ZlibErrors!usize {
stream.avail_in = in.len;
stream.next_out = out.ptr;
stream.avail_out = out.len;
var res = c.zng_inflateReset2(stream, self.window_size);
var res = c.zng_inflateReset(stream);
switch (res) {
c.Z_OK => {},
c.Z_STREAM_ERROR => return ZlibErrors.StreamError,
@@ -74,16 +72,3 @@ fn zfree(self_ptr: ?*anyopaque, alloc_ptr: ?*anyopaque) ?*anyopaque {
var self: *Self = @ptrCast(self_ptr);
self.alloc.rawFree(@ptrCast(alloc_ptr), .@"1", 0);
}
pub fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
_ = alloc;
var out_len: usize = out.len;
const res = c.zng_uncompress(out.ptr, &out_len, in.ptr, in.len);
return switch (res) {
c.Z_OK => out_len,
c.Z_MEM_ERROR => ZlibErrors.NotEnoughMemory,
c.Z_BUF_ERROR => ZlibErrors.OutputBufferTooSmall,
c.Z_DATA_ERROR => ZlibErrors.BadData,
else => ZlibErrors.Unknown,
};
}
+79
View File
@@ -0,0 +1,79 @@
const std = @import("std");
const builtin = @import("builtin");
const c = @import("c.zig").c;
const stream = c.lzma_stream;
const Self = @This();
alloc: std.mem.Allocator,
streams: std.AutoHashMap(std.Thread.Id, stream),
xz: bool,
pub fn init(alloc: std.mem.Allocator, xz: bool) !Self {
return .{
.alloc = alloc,
.streams = .init(alloc),
.xz = xz,
};
}
pub fn deinit(self: Self) void {
var iter = self.streams.keyIterator();
while (iter.next()) |key|
c.lzma_end(self.streams.getPtr(key));
self.streams.deinit();
}
pub fn decompress(self: *Self, in: []u8, out: []u8) LzmaError!usize {
var strm = try self.getOrCreate();
strm.next_in = in.ptr;
strm.avail_in = in.len;
strm.next_out = out.ptr;
strm.avail_out = out.len;
var res = if (self.xz)
c.lzma_stream_decoder(strm, in.len * 2, 0)
else
c.lzma_alone_decoder(strm, in.len * 2);
switch (res) {
c.LZMA_OK => {},
c.LZMA_MEM_ERROR => return LzmaError.LzmaMemoryError,
c.LZMA_PROG_ERROR => return LzmaError.LzmaProgramError,
else => return LzmaError.UnknownResult,
}
while (res == c.LZMA_OK)
res = c.lzma_code(strm, c.LZMA_RUN);
return switch (res) {
c.LZMA_STREAM_END => strm.total_out,
c.LZMA_MEM_ERROR => LzmaError.LzmaMemoryError,
c.LZMA_MEMLIMIT_ERROR => LzmaError.LzmaMemoryLimit,
c.LZMA_FORMAT_ERROR => LzmaError.LzmaBadFormat,
c.LZMA_DATA_ERROR => LzmaError.LzmaDataCorrupt,
c.LZMA_BUF_ERROR => LzmaError.LzmaCannotProgress,
c.LZMA_PROG_ERROR => LzmaError.LzmaProgramError,
else => LzmaError.UnknownResult,
};
}
inline fn getOrCreate(self: *Self) LzmaError!*stream {
const res = try self.streams.getOrPut(std.Thread.getCurrentId());
if (res.found_existing) return res.value_ptr;
// Ideally, the zero value should be LZMA_STREAM_INIT, but translate-c can't handle it properly.
// According to lzma, setting it to entirely zero values *should* work.
// res.value_ptr.* = c.LZMA_STREAM_INIT;
res.value_ptr.* = std.mem.zeroInit(stream, .{});
return res.value_ptr;
}
pub const LzmaError = error{
OutOfMemory,
LzmaMemoryError,
LzmaMemoryLimit,
LzmaBadFormat,
LzmaDataCorrupt,
LzmaCannotProgress,
LzmaProgramError,
Unknown,
};
+32
View File
@@ -0,0 +1,32 @@
const c = @import("c.zig").c;
pub fn lzo(in: []u8, out: []u8) anyerror!usize {
var res = c.lzo_init();
if (res != 0) return error.LzoInitFailed;
var out_len: usize = out.len;
res = c.lzo1x_decompress(in.ptr, in.len, out.ptr, &out_len, null);
return switch (res) {
c.LZO_E_OK => out_len,
c.LZO_E_ERROR => error.LzoError,
c.LZO_E_OUT_OF_MEMORY => error.LzoOutOfMemory,
c.LZO_E_NOT_COMPRESSIBLE => error.LzoNotCompressible,
c.LZO_E_INPUT_OVERRUN => error.LzoInputOverrun,
c.LZO_E_OUTPUT_OVERRUN => error.LzoOutputOverrun,
c.LZO_E_LOOKBEHIND_OVERRUN => error.LzoLookbehindOverrun,
c.LZO_E_EOF_NOT_FOUND => error.LzoEofNotFound,
c.LZO_E_INPUT_NOT_CONSUMED => error.LzoInputNotConsumed,
c.LZO_E_NOT_YET_IMPLEMENTED => error.LzoNotYetImplemented,
c.LZO_E_INVALID_ARGUMENT => error.LzoInvalidArgument,
c.LZO_E_INVALID_ALIGNMENT => error.LzoInvalidAlignment,
c.LZO_E_OUTPUT_NOT_CONSUMED => error.LzoOutputNotConsumed,
c.LZO_E_INTERNAL_ERROR => error.LzoInternalError,
else => error.UnknownResult,
};
}
pub fn lz4(in: []u8, out: []u8) anyerror!usize {
const res = c.LZ4_decompress_safe(in.ptr, out.ptr, @intCast(in.len), @intCast(out.len));
if (res > 0) return @abs(res); // TODO: Find out what error values it can return.
return error.Lz4DecompressFailed;
}
+35
View File
@@ -0,0 +1,35 @@
const std = @import("std");
const Reader = std.Io.Reader;
const builtin = @import("builtin");
pub const DecompFn = *const fn (alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize; // TODO: replace anyerror to definitive error types.
pub fn gzip(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
var rdr: Reader = .fixed(in);
const buf = try alloc.alloc(u8, out.len);
defer alloc.free(buf);
var decomp = std.compress.flate.Decompress.init(&rdr, .zlib, buf);
return decomp.reader.readSliceShort(out);
}
pub fn lzma(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
var rdr: Reader = .fixed(in);
var decomp = try std.compress.lzma.decompress(alloc, rdr.adaptToOldInterface());
return decomp.read(out);
}
pub fn xz(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
var rdr: Reader = .fixed(in);
var decomp = try std.compress.xz.decompress(alloc, rdr.adaptToOldInterface());
return decomp.read(out);
}
pub fn zstd(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
var rdr: Reader = .fixed(in);
const buf = try alloc.alloc(u8, 1024 * 1024);
defer alloc.free(buf);
var decomp = std.compress.zstd.Decompress.init(&rdr, buf, .{});
return decomp.reader.readSliceShort(out) catch |err| {
return decomp.err orelse err;
};
}