Skip to content

Commit

Permalink
Further simplify compression code, add libz support
Browse files Browse the repository at this point in the history
  • Loading branch information
mgord9518 committed Aug 27, 2024
1 parent efb2a88 commit 8954487
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 118 deletions.
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ pub fn buildLibzstd(
const ZlibDecompressor = enum {
zig_stdlib,
libdeflate,
libz,
};

const XzDecompressor = enum {
Expand Down
2 changes: 1 addition & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.{
.name = "squashfuse-zig",
.version = "0.3.1",
.version = "0.3.2",

.paths = [][]const u8{
"build.zig",
Expand Down
87 changes: 57 additions & 30 deletions lib/compression.zig
Original file line number Diff line number Diff line change
Expand Up @@ -98,24 +98,25 @@ pub const Decompressor = *const fn (
out: []u8,
) DecompressError!usize;

pub fn builtWithDecompression(comptime compression: Compression) bool {
if (compression == .none) return true;

const decl_name = "static_" ++ @tagName(compression);
return @hasDecl(build_options, decl_name) and @field(build_options, decl_name);
}

pub fn getDecompressor(kind: Compression) SquashFsError!Decompressor {
switch (kind) {
.zlib => {
if (build_options.zlib_decompressor == .zig_stdlib) {
return @import("compression/zlib_zig.zig").decode;
}

const libdeflate = @import("compression/zlib_libdeflate.zig");
initDecompressionSymbol(libdeflate, .zlib, "deflate") catch return error.Error;
const libz = @import("compression/zlib_libz.zig");

return switch (build_options.zlib_decompressor) {
.zig_stdlib => @import("compression/zlib_zig.zig").decode,
.libdeflate => blk: {
initDecompressionSymbol(libdeflate, .zlib, "libdeflate") catch return error.Error;

return libdeflate.decode;
break :blk libdeflate.decode;
},
.libz => blk: {
initDecompressionSymbol(libz, .zlib, "libz") catch return error.Error;

break :blk libz.decode;
},
};
},
.lzma, .lzo => return error.InvalidCompression,
.xz => {
Expand All @@ -124,13 +125,13 @@ pub fn getDecompressor(kind: Compression) SquashFsError!Decompressor {
}

const libxz = @import("compression/xz_liblzma.zig");
initDecompressionSymbol(libxz, .xz, "lzma") catch return error.Error;
initDecompressionSymbol(libxz, .xz, "liblzma") catch return error.Error;

return libxz.decode;
},
.lz4 => {
const liblz4 = @import("compression/lz4_liblz4.zig");
initDecompressionSymbol(liblz4, .lz4, "lz4") catch return error.Error;
initDecompressionSymbol(liblz4, .lz4, "liblz4") catch return error.Error;

return liblz4.decode;
},
Expand All @@ -140,7 +141,7 @@ pub fn getDecompressor(kind: Compression) SquashFsError!Decompressor {
}

const libzstd = @import("compression/zstd_libzstd.zig");
initDecompressionSymbol(libzstd, .zstd, "zstd") catch return error.Error;
initDecompressionSymbol(libzstd, .zstd, "libzstd") catch return error.Error;

return libzstd.decode;
},
Expand All @@ -151,29 +152,48 @@ pub fn getDecompressor(kind: Compression) SquashFsError!Decompressor {
return error.InvalidCompression;
}

pub fn builtWithDecompression(comptime compression: Compression) bool {
if (compression == .none) return true;

const decl_name = "static_" ++ @tagName(compression);

return @hasDecl(build_options, decl_name) and @field(build_options, decl_name);
}

// Initializes decompression function pointers for C-ABI compression libs
// If `static_[DECOMPRESSOR]` is not given, an attempt will be made to
// dlload the library from the system
fn initDecompressionSymbol(
comptime T: type,
comptime compression: Compression,
comptime library_name: []const u8,
) !void {
if (builtWithDecompression(compression)) {
T.lib_decode = @extern(
*const T.LibDecodeFn,
.{ .name = T.lib_decode_name },
);
if (comptime builtWithDecompression(compression)) {
inline for (@typeInfo(T.required_symbols).Struct.decls) |decl| {
@field(T.required_symbols, decl.name) = @extern(
@TypeOf(@field(T.required_symbols, decl.name)),
.{ .name = decl.name },
);
}

return;
}

var found = false;

// Looks like it wasn't statically linked, attempt to find the library on
// the system
inline for (.{
"/lib/lib{s}.so.1",
"/lib64/lib{s}.so.1",
"/usr/lib/lib{s}.so.1",
"/usr/lib64/lib{s}.so.1",
"/lib/{s}.so.1",
"/lib64/{s}.so.1",
"/usr/lib/{s}.so.1",
"/usr/lib64/{s}.so.1",
}) |fmt| {
const path = std.fmt.comptimePrint(fmt, .{library_name});
const path = std.fmt.comptimePrint(
fmt,
.{library_name},
);

// TODO: close libs
var lib = DynLib.open(path) catch |err| {
switch (err) {
Expand All @@ -182,11 +202,18 @@ fn initDecompressionSymbol(
}
};

T.lib_decode = lib.lookup(
*const T.LibDecodeFn,
T.lib_decode_name,
) orelse return error.SymbolNotFound;
inline for (@typeInfo(T.required_symbols).Struct.decls) |decl| {
@field(T.required_symbols, decl.name) = lib.lookup(
@TypeOf(@field(T.required_symbols, decl.name)),
decl.name,
) orelse return error.SymbolNotFound;
}

found = true;
break;
}

if (!found) return error.DynLibNotFound;
}

// Since the decompressor will never be called on uncompressed blocks,
Expand Down
21 changes: 9 additions & 12 deletions lib/compression/lz4_liblz4.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ const std = @import("std");
const compression = @import("../compression.zig");
const DecompressError = compression.DecompressError;

pub const LibDecodeFn = fn (
[*]const u8,
[*]u8,
c_int,
c_int,
) callconv(.C) c_int;

pub const lib_decode_name = "LZ4_decompress_safe";

// Initialized in `compression.zig`
pub var lib_decode: *const LibDecodeFn = undefined;
pub const required_symbols = struct {
pub var LZ4_decompress_safe: *const fn (
[*]const u8,
[*]u8,
c_int,
c_int,
) callconv(.C) c_int = undefined;
};

pub fn decode(
allocator: std.mem.Allocator,
Expand All @@ -21,7 +18,7 @@ pub fn decode(
) DecompressError!usize {
_ = allocator;

const ret = lib_decode(
const ret = required_symbols.LZ4_decompress_safe(
in.ptr,
out.ptr,
@intCast(in.len),
Expand Down
33 changes: 15 additions & 18 deletions lib/compression/xz_liblzma.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,20 @@ const io = std.io;
const compression = @import("../compression.zig");
const DecompressError = compression.DecompressError;

pub const lib_decode_name = "lzma_stream_buffer_decode";

// Initialized in `compression.zig`
pub var lib_decode: *const LibDecodeFn = undefined;

pub const LibDecodeFn = fn (
memlemit: *u64,
flags: u32,
// TODO: set allocator
allocator: ?*anyopaque,
in: [*]const u8,
in_pos: *usize,
in_size: usize,
out: [*]u8,
out_pos: *usize,
out_size: usize,
) callconv(.C) c_int;
pub const required_symbols = struct {
pub var lzma_stream_buffer_decode: *const fn (
memlemit: *u64,
flags: u32,
// TODO: set allocator
allocator: ?*anyopaque,
in: [*]const u8,
in_pos: *usize,
in_size: usize,
out: [*]u8,
out_pos: *usize,
out_size: usize,
) callconv(.C) c_int = undefined;
};

pub fn decode(
allocator: std.mem.Allocator,
Expand All @@ -33,7 +30,7 @@ pub fn decode(
var inpos: usize = 0;
var outpos: usize = 0;

const err = lib_decode(
const err = required_symbols.lzma_stream_buffer_decode(
&memlimit,
0,
null,
Expand Down
81 changes: 39 additions & 42 deletions lib/compression/zlib_libdeflate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,47 @@ const std = @import("std");
const compression = @import("../compression.zig");
const DecompressError = compression.DecompressError;

pub const LibDecodeFn = fn (
*anyopaque,
[*]const u8,
usize,
[*]u8,
usize,
*usize,
) callconv(.C) c_int;
pub const required_symbols = struct {
pub var libdeflate_zlib_decompress: *const fn (
*anyopaque,
[*]const u8,
usize,
[*]u8,
usize,
*usize,
) callconv(.C) c_int = undefined;
};

pub fn decode(
allocator: std.mem.Allocator,
in: []const u8,
out: []u8,
) DecompressError!usize {
_ = allocator;

var decompressor = Decompressor{};

var written: usize = undefined;

const err = required_symbols.libdeflate_zlib_decompress(
&decompressor,
in.ptr,
in.len,
out.ptr,
out.len,
&written,
);

pub const lib_decode_name = "libdeflate_zlib_decompress";
return switch (err) {
// Defined in <https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h>
0 => written,

// Initialized in `compression.zig`
pub var lib_decode: *const LibDecodeFn = undefined;
1 => DecompressError.CorruptInput,
2 => DecompressError.ShortOutput,
3 => DecompressError.NoSpaceLeft,
else => DecompressError.Error,
};
}

// Deflate constants
const litlen_syms = 288;
Expand Down Expand Up @@ -46,34 +74,3 @@ const Decompressor = extern struct {
litlen_tablebits: u32 = undefined,
free_func: ?*anyopaque = undefined,
};

pub fn decode(
allocator: std.mem.Allocator,
in: []const u8,
out: []u8,
) DecompressError!usize {
_ = allocator;

var decompressor = Decompressor{};

var written: usize = undefined;

const err = lib_decode(
&decompressor,
in.ptr,
in.len,
out.ptr,
out.len,
&written,
);

return switch (err) {
// Defined in <https://github.com/ebiggers/libdeflate/blob/master/libdeflate.h>
0 => written,

1 => DecompressError.CorruptInput,
2 => DecompressError.ShortOutput,
3 => DecompressError.NoSpaceLeft,
else => DecompressError.Error,
};
}
51 changes: 51 additions & 0 deletions lib/compression/zlib_libz.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const std = @import("std");
const compression = @import("../compression.zig");
const DecompressError = compression.DecompressError;

pub const required_symbols = struct {
pub var uncompress: *const fn (
[*]u8,
*c_ulong,
[*]const u8,
c_ulong,
) callconv(.C) c_int = undefined;
};

pub fn decode(
allocator: std.mem.Allocator,
in: []const u8,
out: []u8,
) DecompressError!usize {
_ = allocator;

var written: c_ulong = @intCast(out.len);

const err = required_symbols.uncompress(
out.ptr,
&written,
in.ptr,
in.len,
);

// TODO: audit these and ensure they're correct
if (err < 0) return switch (err) {
// Z_STREAM_ERROR
-2 => DecompressError.ShortOutput,

// Z_DATA_ERROR
-3 => DecompressError.CorruptInput,

// Z_MEM_ERROR
-4 => DecompressError.OutOfMemory,

// Z_BUF_ERROR
-5 => DecompressError.NoSpaceLeft,

// Z_ERRNO, Z_VERSION_ERROR
-1, -6 => DecompressError.Error,

else => DecompressError.Error,
};

return written;
}
Loading

0 comments on commit 8954487

Please sign in to comment.