pub const c = @cImport({ @cInclude("archive.h"); @cInclude("archive_entry.h"); }); const std = @import("std"); pub const Entry = struct { raw: *c.archive_entry, pub fn pathname(self: Entry) [:0]const u8 { return std.mem.span(c.archive_entry_pathname(self.raw)); } pub fn setPathname(self: *Entry, new_pathname: [:0]const u8) void { c.archive_entry_set_pathname(self.raw, new_pathname.ptr); } }; pub const Read = struct { raw: *c.archive, pub fn init() !Read { if (c.archive_read_new()) |raw| { return Read{ .raw = raw }; } else { std.log.err("archive_read_new failed", .{}); return error.LibArchiveError; } } pub fn deinit(self: *Read) void { if (c.archive_read_free(self.raw) != c.ARCHIVE_OK) { std.log.warn("archive_read_free failed", .{}); } } pub const Filter = enum { all, bzip2, compress, grzip, gzip, lrzip, lz4, lzma, lzop, none, rpm, uu, xz, zstd, }; pub fn supportFilter(self: *Read, comptime filter: Filter) !void { const fn_name = comptime "archive_read_support_filter_" ++ @tagName(filter); const f = comptime @field(c, fn_name); if (f(self.raw) != c.ARCHIVE_OK) { std.log.err(fn_name ++ ": {s}", .{c.archive_error_string(self.raw)}); return error.LibArchiveError; } } pub const Format = enum { @"7zip", all, ar, cab, cpio, empty, iso9660, lha, mtree, rar, raw, tar, xar, zip, }; pub fn supportFormat(self: *Read, comptime format: Format) !void { const fn_name = comptime "archive_read_support_format_" ++ @tagName(format); const f = comptime @field(c, fn_name); if (f(self.raw) != c.ARCHIVE_OK) { std.log.err(fn_name ++ ": {s}", .{c.archive_error_string(self.raw)}); return error.LibArchiveError; } } pub fn openFilename(self: *Read, filename: [:0]const u8, block_size: usize) !void { if (c.archive_read_open_filename(self.raw, filename.ptr, block_size) != c.ARCHIVE_OK) { std.log.err("archive_read_open_filename: {s}", .{c.archive_error_string(self.raw)}); return error.LibArchiveError; } } pub fn nextHeader(self: *Read) !?Entry { var header_raw: ?*c.archive_entry = undefined; var r = c.ARCHIVE_RETRY; while (r == c.ARCHIVE_RETRY) { r = c.archive_read_next_header(self.raw, &header_raw); } if (r == c.ARCHIVE_WARN) { std.log.warn("archive_read_next_header: {s}", .{c.archive_error_string(self.raw)}); r = c.ARCHIVE_OK; } if (r == c.ARCHIVE_EOF) { return null; } if (r != c.ARCHIVE_OK or header_raw == null) { std.log.err("archive_read_next_header: {s}", .{c.archive_error_string(self.raw)}); return error.LibArchiveError; } return Entry{ .raw = header_raw.? }; } // TODO: Replace flags with enum pub fn extract(self: *Read, entry: Entry, flags: c_int) !void { var r = c.ARCHIVE_RETRY; while (r == c.ARCHIVE_RETRY) { r = c.archive_read_extract(self.raw, entry.raw, flags); } if (r == c.ARCHIVE_WARN) { std.log.warn("archive_read_extract: {s}", .{c.archive_error_string(self.raw)}); } else if (r != c.ARCHIVE_OK) { std.log.err("archive_read_extract: {s}", .{c.archive_error_string(self.raw)}); return error.LibArchiveError; } } };