2020-08-11 12:07:21 -04:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
#include <optional>
|
|
|
|
#include <array>
|
|
|
|
#include <filesystem>
|
|
|
|
|
2020-08-13 07:48:50 -04:00
|
|
|
#include "log.hpp"
|
2020-09-21 09:37:52 -04:00
|
|
|
#include "path.hpp"
|
2020-08-13 07:48:50 -04:00
|
|
|
|
2021-05-12 08:50:02 -04:00
|
|
|
namespace prism {
|
|
|
|
enum class domain {
|
2022-05-21 18:28:48 -04:00
|
|
|
game,
|
|
|
|
base
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/// Represents a file handle. The file may or may not be fully loaded in memory.
|
2021-05-12 08:50:02 -04:00
|
|
|
class file {
|
2020-08-11 12:07:21 -04:00
|
|
|
public:
|
2021-05-12 08:50:02 -04:00
|
|
|
explicit file(FILE* handle) : handle(handle) {}
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-05-12 08:50:02 -04:00
|
|
|
file(file&& f) noexcept :
|
2020-08-11 12:07:21 -04:00
|
|
|
mem(std::move(f.mem)),
|
|
|
|
handle(std::exchange(f.handle, nullptr)),
|
|
|
|
data(std::move(f.data)) {}
|
|
|
|
|
2021-05-12 08:50:02 -04:00
|
|
|
~file() {
|
2020-08-14 17:45:51 -04:00
|
|
|
if(handle != nullptr)
|
|
|
|
fclose(handle);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Loads a type.
|
|
|
|
@param t The pointer to the type.
|
|
|
|
@param s If not 0, the size to load is derived from sizeof(T).
|
|
|
|
*/
|
|
|
|
template<typename T>
|
|
|
|
void read(T* t, const size_t s = 0) {
|
|
|
|
fread(t, s == 0 ? sizeof(T) : s, 1, handle);
|
|
|
|
}
|
|
|
|
|
2022-02-21 12:07:30 -05:00
|
|
|
void seek(const size_t s) {
|
|
|
|
fseek(handle, s, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
/// Reads a string. Assumes the length is an unsigned integer.
|
|
|
|
void read_string(std::string& str) {
|
|
|
|
unsigned int length = 0;
|
|
|
|
read(&length);
|
|
|
|
|
|
|
|
if(length > 0) {
|
|
|
|
str.resize(length);
|
|
|
|
|
|
|
|
read(str.data(), sizeof(char) * length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Loads the entire file into memory, accessible via cast_data()
|
|
|
|
void read_all() {
|
|
|
|
fseek(handle, 0L, SEEK_END);
|
2021-05-12 08:50:02 -04:00
|
|
|
const auto _size = static_cast<size_t>(ftell(handle));
|
2020-08-11 12:07:21 -04:00
|
|
|
rewind(handle);
|
|
|
|
|
|
|
|
data.resize(_size);
|
|
|
|
fread(data.data(), _size, 1, handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the file is loaded in memory, cast the underlying data.
|
|
|
|
template<typename T>
|
|
|
|
T* cast_data() {
|
|
|
|
return reinterpret_cast<T*>(data.data());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the file is loaded in memory, return the size of the file.
|
2021-05-12 08:50:02 -04:00
|
|
|
[[nodiscard]] size_t size() const {
|
2020-08-11 12:07:21 -04:00
|
|
|
return data.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Reads the entire file as a string.
|
|
|
|
std::string read_as_string() {
|
|
|
|
auto s = read_as_stream();
|
2021-10-14 08:51:58 -04:00
|
|
|
return {(std::istreambuf_iterator<char>(s)), std::istreambuf_iterator<char>()};
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Reads the entire file as a ifstream, useful for JSON deserialization.
|
|
|
|
std::istream read_as_stream() {
|
|
|
|
read_all();
|
|
|
|
|
|
|
|
auto char_data = cast_data<char>();
|
|
|
|
mem = std::make_unique<membuf>(char_data, char_data + size());
|
|
|
|
return std::istream(mem.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
struct membuf : std::streambuf {
|
|
|
|
inline membuf(char* begin, char* end) {
|
|
|
|
this->setg(begin, begin, end);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unique_ptr<membuf> mem;
|
|
|
|
|
|
|
|
FILE* handle = nullptr;
|
|
|
|
|
|
|
|
std::vector<std::byte> data;
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Sets the domain path to a location in the filesystem.
|
|
|
|
@param domain The domain type.
|
|
|
|
@param mode The access mode.
|
|
|
|
@param path The absolute file path.
|
|
|
|
*/
|
2021-10-14 08:51:58 -04:00
|
|
|
void set_domain_path(domain domain, const path& domain_path);
|
2021-05-12 09:05:56 -04:00
|
|
|
path get_domain_path(domain domain);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
/// Converts an absolute path to a domain relative path.
|
2021-10-14 08:51:58 -04:00
|
|
|
path get_relative_path(domain domain, const path& domain_relative_path);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
/// Returns the path to a writeable directory.
|
2021-05-12 09:05:56 -04:00
|
|
|
path get_writeable_directory();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
Opens a file handle.
|
|
|
|
@param domain The file domain.
|
|
|
|
@param path The file path.
|
|
|
|
@param binary_mode Whether or not to open the file as binary or ASCII. Defaults to false.
|
|
|
|
@return An optional with a value if the file was loaded correctly, otherwise it's empty.
|
|
|
|
*/
|
2021-10-14 08:51:58 -04:00
|
|
|
std::optional<file> open_file(const path& file_path, bool binary_mode = false);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-10-14 08:51:58 -04:00
|
|
|
path root_path(const path& path);
|
2021-05-12 09:05:56 -04:00
|
|
|
path get_file_path(const path& path);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2022-05-21 18:28:48 -04:00
|
|
|
inline path base_domain = "/base", game_domain = "/game";
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
inline std::array<std::string, 3> domain_data;
|