202 lines
5.7 KiB
Zig
Executable File
202 lines
5.7 KiB
Zig
Executable File
const coral = @import("coral");
|
|
|
|
const ext = @import("./ext.zig");
|
|
|
|
pub const FileAccessor = struct {
|
|
context: *anyopaque,
|
|
|
|
actions: *const struct {
|
|
open_readable: *const fn (context: *anyopaque, file_path: []const u8) OpenError!*ReadableFile,
|
|
open_writable: *const fn (context: *anyopaque, file_path: []const u8) OpenError!*WritableFile,
|
|
query: *const fn (context: *anyopaque, file_path: []const u8) QueryError!FileInfo,
|
|
},
|
|
|
|
pub fn bind(comptime State: type, state: *State) FileAccessor {
|
|
const Actions = struct {
|
|
fn as_concrete(context: *anyopaque) *State {
|
|
return @ptrCast(*State, @alignCast(@alignOf(State), context));
|
|
}
|
|
|
|
fn open_readable(context: *anyopaque, file_path: []const u8) OpenError!*ReadableFile {
|
|
return as_concrete(context).open_readable(file_path);
|
|
}
|
|
|
|
fn open_writable(context: *anyopaque, file_path: []const u8) OpenError!*WritableFile {
|
|
return as_concrete(context).open_writable(file_path);
|
|
}
|
|
|
|
fn query(context: *anyopaque, file_path: []const u8) QueryError!FileInfo {
|
|
return as_concrete(context).query(file_path);
|
|
}
|
|
};
|
|
|
|
return .{
|
|
.context = @ptrCast(*anyopaque, state),
|
|
|
|
.actions = &.{
|
|
.open_readable = Actions.open_readable,
|
|
.open_writable = Actions.open_writable,
|
|
.query = Actions.query,
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn open_readable(self: FileAccessor, file_path: []const u8) OpenError!*ReadableFile {
|
|
return self.actions.open_readable(self.context, file_path);
|
|
}
|
|
|
|
pub fn open_writable(self: FileAccessor, file_path: []const u8) OpenError!*WritableFile {
|
|
return self.actions.open_readable(self.context, file_path);
|
|
}
|
|
|
|
pub fn query(self: FileAccessor, file_path: []const u8) QueryError!FileInfo {
|
|
return self.actions.query(self.context, file_path);
|
|
}
|
|
};
|
|
|
|
pub const FileInfo = struct {
|
|
size: u64,
|
|
};
|
|
|
|
pub const FileSandbox = struct {
|
|
prefix: []const u8,
|
|
|
|
flags: packed struct {
|
|
is_readable: bool = false,
|
|
is_writable: bool = false,
|
|
is_queryable: bool = false,
|
|
},
|
|
|
|
const native_path_max = 4095;
|
|
|
|
fn native_path_of(file_sandbox: *FileSandbox, file_path: []const u8) [native_path_max + 1]u8 {
|
|
var native_path = [_]u8{0} ** (native_path_max + 1);
|
|
|
|
if ((file_sandbox.prefix.len + file_path.len) < native_path_max) {
|
|
coral.io.copy(&native_path, file_sandbox.prefix);
|
|
coral.io.copy(native_path[file_sandbox.prefix.len ..], file_path);
|
|
}
|
|
|
|
return native_path;
|
|
}
|
|
|
|
pub fn open_readable(file_sandbox: *FileSandbox, file_path: []const u8) OpenError!*ReadableFile {
|
|
if (!file_sandbox.flags.is_readable) return error.AccessDenied;
|
|
|
|
return @ptrCast(*ReadableFile, ext.SDL_RWFromFile(&file_sandbox.native_path_of(file_path), "rb") orelse {
|
|
return error.FileNotFound;
|
|
});
|
|
}
|
|
|
|
pub fn open_writable(file_sandbox: *FileSandbox, file_path: []const u8) OpenError!*WritableFile {
|
|
if (!file_sandbox.flags.is_writable) return error.AccessDenied;
|
|
|
|
return @ptrCast(*WritableFile, ext.SDL_RWFromFile(&file_sandbox.native_path_of(file_path), "wb") orelse {
|
|
return error.FileNotFound;
|
|
});
|
|
}
|
|
|
|
pub fn query(file_sandbox: *FileSandbox, file_path: []const u8) QueryError!FileInfo {
|
|
if (!file_sandbox.flags.is_queryable) return error.AccessDenied;
|
|
|
|
const rw_ops = ext.SDL_RWFromFile(&file_sandbox.native_path_of(file_path), "rb") orelse {
|
|
return error.FileNotFound;
|
|
};
|
|
|
|
defer _ = ext.SDL_RWclose(rw_ops);
|
|
|
|
const file_size = ext.SDL_RWsize(rw_ops);
|
|
|
|
if (file_size < 0) return error.FileNotFound;
|
|
|
|
return FileInfo{
|
|
.size = @intCast(u64, file_size),
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const OpenError = QueryError || error {TooManyFiles};
|
|
|
|
pub const ReadableFile = opaque {
|
|
pub fn as_reader(self: *ReadableFile) coral.io.Reader {
|
|
return coral.io.Reader.bind(self, read);
|
|
}
|
|
|
|
fn as_rw_ops(self: *ReadableFile) *ext.SDL_RWops {
|
|
return @ptrCast(*ext.SDL_RWops, @alignCast(@alignOf(ext.SDL_RWops), self));
|
|
}
|
|
|
|
pub fn close(self: *ReadableFile) bool {
|
|
return ext.SDL_RWclose(self.as_rw_ops()) != 0;
|
|
}
|
|
|
|
pub fn read(self: *ReadableFile, buffer: []u8) coral.io.ReadError!usize {
|
|
ext.SDL_ClearError();
|
|
|
|
const buffer_read = ext.SDL_RWread(self.as_rw_ops(), buffer.ptr, @sizeOf(u8), buffer.len);
|
|
|
|
if ((buffer_read == 0) and (ext.SDL_GetError().* != 0)) return error.IoUnavailable;
|
|
|
|
return buffer_read;
|
|
}
|
|
|
|
pub fn rewind(self: *ReadableFile) SeekError!void {
|
|
return self.seek(0);
|
|
}
|
|
|
|
pub fn seek(self: *ReadableFile, absolute: u64) SeekError!void {
|
|
ext.SDL_ClearError();
|
|
|
|
// TODO: Fix int cast.
|
|
const sought = ext.SDL_RWseek(self.as_rw_ops(), @intCast(i64, absolute), ext.RW_SEEK_SET);
|
|
|
|
if ((sought == -1) and (ext.SDL_GetError().* != 0)) return error.IoUnavailable;
|
|
}
|
|
};
|
|
|
|
pub const QueryError = error {
|
|
FileNotFound,
|
|
AccessDenied,
|
|
};
|
|
|
|
pub const SeekError = error {
|
|
IoUnavailable,
|
|
};
|
|
|
|
pub const WritableFile = opaque {
|
|
pub fn as_writer(self: *WritableFile) coral.io.Writer {
|
|
return coral.io.Writer.bind(WritableFile, self);
|
|
}
|
|
|
|
fn as_rw_ops(self: *WritableFile) *ext.SDL_RWops {
|
|
return @ptrCast(*ext.SDL_RWops, @alignCast(@alignOf(ext.SDL_RWops), self));
|
|
}
|
|
|
|
pub fn close(self: *WritableFile) bool {
|
|
return ext.SDL_RWclose(self.as_rw_ops()) != 0;
|
|
}
|
|
|
|
pub fn rewind(self: *WritableFile) SeekError!void {
|
|
return self.seek(0);
|
|
}
|
|
|
|
pub fn seek(self: *WritableFile, absolute: u64) SeekError!void {
|
|
ext.SDL_ClearError();
|
|
|
|
// TODO: Fix int cast.
|
|
const sought = ext.SDL_RWseek(self.as_rw_ops(), @intCast(i64, absolute), ext.RW_SEEK_SET);
|
|
|
|
if ((sought == -1) and (ext.SDL_GetError().* != 0)) return error.IoUnavailable;
|
|
}
|
|
|
|
pub fn write(self: *WritableFile, buffer: []const u8) coral.io.WriteError!usize {
|
|
ext.SDL_ClearError();
|
|
|
|
const buffer_read = ext.SDL_RWwrite(self.as_rw_ops(), buffer.ptr, @sizeOf(u8), buffer.len);
|
|
|
|
if ((buffer_read == 0) and (ext.SDL_GetError().* != 0)) return error.IoUnavailable;
|
|
|
|
return buffer_read;
|
|
}
|
|
};
|