Split archive-specific logic into own module
This commit is contained in:
parent
5f4e4cc811
commit
2792f27473
130
src/oar.zig
130
src/oar.zig
|
@ -1,29 +1,16 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const sys = @import("./sys.zig");
|
const sys = @import("./sys.zig");
|
||||||
|
const table = @import("./table.zig");
|
||||||
|
|
||||||
///
|
///
|
||||||
/// An entry block of an Oar archive file.
|
|
||||||
///
|
///
|
||||||
/// Typically, following this block in memory is the file data it holds the meta-information for.
|
|
||||||
///
|
///
|
||||||
pub const Entry = extern struct {
|
pub const Archive = struct {
|
||||||
signature: [3]u8 = signature_magic,
|
file_access: sys.FileAccess,
|
||||||
revision: u8,
|
index_cache: IndexCache,
|
||||||
name_buffer: [255]u8 = std.mem.zeroes([255]u8),
|
|
||||||
name_length: u8 = 0,
|
|
||||||
file_size: u64,
|
|
||||||
file_offset: u64,
|
|
||||||
padding: [232]u8 = std.mem.zeroes([232]u8),
|
|
||||||
|
|
||||||
comptime {
|
|
||||||
const entry_size = @sizeOf(Entry);
|
|
||||||
|
|
||||||
if (entry_size != 512)
|
|
||||||
@compileError("Entry is " ++ std.fmt.comptimePrint("{d}", .{entry_size}) ++ " bytes");
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// [FindError.EntryNotFound] happens when an entry could not be found.
|
/// [OpenError.EntryNotFound] happens when an entry could not be found.
|
||||||
///
|
///
|
||||||
pub const FindError = sys.FileAccess.Error || error {
|
pub const FindError = sys.FileAccess.Error || error {
|
||||||
EntryNotFound,
|
EntryNotFound,
|
||||||
|
@ -32,15 +19,110 @@ pub const Entry = extern struct {
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
pub fn find(file_access: sys.FileAccess, entry_name: []const u8) FindError!Entry {
|
pub const InitError = std.mem.Allocator.Error;
|
||||||
_ = file_access;
|
|
||||||
_ = entry_name;
|
|
||||||
|
|
||||||
return error.EntryNotFound;
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
const IndexCache = table.Hashed([]const u8, Entry.Header, table.string_context);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Finds an entry matching `entry_path` in `archive`.
|
||||||
|
///
|
||||||
|
/// The found [Entry] value is returned or a [FindError] if it failed to be found.
|
||||||
|
///
|
||||||
|
pub fn find(archive: *Archive, entry_path: []const u8) FindError!Entry {
|
||||||
|
return Entry{
|
||||||
|
.header = find_header: {
|
||||||
|
if (archive.index_cache.lookup(entry_path)) |entry_header|
|
||||||
|
break: find_header entry_header.*;
|
||||||
|
|
||||||
|
// Start from beginning of archive.
|
||||||
|
try archive.file_access.seek(0);
|
||||||
|
|
||||||
|
var entry_header = Entry.Header{
|
||||||
|
.revision = 0,
|
||||||
|
.file_size = 0,
|
||||||
|
.file_offset = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const read_buffer = std.mem.asBytes(&entry_header);
|
||||||
|
|
||||||
|
// Read first entry.
|
||||||
|
while ((try archive.file_access.read(read_buffer)) == @sizeOf(Entry.Header)) {
|
||||||
|
if (std.mem.eql(u8, entry_path, entry_header.
|
||||||
|
name_buffer[0 .. entry_header.name_length])) {
|
||||||
|
|
||||||
|
// If caching fails... oh well...
|
||||||
|
archive.index_cache.insert(entry_path, entry_header) catch {};
|
||||||
|
|
||||||
|
break: find_header entry_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move over file data following the entry.
|
||||||
|
var to_skip = entry_header.file_size;
|
||||||
|
|
||||||
|
while (to_skip != 0) {
|
||||||
|
const skipped = std.math.min(to_skip, std.math.maxInt(i64));
|
||||||
|
|
||||||
|
try archive.file_access.skip(@intCast(i64, skipped));
|
||||||
|
|
||||||
|
to_skip -= skipped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error.EntryNotFound;
|
||||||
|
},
|
||||||
|
|
||||||
|
.owner = &archive.file_access,
|
||||||
|
.cursor = 0,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Magic identifier used to validate [Entry] data.
|
|
||||||
///
|
///
|
||||||
const signature_magic = [3]u8{'o', 'a', 'r'};
|
///
|
||||||
|
pub fn init(allocator: std.mem.Allocator, archive_file_access: sys.FileAccess) InitError!Archive {
|
||||||
|
return Archive{
|
||||||
|
.index_cache = try IndexCache.init(allocator),
|
||||||
|
.file_access = archive_file_access,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Handles the state of an opened archive entry.
|
||||||
|
///
|
||||||
|
pub const Entry = struct {
|
||||||
|
owner: ?*sys.FileAccess,
|
||||||
|
cursor: u64,
|
||||||
|
header: Header,
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An entry block of an Oar archive file.
|
||||||
|
///
|
||||||
|
/// Typically, following the block in memory is the file data it holds the meta-information for.
|
||||||
|
///
|
||||||
|
pub const Header = extern struct {
|
||||||
|
signature: [signature_magic.len]u8 = signature_magic,
|
||||||
|
revision: u8,
|
||||||
|
name_buffer: [255]u8 = std.mem.zeroes([255]u8),
|
||||||
|
name_length: u8 = 0,
|
||||||
|
file_size: u64,
|
||||||
|
file_offset: u64,
|
||||||
|
padding: [232]u8 = std.mem.zeroes([232]u8),
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
const entry_size = @sizeOf(Header);
|
||||||
|
|
||||||
|
if (entry_size != 512)
|
||||||
|
@compileError("Entry is " ++
|
||||||
|
std.fmt.comptimePrint("{d}", .{entry_size}) ++ " bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Magic identifier used to validate [Entry] data.
|
||||||
|
///
|
||||||
|
pub const signature_magic = [3]u8{'o', 'a', 'r'};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
160
src/sys.zig
160
src/sys.zig
|
@ -8,7 +8,6 @@ const meta = @import("./meta.zig");
|
||||||
const oar = @import("./oar.zig");
|
const oar = @import("./oar.zig");
|
||||||
const stack = @import("./stack.zig");
|
const stack = @import("./stack.zig");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const table = @import("./table.zig");
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// A thread-safe platform abstraction over multiplexing system I/O processing and event handling.
|
/// A thread-safe platform abstraction over multiplexing system I/O processing and event handling.
|
||||||
|
@ -131,28 +130,25 @@ pub const AppContext = opaque {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Initializes a new [Implemenation] with `data_archive_file_access` as the data archive to
|
/// Initializes a new [Implemenation] with `data_access` as the data archive to read from
|
||||||
/// read from and `user_path_prefix` as the native writable user data directory.
|
/// and `user_path_prefix` as the native writable user data directory.
|
||||||
///
|
///
|
||||||
/// Returns the created [Implementation] value on success or [InitError] on failure.
|
/// Returns the created [Implementation] value on success or [InitError] on failure.
|
||||||
///
|
///
|
||||||
fn init(allocator: std.mem.Allocator,
|
fn init(allocator: std.mem.Allocator, data_access: FileAccess) InitError!Implementation {
|
||||||
data_archive_file_access: FileAccess) InitError!Implementation {
|
|
||||||
|
|
||||||
const user_path_prefix = ext.SDL_GetPrefPath("ona", "ona") orelse
|
const user_path_prefix = ext.SDL_GetPrefPath("ona", "ona") orelse
|
||||||
return error.OutOfMemory;
|
return error.OutOfMemory;
|
||||||
|
|
||||||
return Implementation{
|
return Implementation{
|
||||||
.user_file_system = .{.native = .{.path_prefix =
|
.user_file_system = .{.native =
|
||||||
user_path_prefix[0 .. std.mem.len(user_path_prefix)]}},
|
user_path_prefix[0 .. std.mem.len(user_path_prefix)]},
|
||||||
|
|
||||||
.message_semaphore = ext.SDL_CreateSemaphore(0) orelse return error.OutOfSemaphores,
|
.message_semaphore = ext.SDL_CreateSemaphore(0) orelse return error.OutOfSemaphores,
|
||||||
.message_mutex = ext.SDL_CreateMutex() orelse return error.OutOfMutexes,
|
.message_mutex = ext.SDL_CreateMutex() orelse return error.OutOfMutexes,
|
||||||
.user_path_prefix = user_path_prefix,
|
.user_path_prefix = user_path_prefix,
|
||||||
|
|
||||||
.data_file_system = .{.archive = .{
|
.data_file_system = .{.archive = .{
|
||||||
.file_access = data_archive_file_access,
|
.instance = try oar.Archive.init(allocator, data_access),
|
||||||
.index_cache = try FileSystem.ArchiveIndexCache.init(allocator),
|
|
||||||
}},
|
}},
|
||||||
|
|
||||||
.message_thread = null,
|
.message_thread = null,
|
||||||
|
@ -283,6 +279,7 @@ pub const FileAccess = struct {
|
||||||
read: fn (*anyopaque, []u8) Error!usize,
|
read: fn (*anyopaque, []u8) Error!usize,
|
||||||
seek: fn (*anyopaque, u64) Error!void,
|
seek: fn (*anyopaque, u64) Error!void,
|
||||||
seekToEnd: fn (*anyopaque) Error!void,
|
seekToEnd: fn (*anyopaque) Error!void,
|
||||||
|
skip: fn (*anyopaque, i64) Error!void,
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -343,14 +340,22 @@ pub const FileAccess = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Attempts to seek `file_access` to the end of the file while using `app_context` as the execution
|
/// Attempts to seek `file_access` to the end of the file.
|
||||||
/// context.
|
|
||||||
///
|
///
|
||||||
/// Returns [Error] on failure.
|
/// Returns [Error] on failure.
|
||||||
///
|
///
|
||||||
pub fn seekToEnd(file_access: *FileAccess) Error!void {
|
pub fn seekToEnd(file_access: *FileAccess) Error!void {
|
||||||
return file_access.implementation.seekToEnd(file_access.context);
|
return file_access.implementation.seekToEnd(file_access.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Attempts to seek `file_access` by `offset` from the current file position.
|
||||||
|
///
|
||||||
|
/// Returns [Error] on failure;
|
||||||
|
///
|
||||||
|
pub fn skip(file_access: *FileAccess, offset: i64) Error!void {
|
||||||
|
return file_access.implementation.skip(file_access.context, offset);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -358,31 +363,15 @@ pub const FileAccess = struct {
|
||||||
/// available to the application in a sandboxed environment.
|
/// available to the application in a sandboxed environment.
|
||||||
///
|
///
|
||||||
pub const FileSystem = union(enum) {
|
pub const FileSystem = union(enum) {
|
||||||
native: struct {
|
native: []const u8,
|
||||||
path_prefix: []const u8,
|
|
||||||
},
|
|
||||||
|
|
||||||
archive: struct {
|
archive: struct {
|
||||||
file_access: FileAccess,
|
instance: oar.Archive,
|
||||||
index_cache: ArchiveIndexCache,
|
entry_table: [max_open_entries]oar.Entry = std.mem.zeroes([max_open_entries]oar.Entry),
|
||||||
|
|
||||||
entry_table: [max_open_entries]ArchiveEntry =
|
pub const max_open_entries = 16;
|
||||||
std.mem.zeroes([max_open_entries]ArchiveEntry),
|
|
||||||
|
|
||||||
const max_open_entries = 16;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
///
|
|
||||||
/// Handles the state of an opened archive entry.
|
|
||||||
///
|
|
||||||
const ArchiveEntry = struct {
|
|
||||||
using: ?*FileAccess,
|
|
||||||
header: oar.Entry,
|
|
||||||
cursor: u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ArchiveIndexCache = table.Hashed([]const u8, oar.Entry, table.string_context);
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Platform-agnostic mechanism for referencing files and directories on a [FileSystem].
|
/// Platform-agnostic mechanism for referencing files and directories on a [FileSystem].
|
||||||
///
|
///
|
||||||
|
@ -462,57 +451,37 @@ pub const FileSystem = union(enum) {
|
||||||
.archive => |*archive| {
|
.archive => |*archive| {
|
||||||
if (mode != .readonly) return error.ModeUnsupported;
|
if (mode != .readonly) return error.ModeUnsupported;
|
||||||
|
|
||||||
for (archive.entry_table) |*entry| if (entry.using == null) {
|
for (archive.entry_table) |*entry| if (entry.owner == null) {
|
||||||
const entry_path = path.buffer[0 .. path.length];
|
|
||||||
|
|
||||||
entry.* = .{
|
|
||||||
.header = find_header: {
|
|
||||||
if (archive.index_cache.lookup(entry_path)) |header|
|
|
||||||
break: find_header header.*;
|
|
||||||
|
|
||||||
const header = oar.Entry.find(archive.file_access,
|
|
||||||
entry_path) catch return error.FileNotFound;
|
|
||||||
|
|
||||||
// If caching fails... oh well...
|
|
||||||
archive.index_cache.insert(entry_path, header) catch {};
|
|
||||||
|
|
||||||
break: find_header header;
|
|
||||||
},
|
|
||||||
|
|
||||||
.using = &archive.file_access,
|
|
||||||
.cursor = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
const Implementation = struct {
|
const Implementation = struct {
|
||||||
fn archiveEntryCast(context: *anyopaque) *ArchiveEntry {
|
fn close(context: *anyopaque) void {
|
||||||
return @ptrCast(*ArchiveEntry, @alignCast(
|
entryCast(context).owner = null;
|
||||||
@alignOf(ArchiveEntry), context));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(context: *anyopaque) void {
|
fn entryCast(context: *anyopaque) *oar.Entry {
|
||||||
archiveEntryCast(context).using = null;
|
return @ptrCast(*oar.Entry, @alignCast(
|
||||||
|
@alignOf(oar.Entry), context));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queryCursor(context: *anyopaque) FileAccess.Error!u64 {
|
fn queryCursor(context: *anyopaque) FileAccess.Error!u64 {
|
||||||
const archive_entry = archiveEntryCast(context);
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
if (archive_entry.using == null) return error.FileInaccessible;
|
if (archive_entry.owner == null) return error.FileInaccessible;
|
||||||
|
|
||||||
return archive_entry.cursor;
|
return archive_entry.cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn queryLength(context: *anyopaque) FileAccess.Error!u64 {
|
fn queryLength(context: *anyopaque) FileAccess.Error!u64 {
|
||||||
const archive_entry = archiveEntryCast(context);
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
if (archive_entry.using == null) return error.FileInaccessible;
|
if (archive_entry.owner == null) return error.FileInaccessible;
|
||||||
|
|
||||||
return archive_entry.header.file_size;
|
return archive_entry.header.file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(context: *anyopaque, buffer: []u8) FileAccess.Error!usize {
|
fn read(context: *anyopaque, buffer: []u8) FileAccess.Error!usize {
|
||||||
const archive_entry = archiveEntryCast(context);
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
const file_access = archive_entry.using orelse
|
const file_access = archive_entry.owner orelse
|
||||||
return error.FileInaccessible;
|
return error.FileInaccessible;
|
||||||
|
|
||||||
if (archive_entry.cursor >= archive_entry.header.file_size)
|
if (archive_entry.cursor >= archive_entry.header.file_size)
|
||||||
|
@ -525,22 +494,42 @@ pub const FileSystem = union(enum) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(context: *anyopaque, cursor: usize) FileAccess.Error!void {
|
fn seek(context: *anyopaque, cursor: usize) FileAccess.Error!void {
|
||||||
const archive_entry = archiveEntryCast(context);
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
if (archive_entry.using == null) return error.FileInaccessible;
|
if (archive_entry.owner == null) return error.FileInaccessible;
|
||||||
|
|
||||||
archive_entry.cursor = cursor;
|
archive_entry.cursor = cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seekToEnd(context: *anyopaque) FileAccess.Error!void {
|
fn seekToEnd(context: *anyopaque) FileAccess.Error!void {
|
||||||
const archive_entry = archiveEntryCast(context);
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
if (archive_entry.using == null) return error.FileInaccessible;
|
if (archive_entry.owner == null) return error.FileInaccessible;
|
||||||
|
|
||||||
archive_entry.cursor = archive_entry.header.file_size;
|
archive_entry.cursor = archive_entry.header.file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn skip(context: *anyopaque, offset: i64) FileAccess.Error!void {
|
||||||
|
const math = std.math;
|
||||||
|
const archive_entry = entryCast(context);
|
||||||
|
|
||||||
|
if (archive_entry.owner == null) return error.FileInaccessible;
|
||||||
|
|
||||||
|
if (offset < 0) {
|
||||||
|
archive_entry.cursor = math.max(0,
|
||||||
|
archive_entry.cursor - math.absCast(offset));
|
||||||
|
} else {
|
||||||
|
archive_entry.cursor += @intCast(u64, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
entry.* = archive.instance.find(path.buffer[0 .. path.length]) catch |err|
|
||||||
|
return switch (err) {
|
||||||
|
error.FileInaccessible => error.FileNotFound,
|
||||||
|
error.EntryNotFound => error.FileNotFound,
|
||||||
|
};
|
||||||
|
|
||||||
return FileAccess{
|
return FileAccess{
|
||||||
.context = entry,
|
.context = entry,
|
||||||
|
|
||||||
|
@ -551,6 +540,7 @@ pub const FileSystem = union(enum) {
|
||||||
.read = Implementation.read,
|
.read = Implementation.read,
|
||||||
.seek = Implementation.seek,
|
.seek = Implementation.seek,
|
||||||
.seekToEnd = Implementation.seekToEnd,
|
.seekToEnd = Implementation.seekToEnd,
|
||||||
|
.skip = Implementation.skip,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -559,22 +549,19 @@ pub const FileSystem = union(enum) {
|
||||||
},
|
},
|
||||||
|
|
||||||
.native => |native| {
|
.native => |native| {
|
||||||
if (native.path_prefix.len == 0) return error.FileNotFound;
|
if (native.len == 0) return error.FileNotFound;
|
||||||
|
|
||||||
var path_buffer = std.mem.zeroes([4096]u8);
|
var path_buffer = std.mem.zeroes([4096]u8);
|
||||||
|
const seperator_length = @boolToInt(native[native.len - 1] != seperator);
|
||||||
|
|
||||||
const seperator_length = @boolToInt(native.path_prefix[
|
if ((native.len + seperator_length + path.length) >=
|
||||||
native.path_prefix.len - 1] != seperator);
|
|
||||||
|
|
||||||
if ((native.path_prefix.len + seperator_length + path.length) >=
|
|
||||||
path_buffer.len) return error.FileNotFound;
|
path_buffer.len) return error.FileNotFound;
|
||||||
|
|
||||||
std.mem.copy(u8, path_buffer[0 ..], native.path_prefix);
|
std.mem.copy(u8, path_buffer[0 ..], native);
|
||||||
|
|
||||||
if (seperator_length != 0)
|
if (seperator_length != 0) path_buffer[native.len] = seperator;
|
||||||
path_buffer[native.path_prefix.len] = seperator;
|
|
||||||
|
|
||||||
std.mem.copy(u8, path_buffer[native.path_prefix.len ..
|
std.mem.copy(u8, path_buffer[native.len ..
|
||||||
path_buffer.len], path.buffer[0 .. path.length]);
|
path_buffer.len], path.buffer[0 .. path.length]);
|
||||||
|
|
||||||
ext.SDL_ClearError();
|
ext.SDL_ClearError();
|
||||||
|
@ -629,15 +616,14 @@ pub const FileSystem = union(enum) {
|
||||||
|
|
||||||
while (to_seek != 0) {
|
while (to_seek != 0) {
|
||||||
const math = std.math;
|
const math = std.math;
|
||||||
const sought = @intCast(i64, math.min(to_seek, math.maxInt(i64)));
|
const sought = math.min(to_seek, math.maxInt(i64));
|
||||||
|
|
||||||
ext.SDL_ClearError();
|
ext.SDL_ClearError();
|
||||||
|
|
||||||
if (ext.SDL_RWseek(rwOpsCast(context), sought, ext.RW_SEEK_CUR) < 0)
|
if (ext.SDL_RWseek(rwOpsCast(context), @intCast(i64, sought),
|
||||||
return error.FileInaccessible;
|
ext.RW_SEEK_CUR) < 0) return error.FileInaccessible;
|
||||||
|
|
||||||
// Cannot be less than zero because it is derived from `read`.
|
to_seek -= sought;
|
||||||
to_seek -= @intCast(u64, sought);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +633,13 @@ pub const FileSystem = union(enum) {
|
||||||
if (ext.SDL_RWseek(rwOpsCast(context), 0, ext.RW_SEEK_END) < 0)
|
if (ext.SDL_RWseek(rwOpsCast(context), 0, ext.RW_SEEK_END) < 0)
|
||||||
return error.FileInaccessible;
|
return error.FileInaccessible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn skip(context: *anyopaque, offset: i64) FileAccess.Error!void {
|
||||||
|
ext.SDL_ClearError();
|
||||||
|
|
||||||
|
if (ext.SDL_RWseek(rwOpsCast(context), offset, ext.RW_SEEK_SET) < 0)
|
||||||
|
return error.FileInaccessible;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return FileAccess{
|
return FileAccess{
|
||||||
|
@ -663,6 +656,7 @@ pub const FileSystem = union(enum) {
|
||||||
.read = Implementation.read,
|
.read = Implementation.read,
|
||||||
.seek = Implementation.seek,
|
.seek = Implementation.seek,
|
||||||
.seekToEnd = Implementation.seekToEnd,
|
.seekToEnd = Implementation.seekToEnd,
|
||||||
|
.skip = Implementation.skip,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -855,7 +849,7 @@ pub fn runGraphics(comptime Error: anytype,
|
||||||
|
|
||||||
defer ext.SDL_DestroyRenderer(renderer);
|
defer ext.SDL_DestroyRenderer(renderer);
|
||||||
|
|
||||||
var cwd_file_system = FileSystem{.native =.{.path_prefix = "./"}};
|
var cwd_file_system = FileSystem{.native ="./"};
|
||||||
var data_access = try (try cwd_file_system.joinedPath(&.{"./data.oar"})).open(.readonly);
|
var data_access = try (try cwd_file_system.joinedPath(&.{"./data.oar"})).open(.readonly);
|
||||||
|
|
||||||
defer data_access.close();
|
defer data_access.close();
|
||||||
|
|
Loading…
Reference in New Issue