diff --git a/source/app.cpp b/source/app.cpp index 865eb20..5097886 100644 --- a/source/app.cpp +++ b/source/app.cpp @@ -13,10 +13,23 @@ import oar; namespace app { struct directory : public coral::fs { + struct rules { + bool can_read; + + bool can_write; + }; + + virtual rules access_rules() const = 0; + virtual coral::slice native_path() const = 0; }; - struct file_reader : public coral::file_reader { + 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, @@ -29,7 +42,7 @@ namespace app { not_found, }; - file_reader(directory * file_directory) : rw_ops{nullptr} { + file(directory * file_directory) : rw_ops{nullptr} { this->file_directory = file_directory; } @@ -45,7 +58,7 @@ 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; @@ -67,21 +80,43 @@ namespace app { // No room for zero terminator. if (path_buffer.is_full()) return open_result::not_found; - this->rw_ops = ::SDL_RWFromFile(reinterpret_cast(path_buffer.begin()), "r"); + 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(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(path_buffer.begin()), "wb"); + + break; + } + + default: coral::unreachable(); + } if (this->rw_ops == nullptr) return open_result::not_found; return open_result::ok; } - coral::expected read(coral::slice const & buffer) override { + coral::expected read(coral::slice 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 seek(coral::u64 offset) override { @@ -106,6 +141,16 @@ namespace app { return static_cast(byte_position); } + coral::expected write(coral::slice 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: directory * file_directory; @@ -136,6 +181,13 @@ struct base_directory : public app::directory { ::SDL_free(this->directory_path.begin()); } + rules access_rules() const override { + return { + .can_read = true, + .can_write = false, + }; + } + coral::slice native_path() const override { return this->directory_path; } @@ -143,13 +195,14 @@ struct base_directory : public app::directory { void read_file(coral::path const & file_path, coral::callable 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 const & then) override { @@ -183,6 +236,13 @@ struct user_directory : public app::directory { ::SDL_free(this->directory_path.begin()); } + rules access_rules() const override { + return { + .can_read = true, + .can_write = false, + }; + } + coral::slice native_path() const override { return this->directory_path; } @@ -190,17 +250,27 @@ struct user_directory : public app::directory { void read_file(coral::path const & file_path, coral::callable 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 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: