Mostly finished data reader
This commit is contained in:
+3
-6
@@ -3,7 +3,7 @@ const io = std.io;
|
|||||||
|
|
||||||
const InodeType = @import("inode/inode.zig").InodeType;
|
const InodeType = @import("inode/inode.zig").InodeType;
|
||||||
|
|
||||||
const DirHeader = packed struct {
|
const DirHeader = extern struct {
|
||||||
count: u32,
|
count: u32,
|
||||||
inode_block_start: u32,
|
inode_block_start: u32,
|
||||||
inode_num: u32,
|
inode_num: u32,
|
||||||
@@ -48,12 +48,9 @@ pub fn readDirectory(alloc: std.mem.Allocator, rdr: io.AnyReader, size: u64) !st
|
|||||||
var out: std.StringHashMap(DirEntry) = .init(alloc);
|
var out: std.StringHashMap(DirEntry) = .init(alloc);
|
||||||
errdefer out.deinit();
|
errdefer out.deinit();
|
||||||
var red_size: u64 = 3;
|
var red_size: u64 = 3;
|
||||||
var hdr: DirHeader align(4) = undefined;
|
var hdr: DirHeader = undefined;
|
||||||
// rdr.readStruct reads 16 bytes, due to alignment. get around this by manually reading the memory and decoding
|
|
||||||
var hdr_tmp: [12]u8 = [_]u8{0} ** 12;
|
|
||||||
while (red_size < size) {
|
while (red_size < size) {
|
||||||
_ = try rdr.readAll(&hdr_tmp);
|
hdr = try rdr.readStruct(DirHeader);
|
||||||
hdr = std.mem.bytesToValue(DirHeader, &hdr_tmp);
|
|
||||||
red_size += 12;
|
red_size += 12;
|
||||||
var i: u32 = 0;
|
var i: u32 = 0;
|
||||||
try out.ensureUnusedCapacity(hdr.count + 1);
|
try out.ensureUnusedCapacity(hdr.count + 1);
|
||||||
|
|||||||
+8
-7
@@ -26,12 +26,12 @@ pub const File = struct {
|
|||||||
pub fn deinit(self: *File, alloc: std.mem.Allocator) void {
|
pub fn deinit(self: *File, alloc: std.mem.Allocator) void {
|
||||||
self.inode.deinit();
|
self.inode.deinit();
|
||||||
alloc.free(self.name);
|
alloc.free(self.name);
|
||||||
if (self.hasEntries) {
|
if (self.dirEntries != null) {
|
||||||
var iter = self.dirEntries.iterator();
|
var iter = self.dirEntries.?.iterator();
|
||||||
while (iter.next()) |ent| {
|
while (iter.next()) |ent| {
|
||||||
ent.value_ptr.deinit(alloc);
|
ent.value_ptr.deinit(alloc);
|
||||||
}
|
}
|
||||||
self.dirEntries.deinit();
|
self.dirEntries.?.deinit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ pub const File = struct {
|
|||||||
try self.readDirEntries(reader);
|
try self.readDirEntries(reader);
|
||||||
const split_idx = std.mem.indexOf(u8, clean_path, "/") orelse clean_path.len;
|
const split_idx = std.mem.indexOf(u8, clean_path, "/") orelse clean_path.len;
|
||||||
const name = clean_path[0..split_idx];
|
const name = clean_path[0..split_idx];
|
||||||
const ent = self.dirEntries.get(name);
|
const ent = self.dirEntries.?.get(name);
|
||||||
if (ent == null) {
|
if (ent == null) {
|
||||||
return FileError.NotFound;
|
return FileError.NotFound;
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,6 @@ pub const File = struct {
|
|||||||
defer meta_rdr.deinit();
|
defer meta_rdr.deinit();
|
||||||
try meta_rdr.skip(offset);
|
try meta_rdr.skip(offset);
|
||||||
self.dirEntries = try directory.readDirectory(reader.alloc, meta_rdr.any(), size);
|
self.dirEntries = try directory.readDirectory(reader.alloc, meta_rdr.any(), size);
|
||||||
self.hasEntries = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: *File, bytes: []u8) !usize {
|
pub fn read(self: *File, bytes: []u8) !usize {
|
||||||
@@ -117,15 +116,17 @@ fn fileFromDirEntry(read: *Reader, ent: DirEntry) !File {
|
|||||||
try meta_rdr.skip(ent.offset);
|
try meta_rdr.skip(ent.offset);
|
||||||
// Copy name so we can clean-up the DirEntrys without causing issues.
|
// Copy name so we can clean-up the DirEntrys without causing issues.
|
||||||
const name = try read.alloc.alloc(u8, ent.name.len);
|
const name = try read.alloc.alloc(u8, ent.name.len);
|
||||||
std.mem.copyForwards(u8, name, ent.name);
|
errdefer read.alloc.free(name);
|
||||||
|
@memcpy(name, ent.name);
|
||||||
var out: File = .{
|
var out: File = .{
|
||||||
.name = name,
|
.name = name,
|
||||||
.inode = .init(
|
.inode = try .init(
|
||||||
read.alloc,
|
read.alloc,
|
||||||
meta_rdr.any(),
|
meta_rdr.any(),
|
||||||
read.super.block_size,
|
read.super.block_size,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
errdefer out.deinit(read.alloc);
|
||||||
out.data_rdr = switch (out.inode.data) {
|
out.data_rdr = switch (out.inode.data) {
|
||||||
.file, .ext_file => try .init(&out, read),
|
.file, .ext_file => try .init(&out, read),
|
||||||
else => null,
|
else => null,
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ const std = @import("std");
|
|||||||
|
|
||||||
const inode = @import("inode/inode.zig");
|
const inode = @import("inode/inode.zig");
|
||||||
|
|
||||||
|
const Table = @import("table.zig").Table;
|
||||||
const FileHolder = @import("readers/file_holder.zig").FileHolder;
|
const FileHolder = @import("readers/file_holder.zig").FileHolder;
|
||||||
const Superblock = @import("superblock.zig").Superblock;
|
const Superblock = @import("superblock.zig").Superblock;
|
||||||
const File = @import("file.zig").File;
|
const File = @import("file.zig").File;
|
||||||
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
||||||
const DirEntry = @import("directory.zig").DirEntry;
|
const DirEntry = @import("directory.zig").DirEntry;
|
||||||
|
const FragEntry = @import("readers/data.zig").FragEntry;
|
||||||
|
|
||||||
pub const Reader = struct {
|
pub const Reader = struct {
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
@@ -14,6 +16,10 @@ pub const Reader = struct {
|
|||||||
super: Superblock,
|
super: Superblock,
|
||||||
root: File,
|
root: File,
|
||||||
|
|
||||||
|
frag_table: Table(FragEntry),
|
||||||
|
export_table: Table(inode.InodeRef),
|
||||||
|
id_table: Table(u32),
|
||||||
|
|
||||||
pub fn init(alloc: std.mem.Allocator, filepath: []const u8, offset: u64) !Reader {
|
pub fn init(alloc: std.mem.Allocator, filepath: []const u8, offset: u64) !Reader {
|
||||||
var holder: FileHolder = try .init(filepath, offset);
|
var holder: FileHolder = try .init(filepath, offset);
|
||||||
const super: Superblock = try holder.reader().readStruct(Superblock);
|
const super: Superblock = try holder.reader().readStruct(Superblock);
|
||||||
@@ -23,7 +29,25 @@ pub const Reader = struct {
|
|||||||
.holder = holder,
|
.holder = holder,
|
||||||
.super = super,
|
.super = super,
|
||||||
.root = undefined,
|
.root = undefined,
|
||||||
|
.frag_table = undefined,
|
||||||
|
.export_table = undefined,
|
||||||
|
.id_table = undefined,
|
||||||
};
|
};
|
||||||
|
out.frag_table = .init(
|
||||||
|
&out,
|
||||||
|
super.frag_table_start,
|
||||||
|
super.frag_count,
|
||||||
|
);
|
||||||
|
out.export_table = .init(
|
||||||
|
&out,
|
||||||
|
super.export_table_start,
|
||||||
|
super.inode_count,
|
||||||
|
);
|
||||||
|
out.id_table = .init(
|
||||||
|
&out,
|
||||||
|
super.id_table_start,
|
||||||
|
super.id_count,
|
||||||
|
);
|
||||||
out.root = try out.fileFromRef(super.root_ref, "");
|
out.root = try out.fileFromRef(super.root_ref, "");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
+61
-12
@@ -5,6 +5,9 @@ const File = @import("../file.zig").File;
|
|||||||
const Reader = @import("../reader.zig").Reader;
|
const Reader = @import("../reader.zig").Reader;
|
||||||
const BlockSize = @import("../inode/file.zig").BlockSize;
|
const BlockSize = @import("../inode/file.zig").BlockSize;
|
||||||
const DecompressionType = @import("../decompress.zig").DecompressType;
|
const DecompressionType = @import("../decompress.zig").DecompressType;
|
||||||
|
const FileOffsetReader = @import("../readers/file_holder.zig").FileOffsetReader;
|
||||||
|
|
||||||
|
pub const FragEntry = packed struct { start: u64, size: BlockSize, _: u32 };
|
||||||
|
|
||||||
const DataReaderError = error{
|
const DataReaderError = error{
|
||||||
EOF,
|
EOF,
|
||||||
@@ -13,25 +16,25 @@ const DataReaderError = error{
|
|||||||
pub const DataReader = struct {
|
pub const DataReader = struct {
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
decomp: DecompressionType,
|
decomp: DecompressionType,
|
||||||
rdr: io.AnyReader,
|
rdr: FileOffsetReader,
|
||||||
block_size: u32,
|
block_size: u32,
|
||||||
sizes: []BlockSize,
|
sizes: []BlockSize,
|
||||||
frag_rdr: ?io.AnyReader,
|
frag_rdr: ?DataReader = null,
|
||||||
|
|
||||||
next_block_num: u32 = 0,
|
next_block_num: u32 = 0,
|
||||||
cur_bloc: []u8 = undefined,
|
cur_bloc: []u8 = undefined,
|
||||||
cur_offset: u32 = 0,
|
cur_offset: u32 = 0,
|
||||||
|
|
||||||
pub fn init(fil: *File, reader: *Reader) !DataReader {
|
pub fn init(fil: *File, reader: *Reader) !DataReader {
|
||||||
const data_start: u64 = 0;
|
var data_start: u64 = 0;
|
||||||
const sizes: []BlockSize = undefined;
|
var sizes: []BlockSize = undefined;
|
||||||
const size: u64 = 0;
|
var size: u64 = 0;
|
||||||
const frag_idx: u32 = 0;
|
var frag_idx: u32 = 0;
|
||||||
const frag_offset: u32 = 0;
|
var frag_offset: u32 = 0;
|
||||||
switch (fil.inode.data) {
|
switch (fil.inode.data) {
|
||||||
.file => |f| {
|
.file => |f| {
|
||||||
sizes = try reader.alloc.alloc(BlockSize, f.blocks.len);
|
sizes = try reader.alloc.alloc(BlockSize, f.blocks.len);
|
||||||
std.mem.copyForwards(BlockSize, sizes, f.blocks);
|
@memcpy(sizes, f.blocks);
|
||||||
data_start = f.data_start;
|
data_start = f.data_start;
|
||||||
size = f.size;
|
size = f.size;
|
||||||
frag_idx = f.frag_idx;
|
frag_idx = f.frag_idx;
|
||||||
@@ -39,7 +42,7 @@ pub const DataReader = struct {
|
|||||||
},
|
},
|
||||||
.ext_file => |f| {
|
.ext_file => |f| {
|
||||||
sizes = try reader.alloc.alloc(BlockSize, f.blocks.len);
|
sizes = try reader.alloc.alloc(BlockSize, f.blocks.len);
|
||||||
std.mem.copyForwards(BlockSize, sizes, f.blocks);
|
@memcpy(sizes, f.blocks);
|
||||||
data_start = f.data_start;
|
data_start = f.data_start;
|
||||||
size = f.size;
|
size = f.size;
|
||||||
frag_idx = f.frag_idx;
|
frag_idx = f.frag_idx;
|
||||||
@@ -47,11 +50,37 @@ pub const DataReader = struct {
|
|||||||
},
|
},
|
||||||
else => return File.FileError.NotNormalFile,
|
else => return File.FileError.NotNormalFile,
|
||||||
}
|
}
|
||||||
//TODO: set-up frag_rdr
|
var out: DataReader = .{
|
||||||
|
.alloc = reader.alloc,
|
||||||
|
.decomp = reader.super.decomp,
|
||||||
|
.rdr = reader.holder.readerAt(data_start),
|
||||||
|
.block_size = reader.super.block_size,
|
||||||
|
.sizes = sizes,
|
||||||
|
};
|
||||||
|
errdefer out.deinit();
|
||||||
|
if (frag_idx != 0xFFFFFFFF) {
|
||||||
|
const frag_entry = try reader.frag_table.getValue(frag_idx);
|
||||||
|
out.frag_rdr = try .fromFragEntry(reader, frag_entry);
|
||||||
|
try out.frag_rdr.?.skip(frag_offset);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
fn fromFragEntry(reader: *Reader, ent: FragEntry) !DataReader {
|
||||||
|
const size = try reader.alloc.alloc(BlockSize, 1);
|
||||||
|
size[0] = ent.size;
|
||||||
|
return .{
|
||||||
|
.alloc = reader.alloc,
|
||||||
|
.decomp = reader.super.decomp,
|
||||||
|
.rdr = reader.holder.readerAt(ent.start),
|
||||||
|
.block_size = reader.super.block_size,
|
||||||
|
.sizes = size,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *DataReader) void {
|
pub fn deinit(self: *DataReader) void {
|
||||||
|
self.alloc.free(self.sizes);
|
||||||
if (self.cur_bloc.len > 0) self.alloc.free(self.cur_bloc);
|
if (self.cur_bloc.len > 0) self.alloc.free(self.cur_bloc);
|
||||||
|
if (self.frag_rdr != null) self.frag_rdr.?.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn skip(self: *DataReader, offset: u32) !void {
|
pub fn skip(self: *DataReader, offset: u32) !void {
|
||||||
@@ -73,11 +102,31 @@ pub const DataReader = struct {
|
|||||||
const siz = self.sizes[self.next_block_num];
|
const siz = self.sizes[self.next_block_num];
|
||||||
self.next_block_num += 1;
|
self.next_block_num += 1;
|
||||||
if (self.next_block_num == self.sizes.len - 1 and self.frag_rdr != null) {
|
if (self.next_block_num == self.sizes.len - 1 and self.frag_rdr != null) {
|
||||||
|
try self.sizeBlock(self.sizes % self.block_size);
|
||||||
_ = try self.frag_rdr.?.readAll(self.cur_bloc);
|
_ = try self.frag_rdr.?.readAll(self.cur_bloc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (siz.size == 0) {}
|
if (siz.size == 0) {
|
||||||
if (siz.not_compressed) {}
|
try self.sizeBlock(self.block_size);
|
||||||
|
@memset(self.cur_bloc, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (siz.not_compressed) {
|
||||||
|
try self.sizeBlock(siz.size);
|
||||||
|
_ = try self.rdr.any().readAll(self.cur_bloc);
|
||||||
|
} else {
|
||||||
|
self.alloc.free(self.cur_bloc);
|
||||||
|
var limit = std.io.limitedReader(self.reader, siz.size);
|
||||||
|
var dat = try self.decomp.decompress(self.alloc, limit.reader().any());
|
||||||
|
self.block = try dat.toOwnedSlice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sizeBlock(self: *DataReader, size: u32) !void {
|
||||||
|
if (!self.alloc.resize(u8, size)) {
|
||||||
|
self.alloc.free(self.cur_bloc);
|
||||||
|
self.cur_bloc = try self.alloc.alloc(u8, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(self: *DataReader, bytes: []u8) !usize {
|
pub fn read(self: *DataReader, bytes: []u8) !usize {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ pub const FileHolder = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const FileOffsetReader = struct {
|
pub const FileOffsetReader = struct {
|
||||||
file: *File,
|
file: *File,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const Reader = @import("reader.zig").Reader;
|
||||||
|
const DecompressType = @import("decompress.zig").DecompressType;
|
||||||
|
const FileHolder = @import("readers/file_holder.zig").FileHolder;
|
||||||
|
const FileOffsetReader = @import("readers/file_holder.zig").FileOffsetReader;
|
||||||
|
const MetadataReader = @import("readers/metadata.zig").MetadataReader;
|
||||||
|
|
||||||
|
const TableError = error{InvalidIndex};
|
||||||
|
|
||||||
|
pub fn Table(
|
||||||
|
comptime T: type,
|
||||||
|
) type {
|
||||||
|
return struct {
|
||||||
|
alloc: std.mem.Allocator,
|
||||||
|
decomp: DecompressType,
|
||||||
|
holder: *FileHolder,
|
||||||
|
table: []T = &[0]T{},
|
||||||
|
offset: u64,
|
||||||
|
item_count: u32,
|
||||||
|
|
||||||
|
pub fn init(read: *Reader, offset: u64, item_count: u32) Self {
|
||||||
|
return .{
|
||||||
|
.alloc = read.alloc,
|
||||||
|
.decomp = read.super.decomp,
|
||||||
|
.holder = &read.holder,
|
||||||
|
.offset = offset,
|
||||||
|
.item_count = item_count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn deinit(self: *Self, alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getValue(self: *Self, i: u64) !T {
|
||||||
|
if (i >= self.item_count) return TableError.InvalidIndex;
|
||||||
|
if (self.table.len - 1 > i) return self.table[i];
|
||||||
|
var meta_rdr: MetadataReader = undefined;
|
||||||
|
var offset_rdr: FileOffsetReader = undefined;
|
||||||
|
var meta_offset: u64 = 0;
|
||||||
|
var to_read: u32 = 0;
|
||||||
|
while (self.table.len < i) {
|
||||||
|
_ = try self.holder.file.preadAll(std.mem.sliceAsBytes(&meta_offset), self.offset);
|
||||||
|
self.offset += 8;
|
||||||
|
offset_rdr = self.holder.readerAt(meta_offset);
|
||||||
|
meta_rdr = .init(self.alloc, self.decomp, offset_rdr.any());
|
||||||
|
defer meta_rdr.deinit();
|
||||||
|
to_read = @min(self.item_count - self.table.len, comptime blk: {
|
||||||
|
break :blk 8192 / @sizeOf(T);
|
||||||
|
});
|
||||||
|
if (!self.alloc.resize(self.table, self.table.len + to_read)) {
|
||||||
|
const alloc_size = self.table.len + to_read;
|
||||||
|
self.alloc.free(self.table);
|
||||||
|
self.table = try self.alloc.alloc(T, alloc_size);
|
||||||
|
}
|
||||||
|
_ = try meta_rdr.any().readAll(std.mem.asBytes(self.table[self.table.len - to_read ..]));
|
||||||
|
}
|
||||||
|
return self.table[i];
|
||||||
|
}
|
||||||
|
const Self: type = @This();
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user