C++20 Port #5
261
source/app.cpp
261
source/app.cpp
|
@ -11,89 +11,178 @@ import coral.math;
|
||||||
|
|
||||||
import oar;
|
import oar;
|
||||||
|
|
||||||
export namespace app {
|
struct file_reader : public coral::file_reader {
|
||||||
struct directory : public coral::fs {
|
enum class [[nodiscard]] close_result {
|
||||||
struct rules {
|
ok,
|
||||||
bool can_read;
|
io_unavailable,
|
||||||
|
|
||||||
bool can_write;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
directory() : path_buffer{0} {}
|
enum class [[nodiscard]] open_result {
|
||||||
|
ok,
|
||||||
|
io_unavailable,
|
||||||
|
access_denied,
|
||||||
|
not_found,
|
||||||
|
};
|
||||||
|
|
||||||
void read_file(coral::path const & file_path,
|
file_reader(coral::fs * fs) : rw_ops{nullptr} {
|
||||||
coral::callable<void(coral::readable const &)> const & then) {
|
this->fs = fs;
|
||||||
|
|
||||||
if (this->prefix_length == 0) return;
|
|
||||||
|
|
||||||
if (!this->access_rules.can_read) return;
|
|
||||||
|
|
||||||
::SDL_RWops * rw_ops{this->open_rw(file_path, {.can_read = true})};
|
|
||||||
|
|
||||||
if (rw_ops == nullptr) return;
|
|
||||||
|
|
||||||
then([rw_ops](coral::slice<uint8_t> const & buffer) -> size_t {
|
|
||||||
return ::SDL_RWread(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
::SDL_RWclose(rw_ops);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void target(coral::slice<char const> const & directory_path, rules const & access_rules) {
|
close_result close() {
|
||||||
this->access_rules = access_rules;
|
if (::SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable;
|
||||||
this->prefix_length = coral::min(directory_path.length, path_max - 1);
|
|
||||||
|
|
||||||
{
|
this->rw_ops = nullptr;
|
||||||
coral::slice const path_buffer_slice{this->path_buffer};
|
|
||||||
|
|
||||||
coral::copy(path_buffer_slice.sliced(0, this->prefix_length),
|
return close_result::ok;
|
||||||
directory_path.sliced(0, this->prefix_length).as_bytes());
|
|
||||||
|
|
||||||
coral::zero(path_buffer_slice.sliced(this->prefix_length, path_max - this->prefix_length));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_file(coral::path const & file_path,
|
bool is_open() const {
|
||||||
coral::callable<void(coral::writable const &)> const & then) {
|
return this->rw_ops != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->prefix_length == 0) return;
|
open_result open(coral::path const & file_path) {
|
||||||
|
if (this->is_open()) switch (this->close()) {
|
||||||
|
case close_result::ok: break;
|
||||||
|
case close_result::io_unavailable: return open_result::io_unavailable;
|
||||||
|
default: coral::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
if (!this->access_rules.can_write) return;
|
this->rw_ops = ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
|
||||||
|
|
||||||
::SDL_RWops * rw_ops{this->open_rw(file_path, {.can_write = true})};
|
if (this->rw_ops == nullptr) return open_result::not_found;
|
||||||
|
|
||||||
if (rw_ops == nullptr) return;
|
return open_result::ok;
|
||||||
|
}
|
||||||
|
|
||||||
then([rw_ops](coral::slice<uint8_t const> const & buffer) -> size_t {
|
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
|
||||||
return ::SDL_RWwrite(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length);
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
});
|
|
||||||
|
|
||||||
::SDL_RWclose(rw_ops);
|
coral::usize const bytes_read{::SDL_RWread(this->rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length)};
|
||||||
|
|
||||||
|
if ((bytes_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
// TODO: Fix cast.
|
||||||
|
coral::i64 const byte_position{
|
||||||
|
::SDL_RWseek(this->rw_ops, static_cast<coral::i64>(offset), RW_SEEK_SET)};
|
||||||
|
|
||||||
|
if (byte_position == -1) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
return static_cast<coral::u64>(byte_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
coral::expected<coral::u64, coral::io_error> tell() override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
coral::i64 const byte_position{::SDL_RWseek(this->rw_ops, 0, RW_SEEK_SET)};
|
||||||
|
|
||||||
|
if (byte_position == -1) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
return static_cast<coral::u64>(byte_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr coral::usize path_max = 4096;
|
static constexpr coral::usize path_max{4096};
|
||||||
|
|
||||||
rules access_rules;
|
|
||||||
|
|
||||||
coral::usize prefix_length;
|
|
||||||
|
|
||||||
coral::u8 path_buffer[path_max];
|
coral::u8 path_buffer[path_max];
|
||||||
|
|
||||||
::SDL_RWops * open_rw(coral::path const & file_path, rules const & file_rules) {
|
coral::fs * fs;
|
||||||
coral::u8 * const path_begin{this->path_buffer + this->prefix_length};
|
|
||||||
|
|
||||||
coral::slice const path_remaining =
|
::SDL_RWops * rw_ops;
|
||||||
{path_begin, path_begin + (path_max - this->prefix_length) - 1};
|
|
||||||
|
|
||||||
if (path_remaining.length < file_path.byte_size()) return nullptr;
|
|
||||||
|
|
||||||
coral::copy(path_remaining, file_path.as_slice().as_bytes());
|
|
||||||
|
|
||||||
return ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct base_directory : public coral::fs {
|
||||||
|
base_directory() : directory_path{} {
|
||||||
|
char * const path{::SDL_GetBasePath()};
|
||||||
|
|
||||||
|
if (path == nullptr) return;
|
||||||
|
|
||||||
|
coral::usize path_length{0};
|
||||||
|
|
||||||
|
while (path[path_length] != 0) path_length += 1;
|
||||||
|
|
||||||
|
if (path_length == 0) {
|
||||||
|
::SDL_free(path);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->directory_path = {path, path_length};
|
||||||
|
}
|
||||||
|
|
||||||
|
~base_directory() override {
|
||||||
|
::SDL_free(this->directory_path.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||||
|
if (this->directory_path.length == 0) return;
|
||||||
|
|
||||||
|
file_reader reader{this};
|
||||||
|
|
||||||
|
if (reader.open(file_path) != file_reader::open_result::ok) return;
|
||||||
|
|
||||||
|
then(reader);
|
||||||
|
|
||||||
|
if (reader.close() != file_reader::close_result::ok) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
||||||
|
// Directory is read-only.
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
coral::slice<char> directory_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct user_directory : public coral::fs {
|
||||||
|
user_directory(coral::path const & title) : directory_path{} {
|
||||||
|
char * const path{::SDL_GetPrefPath("ona", title.begin())};
|
||||||
|
|
||||||
|
if (path == nullptr) return;
|
||||||
|
|
||||||
|
coral::usize path_length{0};
|
||||||
|
|
||||||
|
while (path[path_length] != 0) path_length += 1;
|
||||||
|
|
||||||
|
if (path_length == 0) {
|
||||||
|
::SDL_free(path);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->directory_path = {path, path_length};
|
||||||
|
}
|
||||||
|
|
||||||
|
~user_directory() override {
|
||||||
|
::SDL_free(this->directory_path.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||||
|
if (this->directory_path.length == 0) return;
|
||||||
|
|
||||||
|
file_reader reader{this};
|
||||||
|
|
||||||
|
if (reader.open(file_path) != file_reader::open_result::ok) return;
|
||||||
|
|
||||||
|
then(reader);
|
||||||
|
|
||||||
|
if (reader.close() != file_reader::close_result::ok) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
||||||
|
// Directory is read-only.
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
coral::slice<char> directory_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
export namespace app {
|
||||||
enum class log_level {
|
enum class log_level {
|
||||||
notice,
|
notice,
|
||||||
warning,
|
warning,
|
||||||
|
@ -101,48 +190,10 @@ export namespace app {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct system {
|
struct system {
|
||||||
system(coral::path const & title) : res_archive{} {
|
system(coral::path const & title) : res{&base, "base_directory.oar"}, user{title} {}
|
||||||
constexpr directory::rules read_only_rules = {.can_read = true};
|
|
||||||
|
|
||||||
{
|
coral::fs & base_fs() {
|
||||||
char * const path{::SDL_GetBasePath()};
|
return this->base;
|
||||||
|
|
||||||
if (path == nullptr) {
|
|
||||||
this->cwd_directory.target("./", read_only_rules);
|
|
||||||
} else {
|
|
||||||
coral::usize path_length{0};
|
|
||||||
|
|
||||||
while (path[path_length] != 0) path_length += 1;
|
|
||||||
|
|
||||||
if (path_length == 0) {
|
|
||||||
this->cwd_directory.target("./", read_only_rules);
|
|
||||||
} else {
|
|
||||||
this->cwd_directory.target({path, path_length}, read_only_rules);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::SDL_free(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
char * const path{::SDL_GetPrefPath("ona", title.begin())};
|
|
||||||
|
|
||||||
if (path != nullptr) {
|
|
||||||
coral::usize path_length{0};
|
|
||||||
|
|
||||||
while (path[path_length] != 0) path_length += 1;
|
|
||||||
|
|
||||||
if (path_length != 0) this->cwd_directory.target({path, path_length}, {
|
|
||||||
.can_read = true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
::SDL_free(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
coral::fs & cwd_fs() {
|
|
||||||
return this->cwd_directory;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poll() {
|
bool poll() {
|
||||||
|
@ -156,7 +207,7 @@ export namespace app {
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::fs & res_fs() {
|
coral::fs & res_fs() {
|
||||||
return this->res_archive;
|
return this->res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(app::log_level level, coral::slice<char const> const & message) {
|
void log(app::log_level level, coral::slice<char const> const & message) {
|
||||||
|
@ -172,7 +223,7 @@ export namespace app {
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::fs & user_fs() {
|
coral::fs & user_fs() {
|
||||||
return this->user_directory;
|
return this->user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -188,11 +239,11 @@ export namespace app {
|
||||||
}
|
}
|
||||||
} allocator;
|
} allocator;
|
||||||
|
|
||||||
oar::archive res_archive;
|
base_directory base;
|
||||||
|
|
||||||
directory cwd_directory;
|
user_directory user;
|
||||||
|
|
||||||
directory user_directory;
|
oar::archive res;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct graphics {
|
struct graphics {
|
||||||
|
|
|
@ -38,13 +38,13 @@ export namespace coral {
|
||||||
|
|
||||||
using u32 = uint32_t;
|
using u32 = uint32_t;
|
||||||
|
|
||||||
using i32 = uint32_t;
|
using i32 = int32_t;
|
||||||
|
|
||||||
usize const i32_max = 0xffffffff;
|
usize const i32_max = 0xffffffff;
|
||||||
|
|
||||||
using u64 = uint64_t;
|
using u64 = uint64_t;
|
||||||
|
|
||||||
using i64 = uint64_t;
|
using i64 = int64_t;
|
||||||
|
|
||||||
using f32 = float;
|
using f32 = float;
|
||||||
|
|
||||||
|
|
|
@ -118,12 +118,6 @@ export namespace coral {
|
||||||
* Platform-generalized file system interface.
|
* Platform-generalized file system interface.
|
||||||
*/
|
*/
|
||||||
struct fs {
|
struct fs {
|
||||||
struct io_rules {
|
|
||||||
bool can_read;
|
|
||||||
|
|
||||||
bool can_write;
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual ~fs() {};
|
virtual ~fs() {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -134,11 +128,6 @@ export namespace coral {
|
||||||
*/
|
*/
|
||||||
virtual void read_file(path const & file_path, callable<void(file_reader &)> const & then) = 0;
|
virtual void read_file(path const & file_path, callable<void(file_reader &)> const & then) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the [io_rules] that this file system interface abides by.
|
|
||||||
*/
|
|
||||||
virtual io_rules rules() const = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to write the file in the file system located at `file_path` relative, calling
|
* Attempts to write the file in the file system located at `file_path` relative, calling
|
||||||
* `then` if it was successfully opened for writing.
|
* `then` if it was successfully opened for writing.
|
||||||
|
|
|
@ -69,8 +69,8 @@ export namespace kym {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writable const & output) {
|
coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writer & output) {
|
||||||
return output(coral::slice{"[object]"}.as_bytes());
|
return output.write(coral::slice{"[object]"}.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
struct bound_object {
|
struct bound_object {
|
||||||
|
@ -81,7 +81,7 @@ export namespace kym {
|
||||||
|
|
||||||
value(*call)(vm &, void *, coral::slice<value const> const &);
|
value(*call)(vm &, void *, coral::slice<value const> const &);
|
||||||
|
|
||||||
coral::expected<coral::usize, coral::io_error>(*stringify)(vm &, void *, coral::writable const &);
|
coral::expected<coral::usize, coral::io_error>(*stringify)(vm &, void *, coral::writer &);
|
||||||
} behavior;
|
} behavior;
|
||||||
|
|
||||||
bound_object(vm * owning_vm) : userdata{nullptr}, owning_vm{owning_vm}, behavior{
|
bound_object(vm * owning_vm) : userdata{nullptr}, owning_vm{owning_vm}, behavior{
|
||||||
|
@ -98,7 +98,7 @@ export namespace kym {
|
||||||
return this->behavior.call(*this->owning_vm, this->userdata, arguments);
|
return this->behavior.call(*this->owning_vm, this->userdata, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::expected<coral::usize, coral::io_error> stringify(coral::writable const & output) {
|
coral::expected<coral::usize, coral::io_error> stringify(coral::writer & output) {
|
||||||
return this->behavior.stringify(*this->owning_vm, this->userdata, output);
|
return this->behavior.stringify(*this->owning_vm, this->userdata, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
184
source/oar.cpp
184
source/oar.cpp
|
@ -3,36 +3,200 @@ export module oar;
|
||||||
import coral;
|
import coral;
|
||||||
import coral.files;
|
import coral.files;
|
||||||
|
|
||||||
export namespace oar {
|
|
||||||
constexpr coral::usize signature_length{4};
|
constexpr coral::usize signature_length{4};
|
||||||
|
|
||||||
|
constexpr coral::usize signature_version_length{1};
|
||||||
|
|
||||||
|
constexpr coral::usize signature_identifier_length{signature_length - signature_version_length};
|
||||||
|
|
||||||
constexpr coral::u8 signature_magic[signature_length]{'o', 'a', 'r', 0};
|
constexpr coral::u8 signature_magic[signature_length]{'o', 'a', 'r', 0};
|
||||||
|
|
||||||
struct entry {
|
struct header {
|
||||||
coral::u8 signature_magic[signature_length];
|
coral::u8 signature_magic[signature_length];
|
||||||
|
|
||||||
|
coral::u32 entry_count;
|
||||||
|
|
||||||
|
coral::u8 padding[504];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(header) == 512);
|
||||||
|
|
||||||
|
struct entry {
|
||||||
coral::path path;
|
coral::path path;
|
||||||
|
|
||||||
coral::u64 data_offset;
|
coral::u64 data_offset;
|
||||||
|
|
||||||
coral::u64 data_length;
|
coral::u64 data_length;
|
||||||
|
|
||||||
coral::u8 padding[244];
|
coral::u8 padding[240];
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(sizeof(entry) == 512);
|
||||||
|
|
||||||
|
export namespace oar {
|
||||||
|
struct archive_file_reader : public coral::file_reader {
|
||||||
|
enum class [[nodiscard]] close_result {
|
||||||
|
ok,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class [[nodiscard]] open_result {
|
||||||
|
ok,
|
||||||
|
io_unavailable,
|
||||||
|
archive_invalid,
|
||||||
|
archive_unsupported,
|
||||||
|
not_found,
|
||||||
|
};
|
||||||
|
|
||||||
|
archive_file_reader(coral::file_reader * archive_reader) {
|
||||||
|
this->archive_reader = archive_reader;
|
||||||
|
this->data_offset = 0;
|
||||||
|
this->data_length = 0;
|
||||||
|
this->data_cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
close_result close() {
|
||||||
|
return close_result::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_open() const {
|
||||||
|
return this->data_offset >= sizeof(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
open_result open(coral::path const & file_path) {
|
||||||
|
if (this->is_open()) switch (this->close()) {
|
||||||
|
case close_result::ok: break;
|
||||||
|
default: coral::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->archive_reader->seek(0).is_ok()) return open_result::io_unavailable;
|
||||||
|
|
||||||
|
constexpr coral::usize header_size = sizeof(header);
|
||||||
|
coral::u8 archive_header_buffer[header_size]{0};
|
||||||
|
|
||||||
|
{
|
||||||
|
coral::expected const read_bytes{archive_reader->read(archive_header_buffer)};
|
||||||
|
|
||||||
|
if ((!read_bytes.is_ok()) || (read_bytes.value() != header_size))
|
||||||
|
return open_result::archive_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
header const * const archive_header{reinterpret_cast<header const *>(archive_header_buffer)};
|
||||||
|
|
||||||
|
if (!coral::equals(coral::slice{archive_header->signature_magic,
|
||||||
|
signature_identifier_length}, coral::slice{signature_magic,
|
||||||
|
signature_identifier_length})) return open_result::archive_invalid;
|
||||||
|
|
||||||
|
if (archive_header->signature_magic[signature_identifier_length] !=
|
||||||
|
signature_magic[signature_identifier_length]) return open_result::archive_unsupported;
|
||||||
|
|
||||||
|
// Read file table.
|
||||||
|
coral::u64 head{0};
|
||||||
|
coral::u64 tail{archive_header->entry_count - 1};
|
||||||
|
constexpr coral::usize entry_size{sizeof(entry)};
|
||||||
|
coral::u8 file_entry_buffer[entry_size]{0};
|
||||||
|
|
||||||
|
while (head <= tail) {
|
||||||
|
coral::u64 const midpoint{head + ((tail - head) / 2)};
|
||||||
|
|
||||||
|
if (!archive_reader->seek(header_size + (entry_size * midpoint)).is_ok())
|
||||||
|
return open_result::archive_invalid;
|
||||||
|
|
||||||
|
{
|
||||||
|
coral::expected const read_bytes{archive_reader->read(file_entry_buffer)};
|
||||||
|
|
||||||
|
if ((!read_bytes.is_ok()) || (read_bytes.value() != header_size))
|
||||||
|
return open_result::archive_invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry const * const archive_entry{reinterpret_cast<entry const *>(file_entry_buffer)};
|
||||||
|
coral::size const comparison{file_path.compare(archive_entry->path)};
|
||||||
|
|
||||||
|
if (comparison == 0) {
|
||||||
|
this->data_offset = archive_entry->data_offset;
|
||||||
|
this->data_length = archive_entry->data_length;
|
||||||
|
this->data_cursor = archive_entry->data_offset;
|
||||||
|
|
||||||
|
return open_result::ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comparison > 0) {
|
||||||
|
head = (midpoint + 1);
|
||||||
|
} else {
|
||||||
|
tail = (midpoint - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return open_result::not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
if (this->archive_reader->seek(this->data_offset + this->data_cursor).is_ok())
|
||||||
|
return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
coral::expected const bytes_read{this->archive_reader->read(buffer.sliced(0,
|
||||||
|
coral::min(buffer.length, static_cast<coral::usize>((
|
||||||
|
this->data_offset + this->data_length) - this->data_cursor))))};
|
||||||
|
|
||||||
|
if (!bytes_read.is_ok()) this->data_cursor += bytes_read.value();
|
||||||
|
|
||||||
|
return bytes_read;
|
||||||
|
}
|
||||||
|
|
||||||
|
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
return coral::io_error::unavailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
coral::expected<coral::u64, coral::io_error> tell() override {
|
||||||
|
if (!this->is_open()) return coral::io_error::unavailable;
|
||||||
|
|
||||||
|
return this->data_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
coral::file_reader * archive_reader;
|
||||||
|
|
||||||
|
coral::u64 data_offset;
|
||||||
|
|
||||||
|
coral::u64 data_length;
|
||||||
|
|
||||||
|
coral::u64 data_cursor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct archive : public coral::fs {
|
struct archive : public coral::fs {
|
||||||
archive() {
|
archive(coral::fs * backing_fs, coral::path const & archive_path) {
|
||||||
|
this->backing_fs = backing_fs;
|
||||||
|
this->archive_path = archive_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_file(coral::path const & file_path,
|
void read_file(coral::path const & file_path,
|
||||||
coral::callable<void(coral::readable const &)> const & then) override {
|
coral::callable<void(coral::file_reader &)> const & then) override {
|
||||||
|
|
||||||
|
if ((this->backing_fs == nullptr) || (this->archive_path.byte_size() == 0)) return;
|
||||||
|
|
||||||
|
this->backing_fs->read_file(this->archive_path, [&](coral::file_reader & archive_reader) {
|
||||||
|
archive_file_reader file_reader{&archive_reader};
|
||||||
|
|
||||||
|
if (file_reader.open(file_path) != archive_file_reader::open_result::ok) return;
|
||||||
|
|
||||||
|
then(file_reader);
|
||||||
|
|
||||||
|
if (file_reader.close() != archive_file_reader::close_result::ok) return;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_file(coral::path const & file_path,
|
void write_file(coral::path const & file_path,
|
||||||
coral::callable<void(coral::writable const &)> const & then) override {
|
coral::callable<void(coral::file_writer &)> const & then) override {
|
||||||
}
|
|
||||||
};
|
// Read-only file system.
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(sizeof(oar::entry) == 512);
|
private:
|
||||||
|
coral::fs * backing_fs;
|
||||||
|
|
||||||
|
coral::path archive_path;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ extern "C" int main(int argc, char const * const * argv) {
|
||||||
constexpr coral::path config_path{"config.kym"};
|
constexpr coral::path config_path{"config.kym"};
|
||||||
bool is_config_loaded{false};
|
bool is_config_loaded{false};
|
||||||
|
|
||||||
system.res_fs().read_file(config_path, [&](coral::readable const & file) {
|
system.res_fs().read_file(config_path, [&](coral::reader & file) {
|
||||||
coral::allocator * const allocator{&system.thread_safe_allocator()};
|
coral::allocator * const allocator{&system.thread_safe_allocator()};
|
||||||
|
|
||||||
kym::vm vm{allocator, [&system](coral::slice<char const> const & error_message) {
|
kym::vm vm{allocator, [&system](coral::slice<char const> const & error_message) {
|
||||||
|
@ -29,10 +29,13 @@ extern "C" int main(int argc, char const * const * argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
coral::stack<coral::u8> script_source{allocator};
|
coral::stack<coral::u8> script_source{allocator};
|
||||||
coral::u8 stream_buffer[1024]{0};
|
|
||||||
|
|
||||||
if (!coral::stream(coral::sequence_writer{&script_source}, file, stream_buffer).is_ok())
|
{
|
||||||
return;
|
coral::u8 stream_buffer[1024]{0};
|
||||||
|
coral::sequence_writer script_writer{&script_source};
|
||||||
|
|
||||||
|
if (!coral::stream(script_writer, file, stream_buffer).is_ok()) return;
|
||||||
|
}
|
||||||
|
|
||||||
vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) {
|
vm.with_object(vm.compile(coral::slice{script_source.begin(), script_source.end()}.as_chars()), [&](kym::bound_object & script) {
|
||||||
vm.with_object(script.call({}), [&](kym::bound_object & config) {
|
vm.with_object(script.call({}), [&](kym::bound_object & config) {
|
||||||
|
@ -51,8 +54,9 @@ extern "C" int main(int argc, char const * const * argv) {
|
||||||
|
|
||||||
vm.with_object(config.get_field("title"), [&](kym::bound_object & title) {
|
vm.with_object(config.get_field("title"), [&](kym::bound_object & title) {
|
||||||
coral::stack<coral::u8, 128> title_buffer{&system.thread_safe_allocator()};
|
coral::stack<coral::u8, 128> title_buffer{&system.thread_safe_allocator()};
|
||||||
|
coral::sequence_writer title_writer{&title_buffer};
|
||||||
|
|
||||||
if (!title.stringify(coral::sequence_writer{&title_buffer}).is_ok()) {
|
if (!title.stringify(title_writer).is_ok()) {
|
||||||
system.log(app::log_level::error,
|
system.log(app::log_level::error,
|
||||||
"failed to decode `title` property of config");
|
"failed to decode `title` property of config");
|
||||||
|
|
||||||
|
@ -71,10 +75,10 @@ extern "C" int main(int argc, char const * const * argv) {
|
||||||
{
|
{
|
||||||
coral::sequence_writer error_writer{&error_message};
|
coral::sequence_writer error_writer{&error_message};
|
||||||
|
|
||||||
if (!error_writer(coral::slice{"failed to load "}.as_bytes()).is_ok())
|
if (!error_writer.write(coral::slice{"failed to load "}.as_bytes()).is_ok())
|
||||||
return coral::u8_max;
|
return coral::u8_max;
|
||||||
|
|
||||||
if (!error_writer(config_path.as_slice().as_bytes()).is_ok())
|
if (!error_writer.write(config_path.as_slice().as_bytes()).is_ok())
|
||||||
return coral::u8_max;
|
return coral::u8_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue