add io::directory_iterator
This commit is contained in:
@@ -23,6 +23,7 @@ namespace io {
|
||||
virtual void mkdirs(std::string_view path) = 0;
|
||||
virtual bool remove(std::string_view path) = 0;
|
||||
virtual uint64_t removeAll(std::string_view path) = 0;
|
||||
virtual std::unique_ptr<PathsGenerator> list(std::string_view path) = 0;
|
||||
};
|
||||
|
||||
class SubDevice : public Device {
|
||||
@@ -69,6 +70,10 @@ namespace io {
|
||||
uint64_t removeAll(std::string_view path) override {
|
||||
return parent->removeAll((root / path).pathPart());
|
||||
}
|
||||
|
||||
std::unique_ptr<PathsGenerator> list(std::string_view path) override {
|
||||
return parent->list((root / path).pathPart());
|
||||
}
|
||||
private:
|
||||
std::shared_ptr<Device> parent;
|
||||
path root;
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
#include <filesystem>
|
||||
|
||||
using namespace io;
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::filesystem::path StdfsDevice::resolve(std::string_view path) {
|
||||
return root / std::filesystem::u8path(path);
|
||||
fs::path StdfsDevice::resolve(std::string_view path) {
|
||||
return root / fs::u8path(path);
|
||||
}
|
||||
|
||||
void StdfsDevice::write(std::string_view path, const void* data, size_t size) {
|
||||
@@ -29,35 +30,58 @@ void StdfsDevice::read(std::string_view path, void* data, size_t size) {
|
||||
|
||||
size_t StdfsDevice::size(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::file_size(resolved);
|
||||
return fs::file_size(resolved);
|
||||
}
|
||||
|
||||
bool StdfsDevice::exists(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::exists(resolved);
|
||||
return fs::exists(resolved);
|
||||
}
|
||||
|
||||
bool StdfsDevice::isdir(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::is_directory(resolved);
|
||||
return fs::is_directory(resolved);
|
||||
}
|
||||
|
||||
bool StdfsDevice::isfile(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::is_regular_file(resolved);
|
||||
return fs::is_regular_file(resolved);
|
||||
}
|
||||
|
||||
void StdfsDevice::mkdirs(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
std::filesystem::create_directories(resolved);
|
||||
fs::create_directories(resolved);
|
||||
}
|
||||
|
||||
bool StdfsDevice::remove(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::remove(resolved);
|
||||
return fs::remove(resolved);
|
||||
}
|
||||
|
||||
uint64_t StdfsDevice::removeAll(std::string_view path) {
|
||||
auto resolved = resolve(path);
|
||||
return std::filesystem::remove_all(resolved);
|
||||
return fs::remove_all(resolved);
|
||||
}
|
||||
|
||||
class StdfsPathsGenerator : public PathsGenerator {
|
||||
public:
|
||||
StdfsPathsGenerator(fs::path root) : root(std::move(root)) {
|
||||
it = fs::directory_iterator(this->root);
|
||||
}
|
||||
|
||||
bool next(io::path& path) override {
|
||||
if (it == fs::directory_iterator()) {
|
||||
return false;
|
||||
}
|
||||
path = it->path().filename().u8string();
|
||||
it++;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
fs::path root;
|
||||
fs::directory_iterator it;
|
||||
};
|
||||
|
||||
std::unique_ptr<PathsGenerator> StdfsDevice::list(std::string_view path) {
|
||||
return std::make_unique<StdfsPathsGenerator>(root / fs::u8path(path));
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace io {
|
||||
void mkdirs(std::string_view path) override;
|
||||
bool remove(std::string_view path) override;
|
||||
uint64_t removeAll(std::string_view path) override;
|
||||
std::unique_ptr<PathsGenerator> list(std::string_view path) override;
|
||||
private:
|
||||
std::filesystem::path root;
|
||||
};
|
||||
|
||||
@@ -145,11 +145,10 @@ std::vector<io::path> EnginePaths::scanForWorlds() const {
|
||||
auto folder = getWorldsFolder();
|
||||
if (!io::is_directory(folder)) return folders;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) {
|
||||
if (!entry.is_directory()) {
|
||||
for (const auto& worldFolder : io::directory_iterator(folder)) {
|
||||
if (!io::is_directory(worldFolder)) {
|
||||
continue;
|
||||
}
|
||||
io::path worldFolder = folder / entry.path().filename().u8string();
|
||||
auto worldFile = worldFolder / WorldFiles::WORLD_FILE;
|
||||
if (!io::is_regular_file(worldFile)) {
|
||||
continue;
|
||||
@@ -271,9 +270,8 @@ std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName) con
|
||||
auto& root = roots[i];
|
||||
auto folder = root.path / fs::u8path(folderName);
|
||||
if (!io::is_directory(folder)) continue;
|
||||
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) {
|
||||
auto name = entry.path().filename().u8string();
|
||||
entries.emplace_back(root.name + ":" + folderName + "/" + name);
|
||||
for (const auto& file : io::directory_iterator(folder)) {
|
||||
entries.emplace_back(root.name + ":" + folderName + "/" + file.name());
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
@@ -287,8 +285,8 @@ std::vector<io::path> ResPaths::listdir(
|
||||
auto& root = roots[i];
|
||||
io::path folder = root.path / folderName;
|
||||
if (!io::is_directory(folder)) continue;
|
||||
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) {
|
||||
entries.push_back(folder / entry.path().filename().u8string());
|
||||
for (const auto& entry : io::directory_iterator(folder)) {
|
||||
entries.push_back(folder / entry);
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
|
||||
+9
-3
@@ -49,6 +49,12 @@ void io::create_subdevice(
|
||||
set_device(name, std::make_shared<io::SubDevice>(parentDevice, root.pathPart()));
|
||||
}
|
||||
|
||||
io::directory_iterator::directory_iterator(const io::path& folder)
|
||||
: folder(folder) {
|
||||
auto& device = io::require_device(folder.entryPoint());
|
||||
generator = device.list(folder.pathPart());
|
||||
}
|
||||
|
||||
io::rafile::rafile(const io::path& filename)
|
||||
: file(io::resolve(filename), std::ios::binary | std::ios::ate) {
|
||||
if (!file) {
|
||||
@@ -171,7 +177,7 @@ std::vector<std::string> io::read_list(const io::path& filename) {
|
||||
}
|
||||
|
||||
bool io::is_regular_file(const io::path& file) {
|
||||
if (file.empty()) {
|
||||
if (file.emptyOrInvalid()) {
|
||||
return false;
|
||||
}
|
||||
auto device = io::get_device(file.entryPoint());
|
||||
@@ -182,7 +188,7 @@ bool io::is_regular_file(const io::path& file) {
|
||||
}
|
||||
|
||||
bool io::is_directory(const io::path& file) {
|
||||
if (file.empty()) {
|
||||
if (file.emptyOrInvalid()) {
|
||||
return false;
|
||||
}
|
||||
auto device = io::get_device(file.entryPoint());
|
||||
@@ -193,7 +199,7 @@ bool io::is_directory(const io::path& file) {
|
||||
}
|
||||
|
||||
bool io::exists(const io::path& file) {
|
||||
if (file.empty()) {
|
||||
if (file.emptyOrInvalid()) {
|
||||
return false;
|
||||
}
|
||||
auto device = io::get_device(file.entryPoint());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <iterator>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -34,6 +35,75 @@ namespace io {
|
||||
size_t length() const;
|
||||
};
|
||||
|
||||
class directory_iterator_impl {
|
||||
public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = path;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = path*;
|
||||
using reference = path&;
|
||||
|
||||
directory_iterator_impl(
|
||||
PathsGenerator& generator, const path& folder, bool end = false
|
||||
)
|
||||
: generator(generator), folder(folder), isend(end) {
|
||||
if (!isend && this->generator.next(current)) {
|
||||
isend = false;
|
||||
current = folder / current;
|
||||
} else {
|
||||
isend = true;
|
||||
}
|
||||
}
|
||||
|
||||
reference operator*() {
|
||||
return current;
|
||||
}
|
||||
|
||||
pointer operator->() {
|
||||
return ¤t;
|
||||
}
|
||||
|
||||
directory_iterator_impl& operator++() {
|
||||
if (isend) {
|
||||
return *this;
|
||||
}
|
||||
if (generator.next(current)) {
|
||||
current = folder / current;
|
||||
} else {
|
||||
isend = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const directory_iterator_impl& other) const {
|
||||
return isend == other.isend;
|
||||
}
|
||||
|
||||
bool operator!=(const directory_iterator_impl& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
private:
|
||||
PathsGenerator& generator;
|
||||
path folder;
|
||||
path current;
|
||||
bool isend = false;
|
||||
};
|
||||
|
||||
class directory_iterator {
|
||||
std::unique_ptr<PathsGenerator> generator;
|
||||
path folder;
|
||||
public:
|
||||
directory_iterator(const path& folder);
|
||||
|
||||
directory_iterator_impl begin() {
|
||||
return directory_iterator_impl(*generator, folder);
|
||||
}
|
||||
|
||||
directory_iterator_impl end() {
|
||||
return directory_iterator_impl(*generator, "", true);
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Write bytes array to the file without any extra data
|
||||
/// @param file target file
|
||||
/// @param data data bytes array
|
||||
@@ -87,7 +157,11 @@ namespace io {
|
||||
|
||||
std::filesystem::path resolve(const io::path& file);
|
||||
|
||||
/// @brief Check if file is one of the supported data interchange formats
|
||||
bool is_data_file(const io::path& file);
|
||||
|
||||
/// @brief Check if file extension is one of the supported data interchange formats
|
||||
bool is_data_interchange_format(const std::string& ext);
|
||||
|
||||
dv::value read_object(const path& file);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,10 @@ namespace io {
|
||||
bool empty() const {
|
||||
return str.empty();
|
||||
}
|
||||
|
||||
bool emptyOrInvalid() const {
|
||||
return str.empty() || colonPos == std::string::npos;
|
||||
}
|
||||
private:
|
||||
/// @brief UTF-8 string contains entry_point:path or empty string
|
||||
std::string str;
|
||||
@@ -135,4 +139,10 @@ namespace io {
|
||||
|
||||
void checkValid() const;
|
||||
};
|
||||
|
||||
class PathsGenerator {
|
||||
public:
|
||||
virtual ~PathsGenerator() = default;
|
||||
virtual bool next(path& dst) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user