Created DataReader (untested)

Other minor fixes & tweaks
This commit is contained in:
Caleb J. Gardner
2026-08-30 02:37:37 -05:00
parent c5d75d3839
commit 173e76469f
6 changed files with 241 additions and 10 deletions
+3 -4
View File
@@ -6,7 +6,6 @@ const util = @import("utils/util.zig");
const File = @import("file.zig"); const File = @import("file.zig");
const Inode = @import("inode.zig"); const Inode = @import("inode.zig");
const Decomp = @import("decomp.zig"); const Decomp = @import("decomp.zig");
const Options = @import("options.zig"); const Options = @import("options.zig");
const Archive = @This(); const Archive = @This();
@@ -16,7 +15,7 @@ map: Io.File.MemoryMap,
super: Super, super: Super,
root_inode_ref: Inode.Reference, root_inode_ref: Inode.Reference,
pub fn open(io: Io, file: Io.File, offset: u64) !Archive { pub fn init(io: Io, file: Io.File, offset: u64) !Archive {
var map = try file.createMemoryMap(io, .{ var map = try file.createMemoryMap(io, .{
.len = try file.length(io) - offset, .len = try file.length(io) - offset,
.offset = offset, .offset = offset,
@@ -33,7 +32,7 @@ pub fn open(io: Io, file: Io.File, offset: u64) !Archive {
.root_inode_ref = superblock.root_inode_ref, .root_inode_ref = superblock.root_inode_ref,
}; };
} }
pub fn close(self: *Archive, io: Io) void { pub fn deinit(self: *Archive, io: Io) void {
self.map.destroy(io); self.map.destroy(io);
} }
@@ -53,7 +52,7 @@ pub fn root(self: *Archive, alloc: std.mem.Allocator) !File {
.name = "", .name = "",
}; };
} }
pub fn openFile(self: *Archive, alloc: std.mem.Allocator, filepath: []const u8) !File { pub fn open(self: *Archive, alloc: std.mem.Allocator, filepath: []const u8) !File {
var root_file = try self.root(alloc); var root_file = try self.root(alloc);
defer root_file.deinit(); defer root_file.deinit();
+92 -1
View File
@@ -4,6 +4,8 @@ const Io = std.Io;
const Inode = @import("inode.zig"); const Inode = @import("inode.zig");
const Directory = @import("dir.zig"); const Directory = @import("dir.zig");
const MetadataReader = @import("utils/meta.zig"); const MetadataReader = @import("utils/meta.zig");
const Options = @import("options.zig");
const DataReader = @import("utils/data_reader.zig");
const Super = @import("archive.zig").Super; const Super = @import("archive.zig").Super;
const File = @This(); const File = @This();
@@ -35,6 +37,31 @@ pub fn deinit(self: File) void {
self.alloc.free(self.name); self.alloc.free(self.name);
} }
/// Reader interface to read a regular file's contents.
pub fn reader(self: File, alloc: std.mem.Allocator) !DataReader {
return switch (self.inode.header.type) {
.file => |f| .init(
alloc,
self.data,
self.super.decomp_fn,
self.super.block_size,
f.start,
f.size,
f.blocks,
),
.ext_file => |f| .init(
alloc,
self.data,
self.super.decomp_fn,
self.super.block_size,
f.start,
f.size,
f.blocks,
),
else => error.NotRegularFile,
};
}
pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File { pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
switch (self.inode.header.type) { switch (self.inode.header.type) {
.dir, .ext_dir => {}, .dir, .ext_dir => {},
@@ -47,6 +74,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
return self.copy(alloc); return self.copy(alloc);
const first_element: []u8 = std.mem.sliceTo(path, '/'); const first_element: []u8 = std.mem.sliceTo(path, '/');
const final = first_element.len == path.len;
var dir_size: u32 = undefined; var dir_size: u32 = undefined;
var dir_rdr: MetadataReader = undefined; var dir_rdr: MetadataReader = undefined;
@@ -67,10 +95,73 @@ pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
else => unreachable, else => unreachable,
} }
const inode: Inode = { const entry: Directory.Entry = blk: {
var dir: Directory = try .read(alloc, &dir_rdr.interface, dir_size); var dir: Directory = try .read(alloc, &dir_rdr.interface, dir_size);
defer dir.deinit(alloc); defer dir.deinit(alloc);
var entries = dir.entries;
while (entries.len > 0) {
const idx = entries.len / 2;
const val = entries[idx];
switch (std.mem.order(u8, first_element, val.name)) {
.eq => {
if (final) {
const inode: Inode = try .fromRef(
alloc,
self.data,
.{ .start = val.start, .offset = val.offset },
self.super,
);
errdefer inode.deinit(alloc);
return .{
.alloc = alloc,
.data = self.data,
.super = self.super,
.inode = inode,
.name = try alloc.dupe(u8, val.name),
};
}
break :blk val;
},
.lt => entries = entries[0..idx],
.gt => entries = entries[idx..],
}
}
return error.NotFound;
}; };
if (entry.type != .dir)
return error.NotFound;
const transient_file: File = .{
.alloc = alloc,
.data = self.data,
.super = self.super,
.inode = try .fromRef(
alloc,
self.data,
.{ .start = entry.start, .offset = entry.offset },
self.super,
),
.name = "",
};
return transient_file.open(alloc, filepath[first_element.len..]);
}
/// Extract the given File to the location.
pub fn extract(self: File, alloc: std.mem.Allocator, io: Io, ext_loc: []const u8, options: Options) !void {
_ = self;
_ = alloc;
_ = io;
_ = ext_loc;
_ = options;
return error.TODO; return error.TODO;
} }
+1 -1
View File
@@ -246,7 +246,7 @@ pub const ExtDev = extern struct {
xattr_idx: u32, xattr_idx: u32,
pub fn read(rdr: *Io.Reader) !ExtDev { pub fn read(rdr: *Io.Reader) !ExtDev {
return util.readValue(ExtDev, rdr); return util.readValueRdr(ExtDev, rdr);
} }
}; };
+3 -3
View File
@@ -12,11 +12,11 @@ test "Open" {
var archive_file = try Io.Dir.cwd().openFile(io, TEST_ARCHIVE, .{}); var archive_file = try Io.Dir.cwd().openFile(io, TEST_ARCHIVE, .{});
defer archive_file.close(io); defer archive_file.close(io);
var arc: Archive = try .open(io, archive_file, 0); var arc: Archive = try .init(io, archive_file, 0);
defer arc.close(io); defer arc.deinit(io);
std.debug.print("{}\n", .{arc.super}); std.debug.print("{}\n", .{arc.super});
var root = try arc.root(alloc); var root = try arc.root(alloc);
defer root.close(); defer root.deinit();
} }
+141
View File
@@ -0,0 +1,141 @@
const std = @import("std");
const Io = std.Io;
const Decomp = @import("../decomp.zig");
const BlockSize = @import("../inode.zig").BlockSize;
const DataReader = @This();
alloc: std.mem.Allocator,
data: []u8,
decomp: Decomp.Fn,
block_size: u32,
size: u64,
blocks: []BlockSize,
frag: ?[]u8 = null,
idx: u32 = 0,
buf: []u8,
interface: Io.Reader = .{
.buffer = &[0]u8{},
.seek = 0,
.end = 0,
.vtable = &.{
.stream = stream,
.discard = discard,
.readVec = readVec,
},
},
pub fn init(alloc: std.mem.Allocator, data: []u8, decomp: Decomp.Fn, block_size: u32, start: u64, size: u64, blocks: []BlockSize) DataReader {
return .{
.alloc = alloc,
.data = data[start..],
.decomp = decomp,
.block_size = block_size,
.size = size,
.blocks = blocks,
.buf = if (blocks.len > 0) try alloc.alloc(u8, 1024 * 1024) else &[0]u8{},
};
}
pub fn deinit(self: DataReader) void {
self.alloc.free(self.buf);
}
pub fn addFrag(self: *DataReader, frag: []u8) void {
self.frag = frag;
}
fn advance(self: *DataReader) Io.Reader.Error!void {
if (self.idx > self.blocks.len) return error.EndOfStream;
defer self.idx += 1;
self.interface.seek = 0;
errdefer self.interface.end = 0;
if (self.idx == self.blocks.len) {
if (self.frag == null) return error.EndOfStream;
self.interface.buffer = self.frag.?;
self.interface.end = self.frag.?.len;
return;
}
self.interface.end = if (self.frag == null and self.idx == self.blocks.len - 1)
self.size % self.block_size
else
self.block_size;
const block = self.blocks[self.idx];
if (block.size == 0) {
@memset(self.buf[0..self.interface.end], 0);
self.interface.buffer = self.buf;
return;
}
if (block.uncompressed) {
self.interface.buffer = self.data;
self.data = self.data[self.interface.end..];
return;
}
_ = self.decomp(self.alloc, self.data[0..block.size], self.buf[0..self.interface.end]) catch return error.ReadFailed;
self.data = self.data[block.size..];
self.interface.buffer = self.buf;
return;
}
fn stream(rdr: *Io.Reader, wrt: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
if (rdr.seek >= rdr.end) {
var meta: *DataReader = @fieldParentPtr("interface", rdr);
try meta.advance();
}
if (limit == .nothing) return 0;
const size = @min(@intFromEnum(limit), rdr.end - rdr.seek);
const wrote = try wrt.write(rdr.buffer[rdr.seek..][0..size]);
rdr.seek += wrote;
return wrote;
}
fn discard(rdr: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
if (rdr.seek >= rdr.end) {
var meta: *DataReader = @fieldParentPtr("interface", rdr);
try meta.advance();
}
if (limit == .nothing) return 0;
const size = @min(@intFromEnum(limit), rdr.end - rdr.seek);
rdr.seek += size;
return size;
}
fn readVec(rdr: *Io.Reader, vec: [][]u8) Io.Reader.Error!usize {
if (rdr.seek >= rdr.end) {
var meta: *DataReader = @fieldParentPtr("interface", rdr);
try meta.advance();
}
var wrote: usize = 0;
for (vec) |s| {
const size = @min(rdr.end - rdr.seek, s.len);
@memcpy(s[0..size], rdr.buffer[rdr.seek..][0..size]);
wrote += size;
rdr.seek += size;
if (rdr.seek >= rdr.end) break;
}
return wrote;
}
+1 -1
View File
@@ -15,7 +15,7 @@ decomp: Decomp.Fn,
decomp_block: [8192]u8 = undefined, decomp_block: [8192]u8 = undefined,
interface: Io.Reader = .{ interface: Io.Reader = .{
.buffer = &[0]u8, .buffer = &[0]u8{},
.end = 0, .end = 0,
.seek = 0, .seek = 0,
.vtable = &.{ .vtable = &.{