C++20 Port #5
							
								
								
									
										305
									
								
								source/app.cpp
									
									
									
									
									
								
							
							
						
						
									
										305
									
								
								source/app.cpp
									
									
									
									
									
								
							| @ -11,89 +11,178 @@ import coral.math; | ||||
| 
 | ||||
| import oar; | ||||
| 
 | ||||
| export namespace app { | ||||
| 	struct directory : public coral::fs { | ||||
| 		struct rules { | ||||
| 			bool can_read; | ||||
| 
 | ||||
| 			bool can_write; | ||||
| 		}; | ||||
| 
 | ||||
| 		directory() : path_buffer{0} {} | ||||
| 
 | ||||
| 		void read_file(coral::path const & file_path, | ||||
| 			coral::callable<void(coral::readable const &)> const & then) { | ||||
| 
 | ||||
| 			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) { | ||||
| 			this->access_rules = access_rules; | ||||
| 			this->prefix_length = coral::min(directory_path.length, path_max - 1); | ||||
| 
 | ||||
| 			{ | ||||
| 				coral::slice const path_buffer_slice{this->path_buffer}; | ||||
| 
 | ||||
| 				coral::copy(path_buffer_slice.sliced(0, this->prefix_length), | ||||
| 					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, | ||||
| 			coral::callable<void(coral::writable const &)> const & then) { | ||||
| 
 | ||||
| 			if (this->prefix_length == 0) return; | ||||
| 
 | ||||
| 			if (!this->access_rules.can_write) return; | ||||
| 
 | ||||
| 			::SDL_RWops * rw_ops{this->open_rw(file_path, {.can_write = true})}; | ||||
| 
 | ||||
| 			if (rw_ops == nullptr) return; | ||||
| 
 | ||||
| 			then([rw_ops](coral::slice<uint8_t const> const & buffer) -> size_t { | ||||
| 				return ::SDL_RWwrite(rw_ops, buffer.pointer, sizeof(uint8_t), buffer.length); | ||||
| 			}); | ||||
| 
 | ||||
| 			::SDL_RWclose(rw_ops); | ||||
| 		} | ||||
| 
 | ||||
| 		private: | ||||
| 		static constexpr coral::usize path_max = 4096; | ||||
| 
 | ||||
| 		rules access_rules; | ||||
| 
 | ||||
| 		coral::usize prefix_length; | ||||
| 
 | ||||
| 		coral::u8 path_buffer[path_max]; | ||||
| 
 | ||||
| 		::SDL_RWops * open_rw(coral::path const & file_path, rules const & file_rules) { | ||||
| 			coral::u8 * const path_begin{this->path_buffer + this->prefix_length}; | ||||
| 
 | ||||
| 			coral::slice const path_remaining = | ||||
| 				{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 file_reader : public coral::file_reader { | ||||
| 	enum class [[nodiscard]] close_result { | ||||
| 		ok, | ||||
| 		io_unavailable, | ||||
| 	}; | ||||
| 
 | ||||
| 	enum class [[nodiscard]] open_result { | ||||
| 		ok, | ||||
| 		io_unavailable, | ||||
| 		access_denied, | ||||
| 		not_found, | ||||
| 	}; | ||||
| 
 | ||||
| 	file_reader(coral::fs * fs) : rw_ops{nullptr} { | ||||
| 		this->fs = fs; | ||||
| 	} | ||||
| 
 | ||||
| 	close_result close() { | ||||
| 		if (::SDL_RWclose(this->rw_ops) != 0) return close_result::io_unavailable; | ||||
| 
 | ||||
| 		this->rw_ops = nullptr; | ||||
| 
 | ||||
| 		return close_result::ok; | ||||
| 	} | ||||
| 
 | ||||
| 	bool is_open() const { | ||||
| 		return this->rw_ops != nullptr; | ||||
| 	} | ||||
| 
 | ||||
| 	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(); | ||||
| 		} | ||||
| 
 | ||||
| 		this->rw_ops = ::SDL_RWFromFile(reinterpret_cast<char const *>(this->path_buffer), "r"); | ||||
| 
 | ||||
| 		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 { | ||||
| 		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)}; | ||||
| 
 | ||||
| 		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: | ||||
| 	static constexpr coral::usize path_max{4096}; | ||||
| 
 | ||||
| 	coral::u8 path_buffer[path_max]; | ||||
| 
 | ||||
| 	coral::fs * fs; | ||||
| 
 | ||||
| 	::SDL_RWops * rw_ops; | ||||
| }; | ||||
| 
 | ||||
| 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 { | ||||
| 		notice, | ||||
| 		warning, | ||||
| @ -101,48 +190,10 @@ export namespace app { | ||||
| 	}; | ||||
| 
 | ||||
| 	struct system { | ||||
| 		system(coral::path const & title) : res_archive{}  { | ||||
| 			constexpr directory::rules read_only_rules = {.can_read = true}; | ||||
| 		system(coral::path const & title) : res{&base, "base_directory.oar"}, user{title} {} | ||||
| 
 | ||||
| 			{ | ||||
| 				char * const path{::SDL_GetBasePath()}; | ||||
| 
 | ||||
| 				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; | ||||
| 		coral::fs & base_fs() { | ||||
| 			return this->base; | ||||
| 		} | ||||
| 
 | ||||
| 		bool poll() { | ||||
| @ -156,7 +207,7 @@ export namespace app { | ||||
| 		} | ||||
| 
 | ||||
| 		coral::fs & res_fs() { | ||||
| 			return this->res_archive; | ||||
| 			return this->res; | ||||
| 		} | ||||
| 
 | ||||
| 		void log(app::log_level level, coral::slice<char const> const & message) { | ||||
| @ -172,7 +223,7 @@ export namespace app { | ||||
| 		} | ||||
| 
 | ||||
| 		coral::fs & user_fs() { | ||||
| 			return this->user_directory; | ||||
| 			return this->user; | ||||
| 		} | ||||
| 
 | ||||
| 		private: | ||||
| @ -188,11 +239,11 @@ export namespace app { | ||||
| 			} | ||||
| 		} allocator; | ||||
| 
 | ||||
| 		oar::archive res_archive; | ||||
| 		base_directory base; | ||||
| 
 | ||||
| 		directory cwd_directory; | ||||
| 		user_directory user; | ||||
| 
 | ||||
| 		directory user_directory; | ||||
| 		oar::archive res; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct graphics { | ||||
|  | ||||
| @ -38,13 +38,13 @@ export namespace coral { | ||||
| 
 | ||||
| 	using u32 = uint32_t; | ||||
| 
 | ||||
| 	using i32 = uint32_t; | ||||
| 	using i32 = int32_t; | ||||
| 
 | ||||
| 	usize const i32_max = 0xffffffff; | ||||
| 
 | ||||
| 	using u64 = uint64_t; | ||||
| 
 | ||||
| 	using i64 = uint64_t; | ||||
| 	using i64 = int64_t; | ||||
| 
 | ||||
| 	using f32 = float; | ||||
| 
 | ||||
|  | ||||
| @ -118,12 +118,6 @@ export namespace coral { | ||||
| 	 * Platform-generalized file system interface. | ||||
| 	 */ | ||||
| 	struct fs { | ||||
| 		struct io_rules { | ||||
| 			bool can_read; | ||||
| 
 | ||||
| 			bool can_write; | ||||
| 		}; | ||||
| 
 | ||||
| 		virtual ~fs() {}; | ||||
| 
 | ||||
| 		/**
 | ||||
| @ -134,11 +128,6 @@ export namespace coral { | ||||
| 		 */ | ||||
| 		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 | ||||
| 		 * `then` if it was successfully opened for writing. | ||||
|  | ||||
| @ -69,8 +69,8 @@ export namespace kym { | ||||
| 		return nil; | ||||
| 	} | ||||
| 
 | ||||
| 	coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writable const & output) { | ||||
| 		return output(coral::slice{"[object]"}.as_bytes()); | ||||
| 	coral::expected<coral::usize, coral::io_error> default_stringify(vm & owning_vm, void * userdata, coral::writer & output) { | ||||
| 		return output.write(coral::slice{"[object]"}.as_bytes()); | ||||
| 	} | ||||
| 
 | ||||
| 	struct bound_object { | ||||
| @ -81,7 +81,7 @@ export namespace kym { | ||||
| 
 | ||||
| 			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; | ||||
| 
 | ||||
| 		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); | ||||
| 		} | ||||
| 
 | ||||
| 		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); | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										188
									
								
								source/oar.cpp
									
									
									
									
									
								
							
							
						
						
									
										188
									
								
								source/oar.cpp
									
									
									
									
									
								
							| @ -3,36 +3,200 @@ export module oar; | ||||
| import coral; | ||||
| import coral.files; | ||||
| 
 | ||||
| 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}; | ||||
| 
 | ||||
| struct header { | ||||
| 	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::u64 data_offset; | ||||
| 
 | ||||
| 	coral::u64 data_length; | ||||
| 
 | ||||
| 	coral::u8 padding[240]; | ||||
| }; | ||||
| 
 | ||||
| static_assert(sizeof(entry) == 512); | ||||
| 
 | ||||
| export namespace oar { | ||||
| 	constexpr coral::usize signature_length{4}; | ||||
| 	struct archive_file_reader : public coral::file_reader { | ||||
| 		enum class [[nodiscard]] close_result { | ||||
| 			ok, | ||||
| 		}; | ||||
| 
 | ||||
| 	constexpr coral::u8 signature_magic[signature_length]{'o', 'a', 'r', 0}; | ||||
| 		enum class [[nodiscard]] open_result { | ||||
| 			ok, | ||||
| 			io_unavailable, | ||||
| 			archive_invalid, | ||||
| 			archive_unsupported, | ||||
| 			not_found, | ||||
| 		}; | ||||
| 
 | ||||
| 	struct entry { | ||||
| 		coral::u8 signature_magic[signature_length]; | ||||
| 		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; | ||||
| 		} | ||||
| 
 | ||||
| 		coral::path path; | ||||
| 		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::u8 padding[244]; | ||||
| 		coral::u64 data_cursor; | ||||
| 	}; | ||||
| 
 | ||||
| 	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, | ||||
| 			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, | ||||
| 			coral::callable<void(coral::writable const &)> const & then) override { | ||||
| 			coral::callable<void(coral::file_writer &)> const & then) override { | ||||
| 
 | ||||
| 			// Read-only file system.
 | ||||
| 		} | ||||
| 
 | ||||
| 		private: | ||||
| 		coral::fs * backing_fs; | ||||
| 
 | ||||
| 		coral::path archive_path; | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| static_assert(sizeof(oar::entry) == 512); | ||||
|  | ||||
| @ -15,7 +15,7 @@ extern "C" int main(int argc, char const * const * argv) { | ||||
| 		constexpr coral::path config_path{"config.kym"}; | ||||
| 		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()}; | ||||
| 
 | ||||
| 			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::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(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) { | ||||
| 						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, | ||||
| 								"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}; | ||||
| 
 | ||||
| 				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; | ||||
| 
 | ||||
| 				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; | ||||
| 			} | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user