Compare commits
4 Commits
cea0a4e0ed
...
5d4f40393b
Author | SHA1 | Date |
---|---|---|
kayomn | 5d4f40393b | |
kayomn | fd62ec5966 | |
kayomn | c4b83082e3 | |
kayomn | 0b8167ce1d |
164
source/app.cpp
164
source/app.cpp
|
@ -12,7 +12,24 @@ import coral.math;
|
|||
import oar;
|
||||
|
||||
namespace app {
|
||||
struct file_reader : public coral::file_reader {
|
||||
struct directory : public coral::fs {
|
||||
struct rules {
|
||||
bool can_read;
|
||||
|
||||
bool can_write;
|
||||
};
|
||||
|
||||
virtual rules access_rules() const = 0;
|
||||
|
||||
virtual coral::slice<char const> native_path() const = 0;
|
||||
};
|
||||
|
||||
struct file : public coral::file_reader, public coral::file_writer {
|
||||
enum class open_mode {
|
||||
read_only,
|
||||
overwrite,
|
||||
};
|
||||
|
||||
enum class [[nodiscard]] close_result {
|
||||
ok,
|
||||
io_unavailable,
|
||||
|
@ -25,8 +42,8 @@ namespace app {
|
|||
not_found,
|
||||
};
|
||||
|
||||
file_reader(coral::fs * fs) : rw_ops{nullptr} {
|
||||
this->fs = fs;
|
||||
file(directory * file_directory) : rw_ops{nullptr} {
|
||||
this->file_directory = file_directory;
|
||||
}
|
||||
|
||||
close_result close() {
|
||||
|
@ -41,28 +58,65 @@ namespace app {
|
|||
return this->rw_ops != nullptr;
|
||||
}
|
||||
|
||||
open_result open(coral::path const & file_path) {
|
||||
open_result open(coral::path const & file_path, open_mode mode) {
|
||||
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();
|
||||
}
|
||||
|
||||
this->rw_ops = ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r");
|
||||
// Windows system path max is something like 512 bytes (depending on the version) and
|
||||
// on Linux it's 4096.
|
||||
coral::fixed_buffer<4096> path_buffer{0};
|
||||
|
||||
if (!path_buffer.write(this->file_directory->native_path().as_bytes()).is_ok())
|
||||
// What kind of directory path is being used that would be longer than 4096 bytes?
|
||||
return open_result::not_found;
|
||||
|
||||
if (!path_buffer.write(file_path.as_slice().as_bytes()).is_ok())
|
||||
// This happening is still implausible but slightly more reasonable?
|
||||
return open_result::not_found;
|
||||
|
||||
// No room for zero terminator.
|
||||
if (path_buffer.is_full()) return open_result::not_found;
|
||||
|
||||
switch (mode) {
|
||||
case open_mode::read_only: {
|
||||
if (!this->file_directory->access_rules().can_read)
|
||||
return open_result::access_denied;
|
||||
|
||||
this->rw_ops = ::SDL_RWFromFile(
|
||||
reinterpret_cast<char const *>(path_buffer.begin()), "rb");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case open_mode::overwrite: {
|
||||
if (!this->file_directory->access_rules().can_write)
|
||||
return open_result::access_denied;
|
||||
|
||||
this->rw_ops = ::SDL_RWFromFile(
|
||||
reinterpret_cast<char const *>(path_buffer.begin()), "wb");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: coral::unreachable();
|
||||
}
|
||||
|
||||
if (this->rw_ops == nullptr) return open_result::not_found;
|
||||
|
||||
return open_result::ok;
|
||||
}
|
||||
|
||||
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & buffer) override {
|
||||
coral::expected<coral::usize, coral::io_error> read(coral::slice<coral::u8> const & data) override {
|
||||
if (!this->is_open()) return coral::io_error::unavailable;
|
||||
|
||||
coral::usize const bytes_read{::SDL_RWread(this->rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length)};
|
||||
coral::usize const data_read{::SDL_RWread(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)};
|
||||
|
||||
if ((bytes_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
||||
if ((data_read == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
||||
|
||||
return bytes_read;
|
||||
return data_read;
|
||||
}
|
||||
|
||||
coral::expected<coral::u64, coral::io_error> seek(coral::u64 offset) override {
|
||||
|
@ -87,18 +141,24 @@ namespace app {
|
|||
return static_cast<coral::u64>(byte_position);
|
||||
}
|
||||
|
||||
coral::expected<coral::usize, coral::io_error> write(coral::slice<coral::u8 const> const & data) override {
|
||||
if (!this->is_open()) return coral::io_error::unavailable;
|
||||
|
||||
coral::usize const data_written{::SDL_RWwrite(this->rw_ops, data.pointer, sizeof(uint8_t), data.length)};
|
||||
|
||||
if ((data_written == 0) && (::SDL_GetError() != nullptr)) return coral::io_error::unavailable;
|
||||
|
||||
return data_written;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr coral::usize path_max{4096};
|
||||
|
||||
coral::u8 path_buffer[path_max];
|
||||
|
||||
coral::fs * fs;
|
||||
directory * file_directory;
|
||||
|
||||
::SDL_RWops * rw_ops;
|
||||
};
|
||||
}
|
||||
|
||||
struct base_directory : public coral::fs {
|
||||
struct base_directory : public app::directory {
|
||||
base_directory() : directory_path{} {
|
||||
char * const path{::SDL_GetBasePath()};
|
||||
|
||||
|
@ -121,16 +181,28 @@ struct base_directory : public coral::fs {
|
|||
::SDL_free(this->directory_path.begin());
|
||||
}
|
||||
|
||||
rules access_rules() const override {
|
||||
return {
|
||||
.can_read = true,
|
||||
.can_write = false,
|
||||
};
|
||||
}
|
||||
|
||||
coral::slice<const char> native_path() const override {
|
||||
return this->directory_path;
|
||||
}
|
||||
|
||||
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||
if (this->directory_path.length == 0) return;
|
||||
|
||||
app::file_reader reader{this};
|
||||
app::file file{this};
|
||||
|
||||
if (reader.open(file_path) != app::file_reader::open_result::ok) return;
|
||||
if (file.open(file_path, app::file::open_mode::read_only) != app::file::open_result::ok)
|
||||
return;
|
||||
|
||||
then(reader);
|
||||
then(file);
|
||||
|
||||
if (reader.close() != app::file_reader::close_result::ok) return;
|
||||
if (file.close() != app::file::close_result::ok) return;
|
||||
}
|
||||
|
||||
void write_file(coral::path const & file_path, coral::callable<void(coral::file_writer &)> const & then) override {
|
||||
|
@ -141,7 +213,7 @@ struct base_directory : public coral::fs {
|
|||
coral::slice<char> directory_path;
|
||||
};
|
||||
|
||||
struct user_directory : public coral::fs {
|
||||
struct user_directory : public app::directory {
|
||||
user_directory(coral::path const & title) : directory_path{} {
|
||||
char * const path{::SDL_GetPrefPath("ona", title.begin())};
|
||||
|
||||
|
@ -164,20 +236,41 @@ struct user_directory : public coral::fs {
|
|||
::SDL_free(this->directory_path.begin());
|
||||
}
|
||||
|
||||
rules access_rules() const override {
|
||||
return {
|
||||
.can_read = true,
|
||||
.can_write = false,
|
||||
};
|
||||
}
|
||||
|
||||
coral::slice<const char> native_path() const override {
|
||||
return this->directory_path;
|
||||
}
|
||||
|
||||
void read_file(coral::path const & file_path, coral::callable<void(coral::file_reader &)> const & then) override {
|
||||
if (this->directory_path.length == 0) return;
|
||||
|
||||
app::file_reader reader{this};
|
||||
app::file file{this};
|
||||
|
||||
if (reader.open(file_path) != app::file_reader::open_result::ok) return;
|
||||
if (file.open(file_path, app::file::open_mode::read_only) != app::file::open_result::ok)
|
||||
return;
|
||||
|
||||
then(reader);
|
||||
then(file);
|
||||
|
||||
if (reader.close() != app::file_reader::close_result::ok) return;
|
||||
if (file.close() != app::file::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.
|
||||
if (this->directory_path.length == 0) return;
|
||||
|
||||
app::file file{this};
|
||||
|
||||
if (file.open(file_path, app::file::open_mode::overwrite) != app::file::open_result::ok)
|
||||
return;
|
||||
|
||||
then(file);
|
||||
|
||||
if (file.close() != app::file::close_result::ok) return;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -192,10 +285,11 @@ export namespace app {
|
|||
};
|
||||
|
||||
struct system {
|
||||
system(coral::path const & title) : res{&base, "base_directory.oar"}, user{title} {}
|
||||
system(coral::path const & title) : user_directory{title},
|
||||
res_archive{&base_directory, res_archive_path} {}
|
||||
|
||||
coral::fs & base_fs() {
|
||||
return this->base;
|
||||
app::directory & base_dir() {
|
||||
return this->base_directory;
|
||||
}
|
||||
|
||||
bool poll() {
|
||||
|
@ -209,7 +303,7 @@ export namespace app {
|
|||
}
|
||||
|
||||
coral::fs & res_fs() {
|
||||
return this->res;
|
||||
return this->res_archive;
|
||||
}
|
||||
|
||||
void log(app::log_level level, coral::slice<char const> const & message) {
|
||||
|
@ -224,11 +318,13 @@ export namespace app {
|
|||
return this->allocator;
|
||||
}
|
||||
|
||||
coral::fs & user_fs() {
|
||||
return this->user;
|
||||
app::directory & user_dir() {
|
||||
return this->user_directory;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr coral::path res_archive_path{"base.oar"};
|
||||
|
||||
::SDL_Event sdl_event;
|
||||
|
||||
struct : public coral::allocator {
|
||||
|
@ -241,11 +337,11 @@ export namespace app {
|
|||
}
|
||||
} allocator;
|
||||
|
||||
base_directory base;
|
||||
struct base_directory base_directory;
|
||||
|
||||
user_directory user;
|
||||
struct user_directory user_directory;
|
||||
|
||||
oar::archive res;
|
||||
oar::archive res_archive;
|
||||
};
|
||||
|
||||
struct graphics {
|
||||
|
|
|
@ -641,11 +641,11 @@ export namespace coral {
|
|||
}
|
||||
|
||||
/**
|
||||
* Multiplexing byte buffer of `capacity` size that may be used for memory-backed I/O
|
||||
* operations and lightweight data construction.
|
||||
* Multiplexing byte-based ring buffer of `capacity` size that may be used for memory-backed
|
||||
* I/O operations and lightweight data construction.
|
||||
*/
|
||||
template<usize capacity> struct ring_buffer : public writer, public reader {
|
||||
ring_buffer(coral::u8 fill_value) : data{fill_value} {}
|
||||
template<usize capacity> struct fixed_buffer : public writer, public reader {
|
||||
fixed_buffer(coral::u8 fill_value) : data{fill_value} {}
|
||||
|
||||
/**
|
||||
* Returns the base pointer of the buffer data.
|
||||
|
|
Loading…
Reference in New Issue