diff --git a/src/io/devices/Device.hpp b/src/io/devices/Device.hpp index bb000602..98666415 100644 --- a/src/io/devices/Device.hpp +++ b/src/io/devices/Device.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include #include "../path.hpp" @@ -13,7 +15,7 @@ namespace io { virtual std::filesystem::path resolve(std::string_view path) = 0; virtual void write(std::string_view path, const void* data, size_t size) = 0; - virtual void read(std::string_view path, void* data, size_t size) = 0; + virtual std::unique_ptr read(std::string_view path) = 0; virtual size_t size(std::string_view path) = 0; @@ -43,8 +45,8 @@ namespace io { parent->write((root / path).pathPart(), data, size); } - void read(std::string_view path, void* data, size_t size) override { - parent->read((root / path).pathPart(), data, size); + std::unique_ptr read(std::string_view path) override { + return parent->read((root / path).pathPart()); } size_t size(std::string_view path) override { diff --git a/src/io/devices/StdfsDevice.cpp b/src/io/devices/StdfsDevice.cpp index ad33547d..e5009e00 100644 --- a/src/io/devices/StdfsDevice.cpp +++ b/src/io/devices/StdfsDevice.cpp @@ -35,13 +35,13 @@ void StdfsDevice::write(std::string_view path, const void* data, size_t size) { output.write((const char*)data, size); } -void StdfsDevice::read(std::string_view path, void* data, size_t size) { +std::unique_ptr StdfsDevice::read(std::string_view path) { auto resolved = resolve(path); - std::ifstream input(resolved, std::ios::binary); - if (!input.is_open()) { + auto input = std::make_unique(resolved, std::ios::binary); + if (!*input) { throw std::runtime_error("could not to open file " + resolved.u8string()); } - input.read((char*)data, size); + return input; } size_t StdfsDevice::size(std::string_view path) { diff --git a/src/io/devices/StdfsDevice.hpp b/src/io/devices/StdfsDevice.hpp index 819dfe4f..9112f2f9 100644 --- a/src/io/devices/StdfsDevice.hpp +++ b/src/io/devices/StdfsDevice.hpp @@ -7,7 +7,7 @@ namespace io { std::filesystem::path resolve(std::string_view path) override; void write(std::string_view path, const void* data, size_t size) override; - void read(std::string_view path, void* data, size_t size) override; + std::unique_ptr read(std::string_view path) override; size_t size(std::string_view path) override; bool exists(std::string_view path) override; bool isdir(std::string_view path) override; diff --git a/src/io/io.cpp b/src/io/io.cpp index a9ee86de..efb241d4 100644 --- a/src/io/io.cpp +++ b/src/io/io.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "coders/commons.hpp" @@ -60,12 +61,16 @@ io::directory_iterator::directory_iterator(const io::path& folder) } io::rafile::rafile(const io::path& filename) - : file(io::resolve(filename), std::ios::binary | std::ios::ate) { - if (!file) { + : file(std::make_unique(io::resolve(filename), std::ios::binary | std::ios::ate)) { + if (!*file) { throw std::runtime_error("could not to open file " + filename.string()); } - filelength = file.tellg(); - file.seekg(0); + filelength = file->tellg(); + file->seekg(0); +} + +io::rafile::rafile(std::unique_ptr file, size_t length) + : file(std::move(file)), filelength(length) { } size_t io::rafile::length() const { @@ -73,11 +78,11 @@ size_t io::rafile::length() const { } void io::rafile::seekg(std::streampos pos) { - file.seekg(pos); + file->seekg(pos); } void io::rafile::read(char* buffer, std::streamsize size) { - file.read(buffer, size); + file->read(buffer, size); } bool io::write_bytes( @@ -96,8 +101,17 @@ bool io::read(const io::path& filename, char* data, size_t size) { if (device == nullptr) { return false; } - device->read(filename.pathPart(), data, size); - return true; + auto stream = io::read(filename); + stream->read(data, size); + return stream->good(); +} + +std::unique_ptr io::read(const io::path& filename) { + auto device = io::get_device(filename.entryPoint()); + if (device == nullptr) { + throw std::runtime_error("io-device not found: " + filename.entryPoint()); + } + return device->read(filename.pathPart()); } util::Buffer io::read_bytes_buffer(const path& file) { @@ -112,15 +126,17 @@ std::unique_ptr io::read_bytes( auto& device = io::require_device(filename.entryPoint()); length = device.size(filename.pathPart()); auto data = std::make_unique(length); - device.read(filename.pathPart(), data.get(), length); - return data; + auto stream = io::read(filename); + stream->read(reinterpret_cast(data.get()), length); + return stream->good() ? std::move(data) : nullptr; } std::vector io::read_bytes(const path& filename) { auto& device = io::require_device(filename.entryPoint()); size_t length = device.size(filename.pathPart()); std::vector data(length); - device.read(filename.pathPart(), data.data(), length); + auto stream = io::read(filename); + stream->read(reinterpret_cast(data.data()), length); return data; } @@ -163,15 +179,10 @@ dv::value io::read_toml(const path& file) { } std::vector io::read_list(const io::path& filename) { - std::ifstream file(resolve(filename)); // FIXME - if (!file) { - throw std::runtime_error( - "could not to open file " + filename.string() - ); - } + auto stream = io::read(filename); std::vector lines; std::string line; - while (std::getline(file, line)) { + while (std::getline(*stream, line)) { util::trim(line); if (line.length() == 0) continue; if (line[0] == '#') continue; diff --git a/src/io/io.hpp b/src/io/io.hpp index 14541eea..ba63688e 100644 --- a/src/io/io.hpp +++ b/src/io/io.hpp @@ -15,21 +15,33 @@ namespace io { class Device; + /// @brief Set device for the entry-point void set_device(const std::string& name, std::shared_ptr device); + + /// @brief Remove device by entry-point void remove_device(const std::string& name); + + /// @brief Get device by entry-point std::shared_ptr get_device(const std::string& name); + + /// @brief Get device by entry-point or throw exception Device& require_device(const std::string& name); + /// @brief Create subdevice for the entry-point + /// @param name subdevice entry-point + /// @param parent parent device entry-point + /// @param root root path for the subdevice void create_subdevice( const std::string& name, const std::string& parent, const path& root ); /// @brief Read-only random access file class rafile { - std::ifstream file; + std::unique_ptr file; size_t filelength; public: rafile(const path& filename); + rafile(std::unique_ptr file, size_t length); void seekg(std::streampos pos); void read(char* buffer, std::streamsize size); @@ -131,6 +143,7 @@ namespace io { ); bool read(const io::path& file, char* data, size_t size); + std::unique_ptr read(const io::path& file); util::Buffer read_bytes_buffer(const path& file); std::unique_ptr read_bytes(const path& file, size_t& length); std::vector read_bytes(const path& file); @@ -140,21 +153,38 @@ namespace io { /// @param file *.json or *.bjson file dv::value read_json(const path& file); + /// @brief Read BJSON file dv::value read_binary_json(const path& file); /// @brief Read TOML file /// @param file *.toml file dv::value read_toml(const path& file); + /// @brief Read list of strings from the file std::vector read_list(const io::path& file); + /// @brief Check if path is a regular file bool is_regular_file(const io::path& file); - bool is_directory(const io::path& file); - bool exists(const io::path& file); + + /// @brief Check if path is a directory + bool is_directory(const io::path& path); + + /// @brief Check if file or directory exists + bool exists(const io::path& path); + + /// @brief Create directory bool create_directory(const io::path& file); + + /// @brief Create directories recursively bool create_directories(const io::path& file); + + /// @brief Remove file or empty directory bool remove(const io::path& file); + + /// @brief Remove all files and directories in the folder recursively uint64_t remove_all(const io::path& file); + + /// @brief Get file size in bytes size_t file_size(const io::path& file); std::filesystem::path resolve(const io::path& file);