Created DataReader (untested)
Other minor fixes & tweaks
This commit is contained in:
+3
-4
@@ -6,7 +6,6 @@ const util = @import("utils/util.zig");
|
||||
const File = @import("file.zig");
|
||||
const Inode = @import("inode.zig");
|
||||
const Decomp = @import("decomp.zig");
|
||||
|
||||
const Options = @import("options.zig");
|
||||
|
||||
const Archive = @This();
|
||||
@@ -16,7 +15,7 @@ map: Io.File.MemoryMap,
|
||||
super: Super,
|
||||
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, .{
|
||||
.len = try file.length(io) - 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,
|
||||
};
|
||||
}
|
||||
pub fn close(self: *Archive, io: Io) void {
|
||||
pub fn deinit(self: *Archive, io: Io) void {
|
||||
self.map.destroy(io);
|
||||
}
|
||||
|
||||
@@ -53,7 +52,7 @@ pub fn root(self: *Archive, alloc: std.mem.Allocator) !File {
|
||||
.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);
|
||||
defer root_file.deinit();
|
||||
|
||||
|
||||
+92
-1
@@ -4,6 +4,8 @@ const Io = std.Io;
|
||||
const Inode = @import("inode.zig");
|
||||
const Directory = @import("dir.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 File = @This();
|
||||
@@ -35,6 +37,31 @@ pub fn deinit(self: File) void {
|
||||
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 {
|
||||
switch (self.inode.header.type) {
|
||||
.dir, .ext_dir => {},
|
||||
@@ -47,6 +74,7 @@ pub fn open(self: File, alloc: std.mem.Allocator, filepath: []const u8) !File {
|
||||
return self.copy(alloc);
|
||||
|
||||
const first_element: []u8 = std.mem.sliceTo(path, '/');
|
||||
const final = first_element.len == path.len;
|
||||
|
||||
var dir_size: u32 = 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,
|
||||
}
|
||||
|
||||
const inode: Inode = {
|
||||
const entry: Directory.Entry = blk: {
|
||||
var dir: Directory = try .read(alloc, &dir_rdr.interface, dir_size);
|
||||
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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -246,7 +246,7 @@ pub const ExtDev = extern struct {
|
||||
xattr_idx: u32,
|
||||
|
||||
pub fn read(rdr: *Io.Reader) !ExtDev {
|
||||
return util.readValue(ExtDev, rdr);
|
||||
return util.readValueRdr(ExtDev, rdr);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+3
-3
@@ -12,11 +12,11 @@ test "Open" {
|
||||
var archive_file = try Io.Dir.cwd().openFile(io, TEST_ARCHIVE, .{});
|
||||
defer archive_file.close(io);
|
||||
|
||||
var arc: Archive = try .open(io, archive_file, 0);
|
||||
defer arc.close(io);
|
||||
var arc: Archive = try .init(io, archive_file, 0);
|
||||
defer arc.deinit(io);
|
||||
|
||||
std.debug.print("{}\n", .{arc.super});
|
||||
|
||||
var root = try arc.root(alloc);
|
||||
defer root.close();
|
||||
defer root.deinit();
|
||||
}
|
||||
|
||||
@@ -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
@@ -15,7 +15,7 @@ decomp: Decomp.Fn,
|
||||
decomp_block: [8192]u8 = undefined,
|
||||
|
||||
interface: Io.Reader = .{
|
||||
.buffer = &[0]u8,
|
||||
.buffer = &[0]u8{},
|
||||
.end = 0,
|
||||
.seek = 0,
|
||||
.vtable = &.{
|
||||
|
||||
Reference in New Issue
Block a user