add io::directory_iterator

This commit is contained in:
MihailRis 2025-01-31 10:07:05 +03:00
parent c3066eebd3
commit 347d76870a
13 changed files with 182 additions and 64 deletions

View File

@ -94,8 +94,7 @@ static void add_layouts(
if (!io::is_directory(folder)) { if (!io::is_directory(folder)) {
return; return;
} }
for (auto& entry : fs::directory_iterator(io::resolve(folder))) { for (const auto& file : io::directory_iterator(folder)) {
io::path file = folder / entry.path().filename().u8string();
if (file.extension() != ".xml") continue; if (file.extension() != ".xml") continue;
std::string name = prefix + ":" + file.stem(); std::string name = prefix + ":" + file.stem();
loader.add( loader.add(

View File

@ -50,8 +50,7 @@ static void detect_defs(
if (!io::is_directory(folder)) { if (!io::is_directory(folder)) {
return; return;
} }
for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { for (const auto& file : io::directory_iterator(folder)) {
io::path file = folder / entry.path().filename().u8string();
std::string name = file.stem(); std::string name = file.stem();
if (name[0] == '_') { if (name[0] == '_') {
continue; continue;
@ -75,8 +74,7 @@ static void detect_defs_pairs(
if (!io::is_directory(folder)) { if (!io::is_directory(folder)) {
return; return;
} }
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { for (const auto& file : io::directory_iterator(folder)) {
io::path file = folder / entry.path().filename().u8string();
std::string name = file.stem(); std::string name = file.stem();
if (name[0] == '_') { if (name[0] == '_') {
continue; continue;
@ -747,8 +745,7 @@ static inline void foreach_file(
if (!io::is_directory(dir)) { if (!io::is_directory(dir)) {
return; return;
} }
for (const auto& entry : fs::directory_iterator(io::resolve(dir))) { for (const auto& path : io::directory_iterator(dir)) {
io::path path = dir / entry.path().filename().u8string();
if (io::is_directory(path)) { if (io::is_directory(path)) {
continue; continue;
} }
@ -808,8 +805,7 @@ void ContentLoader::load() {
// Load block materials // Load block materials
io::path materialsDir = folder / "block_materials"; io::path materialsDir = folder / "block_materials";
if (io::is_directory(materialsDir)) { if (io::is_directory(materialsDir)) {
for (const auto& entry : fs::directory_iterator(io::resolve(materialsDir))) { for (const auto& file : io::directory_iterator(materialsDir)) {
io::path file = materialsDir / entry.path().filename().u8string();
auto [packid, full, filename] = auto [packid, full, filename] =
create_unit_id(pack->id, file.stem()); create_unit_id(pack->id, file.stem());
loadBlockMaterial( loadBlockMaterial(

View File

@ -129,8 +129,7 @@ void ContentPack::scanFolder(
if (!io::is_directory(folder)) { if (!io::is_directory(folder)) {
return; return;
} }
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { for (const auto& packFolder : io::directory_iterator(folder)) {
io::path packFolder = folder / entry.path().filename().u8string();
if (!io::is_directory(packFolder)) continue; if (!io::is_directory(packFolder)) continue;
if (!is_pack(packFolder)) continue; if (!is_pack(packFolder)) continue;
try { try {

View File

@ -23,6 +23,7 @@ namespace io {
virtual void mkdirs(std::string_view path) = 0; virtual void mkdirs(std::string_view path) = 0;
virtual bool remove(std::string_view path) = 0; virtual bool remove(std::string_view path) = 0;
virtual uint64_t removeAll(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 { class SubDevice : public Device {
@ -69,6 +70,10 @@ namespace io {
uint64_t removeAll(std::string_view path) override { uint64_t removeAll(std::string_view path) override {
return parent->removeAll((root / path).pathPart()); return parent->removeAll((root / path).pathPart());
} }
std::unique_ptr<PathsGenerator> list(std::string_view path) override {
return parent->list((root / path).pathPart());
}
private: private:
std::shared_ptr<Device> parent; std::shared_ptr<Device> parent;
path root; path root;

View File

@ -4,9 +4,10 @@
#include <filesystem> #include <filesystem>
using namespace io; using namespace io;
namespace fs = std::filesystem;
std::filesystem::path StdfsDevice::resolve(std::string_view path) { fs::path StdfsDevice::resolve(std::string_view path) {
return root / std::filesystem::u8path(path); return root / fs::u8path(path);
} }
void StdfsDevice::write(std::string_view path, const void* data, size_t size) { 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) { size_t StdfsDevice::size(std::string_view path) {
auto resolved = resolve(path); auto resolved = resolve(path);
return std::filesystem::file_size(resolved); return fs::file_size(resolved);
} }
bool StdfsDevice::exists(std::string_view path) { bool StdfsDevice::exists(std::string_view path) {
auto resolved = resolve(path); auto resolved = resolve(path);
return std::filesystem::exists(resolved); return fs::exists(resolved);
} }
bool StdfsDevice::isdir(std::string_view path) { bool StdfsDevice::isdir(std::string_view path) {
auto resolved = resolve(path); auto resolved = resolve(path);
return std::filesystem::is_directory(resolved); return fs::is_directory(resolved);
} }
bool StdfsDevice::isfile(std::string_view path) { bool StdfsDevice::isfile(std::string_view path) {
auto resolved = resolve(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) { void StdfsDevice::mkdirs(std::string_view path) {
auto resolved = resolve(path); auto resolved = resolve(path);
std::filesystem::create_directories(resolved); fs::create_directories(resolved);
} }
bool StdfsDevice::remove(std::string_view path) { bool StdfsDevice::remove(std::string_view path) {
auto resolved = resolve(path); auto resolved = resolve(path);
return std::filesystem::remove(resolved); return fs::remove(resolved);
} }
uint64_t StdfsDevice::removeAll(std::string_view path) { uint64_t StdfsDevice::removeAll(std::string_view path) {
auto resolved = resolve(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));
} }

View File

@ -15,6 +15,7 @@ namespace io {
void mkdirs(std::string_view path) override; void mkdirs(std::string_view path) override;
bool remove(std::string_view path) override; bool remove(std::string_view path) override;
uint64_t removeAll(std::string_view path) override; uint64_t removeAll(std::string_view path) override;
std::unique_ptr<PathsGenerator> list(std::string_view path) override;
private: private:
std::filesystem::path root; std::filesystem::path root;
}; };

View File

@ -145,11 +145,10 @@ std::vector<io::path> EnginePaths::scanForWorlds() const {
auto folder = getWorldsFolder(); auto folder = getWorldsFolder();
if (!io::is_directory(folder)) return folders; if (!io::is_directory(folder)) return folders;
for (const auto& entry : std::filesystem::directory_iterator(io::resolve(folder))) { for (const auto& worldFolder : io::directory_iterator(folder)) {
if (!entry.is_directory()) { if (!io::is_directory(worldFolder)) {
continue; continue;
} }
io::path worldFolder = folder / entry.path().filename().u8string();
auto worldFile = worldFolder / WorldFiles::WORLD_FILE; auto worldFile = worldFolder / WorldFiles::WORLD_FILE;
if (!io::is_regular_file(worldFile)) { if (!io::is_regular_file(worldFile)) {
continue; continue;
@ -271,9 +270,8 @@ std::vector<std::string> ResPaths::listdirRaw(const std::string& folderName) con
auto& root = roots[i]; auto& root = roots[i];
auto folder = root.path / fs::u8path(folderName); auto folder = root.path / fs::u8path(folderName);
if (!io::is_directory(folder)) continue; if (!io::is_directory(folder)) continue;
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { for (const auto& file : io::directory_iterator(folder)) {
auto name = entry.path().filename().u8string(); entries.emplace_back(root.name + ":" + folderName + "/" + file.name());
entries.emplace_back(root.name + ":" + folderName + "/" + name);
} }
} }
return entries; return entries;
@ -287,8 +285,8 @@ std::vector<io::path> ResPaths::listdir(
auto& root = roots[i]; auto& root = roots[i];
io::path folder = root.path / folderName; io::path folder = root.path / folderName;
if (!io::is_directory(folder)) continue; if (!io::is_directory(folder)) continue;
for (const auto& entry : fs::directory_iterator(io::resolve(folder))) { for (const auto& entry : io::directory_iterator(folder)) {
entries.push_back(folder / entry.path().filename().u8string()); entries.push_back(folder / entry);
} }
} }
return entries; return entries;

View File

@ -49,6 +49,12 @@ void io::create_subdevice(
set_device(name, std::make_shared<io::SubDevice>(parentDevice, root.pathPart())); 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) io::rafile::rafile(const io::path& filename)
: file(io::resolve(filename), std::ios::binary | std::ios::ate) { : file(io::resolve(filename), std::ios::binary | std::ios::ate) {
if (!file) { 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) { bool io::is_regular_file(const io::path& file) {
if (file.empty()) { if (file.emptyOrInvalid()) {
return false; return false;
} }
auto device = io::get_device(file.entryPoint()); 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) { bool io::is_directory(const io::path& file) {
if (file.empty()) { if (file.emptyOrInvalid()) {
return false; return false;
} }
auto device = io::get_device(file.entryPoint()); 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) { bool io::exists(const io::path& file) {
if (file.empty()) { if (file.emptyOrInvalid()) {
return false; return false;
} }
auto device = io::get_device(file.entryPoint()); auto device = io::get_device(file.entryPoint());

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <filesystem> #include <filesystem>
#include <iterator>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <string> #include <string>
@ -34,6 +35,75 @@ namespace io {
size_t length() const; 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 &current;
}
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 /// @brief Write bytes array to the file without any extra data
/// @param file target file /// @param file target file
/// @param data data bytes array /// @param data data bytes array
@ -87,7 +157,11 @@ namespace io {
std::filesystem::path resolve(const io::path& file); 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); 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); bool is_data_interchange_format(const std::string& ext);
dv::value read_object(const path& file); dv::value read_object(const path& file);
} }

View File

@ -127,6 +127,10 @@ namespace io {
bool empty() const { bool empty() const {
return str.empty(); return str.empty();
} }
bool emptyOrInvalid() const {
return str.empty() || colonPos == std::string::npos;
}
private: private:
/// @brief UTF-8 string contains entry_point:path or empty string /// @brief UTF-8 string contains entry_point:path or empty string
std::string str; std::string str;
@ -135,4 +139,10 @@ namespace io {
void checkValid() const; void checkValid() const;
}; };
class PathsGenerator {
public:
virtual ~PathsGenerator() = default;
virtual bool next(path& dst) = 0;
};
} }

View File

@ -95,7 +95,8 @@ static int l_exists(lua::State* L) {
} }
static int l_isfile(lua::State* L) { static int l_isfile(lua::State* L) {
io::path path = resolve_path_soft(lua::require_string(L, 1)); const char* string =lua::require_string(L, 1);
io::path path = resolve_path_soft(string);
return lua::pushboolean(L, io::is_regular_file(path)); return lua::pushboolean(L, io::is_regular_file(path));
} }
@ -184,10 +185,8 @@ static int l_list(lua::State* L) {
} }
lua::createtable(L, 0, 0); lua::createtable(L, 0, 0);
size_t index = 1; size_t index = 1;
for (auto& entry : fs::directory_iterator(io::resolve(path))) { for (const auto& file : io::directory_iterator(path)) {
auto name = entry.path().filename().u8string(); lua::pushstring(L, file.string());
auto file = dirname + "/" + name;
lua::pushstring(L, file);
lua::rawseti(L, index); lua::rawseti(L, index);
index++; index++;
} }

View File

@ -1,13 +1,13 @@
#pragma once #pragma once
#include <stdexcept>
#include <typeindex> #include <typeindex>
#include <typeinfo> #include <typeinfo>
#include <stdexcept>
#include <unordered_map> #include <unordered_map>
#include "data/dv.hpp" #include "data/dv.hpp"
#include "lua_wrapper.hpp"
#include "lua_custom_types.hpp" #include "lua_custom_types.hpp"
#include "lua_wrapper.hpp"
#define GLM_ENABLE_EXPERIMENTAL #define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
@ -68,7 +68,7 @@ namespace lua {
return 1; return 1;
} }
template<int n> template <int n>
inline int pushvec_stack(lua::State* L, const glm::vec<n, float>& vec) { inline int pushvec_stack(lua::State* L, const glm::vec<n, float>& vec) {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
pushnumber(L, vec[i]); pushnumber(L, vec[i]);
@ -76,7 +76,7 @@ namespace lua {
return n; return n;
} }
template<int n> template <int n>
inline int pushivec_stack(lua::State* L, const glm::vec<n, int>& vec) { inline int pushivec_stack(lua::State* L, const glm::vec<n, int>& vec) {
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
pushinteger(L, vec[i]); pushinteger(L, vec[i]);
@ -108,10 +108,10 @@ namespace lua {
inline int pushquat(lua::State* L, glm::quat quat) { inline int pushquat(lua::State* L, glm::quat quat) {
createtable(L, 4, 0); createtable(L, 4, 0);
pushnumber(L, quat.w); pushnumber(L, quat.w);
rawseti(L, 1); rawseti(L, 1);
pushnumber(L, quat.x); pushnumber(L, quat.x);
rawseti(L, 2); rawseti(L, 2);
@ -127,7 +127,7 @@ namespace lua {
pushnumber(L, quat.w); pushnumber(L, quat.w);
rawseti(L, 1); rawseti(L, 1);
pushnumber(L, quat.x); pushnumber(L, quat.x);
rawseti(L, 2); rawseti(L, 2);
@ -287,8 +287,9 @@ namespace lua {
} }
template <class T> template <class T>
inline std::enable_if_t<std::is_base_of_v<Userdata, T>> inline std::enable_if_t<std::is_base_of_v<Userdata, T>> newusertype(
newusertype(lua::State* L) { lua::State* L
) {
const std::string& name = T::TYPENAME; const std::string& name = T::TYPENAME;
usertypeNames[typeid(T)] = name; usertypeNames[typeid(T)] = name;
T::createMetatable(L); T::createMetatable(L);
@ -386,7 +387,7 @@ namespace lua {
rawgeti(L, 4); rawgeti(L, 4);
auto z = tonumber(L, -1); auto z = tonumber(L, -1);
pop(L); pop(L);
pop(L); pop(L);
return glm::quat(x, y, z, w); return glm::quat(x, y, z, w);
} }
@ -445,8 +446,7 @@ namespace lua {
int pushvalue(lua::State*, const dv::value& value); int pushvalue(lua::State*, const dv::value& value);
[[nodiscard]] [[nodiscard]] dv::value tovalue(lua::State*, int idx);
dv::value tovalue(lua::State*, int idx);
inline bool getfield(lua::State* L, const std::string& name, int idx = -1) { inline bool getfield(lua::State* L, const std::string& name, int idx = -1) {
lua_getfield(L, idx, name.c_str()); lua_getfield(L, idx, name.c_str());
@ -457,11 +457,13 @@ namespace lua {
return true; return true;
} }
inline int requirefield(lua::State* L, const std::string& name, int idx = -1) { inline int requirefield(
lua::State* L, const std::string& name, int idx = -1
) {
if (getfield(L, name, idx)) { if (getfield(L, name, idx)) {
return 1; return 1;
} }
throw std::runtime_error("object has no member '"+name+"'"); throw std::runtime_error("object has no member '" + name + "'");
} }
inline bool hasfield(lua::State* L, const std::string& name, int idx = -1) { inline bool hasfield(lua::State* L, const std::string& name, int idx = -1) {
@ -637,7 +639,7 @@ namespace lua {
} }
inline const char* require_string_field( inline const char* require_string_field(
lua::State* L, const std::string& name, int idx=-1 lua::State* L, const std::string& name, int idx = -1
) { ) {
requirefield(L, name, idx); requirefield(L, name, idx);
auto value = require_string(L, -1); auto value = require_string(L, -1);
@ -646,7 +648,7 @@ namespace lua {
} }
inline Integer require_integer_field( inline Integer require_integer_field(
lua::State* L, const std::string& name, int idx=-1 lua::State* L, const std::string& name, int idx = -1
) { ) {
requirefield(L, name, idx); requirefield(L, name, idx);
auto value = tointeger(L, -1); auto value = tointeger(L, -1);
@ -655,7 +657,7 @@ namespace lua {
} }
inline Number require_number_field( inline Number require_number_field(
lua::State* L, const std::string& name, int idx=-1 lua::State* L, const std::string& name, int idx = -1
) { ) {
requirefield(L, name, idx); requirefield(L, name, idx);
auto value = tonumber(L, -1); auto value = tonumber(L, -1);
@ -664,7 +666,7 @@ namespace lua {
} }
inline bool get_boolean_field( inline bool get_boolean_field(
lua::State* L, const std::string& name, bool def, int idx=-1 lua::State* L, const std::string& name, bool def, int idx = -1
) { ) {
if (getfield(L, name, idx)) { if (getfield(L, name, idx)) {
bool value = toboolean(L, -1); bool value = toboolean(L, -1);
@ -675,7 +677,7 @@ namespace lua {
} }
inline Integer get_integer_field( inline Integer get_integer_field(
lua::State* L, const std::string& name, Integer def, int idx=-1 lua::State* L, const std::string& name, Integer def, int idx = -1
) { ) {
if (getfield(L, name, idx)) { if (getfield(L, name, idx)) {
auto value = tointeger(L, -1); auto value = tointeger(L, -1);
@ -686,7 +688,7 @@ namespace lua {
} }
inline Number get_number_field( inline Number get_number_field(
lua::State* L, const std::string& name, Number def, int idx=-1 lua::State* L, const std::string& name, Number def, int idx = -1
) { ) {
if (getfield(L, name, idx)) { if (getfield(L, name, idx)) {
auto value = tonumber(L, -1); auto value = tonumber(L, -1);
@ -697,15 +699,20 @@ namespace lua {
} }
inline Integer get_integer_field( inline Integer get_integer_field(
lua::State* L, const std::string& name, lua::State* L,
Integer def, Integer min, Integer max, int idx=-1 const std::string& name,
Integer def,
Integer min,
Integer max,
int idx = -1
) { ) {
if (getfield(L, name, idx)) { if (getfield(L, name, idx)) {
auto value = tointeger(L, -1); auto value = tointeger(L, -1);
if (value < min || value > max) { if (value < min || value > max) {
throw std::runtime_error( throw std::runtime_error(
"value is out of range [" "value is out of range [" + std::to_string(min) + ", " +
+std::to_string(min)+", "+std::to_string(max)+"]"); std::to_string(max) + "]"
);
} }
pop(L); pop(L);
return value; return value;

View File

@ -42,14 +42,14 @@ void WorldConverter::addRegionsTasks(
if (!io::is_directory(regionsFolder)) { if (!io::is_directory(regionsFolder)) {
return; return;
} }
for (const auto& file : fs::directory_iterator(io::resolve(regionsFolder))) { for (const auto& file :io::directory_iterator(regionsFolder)) {
int x, z; int x, z;
std::string name = file.path().stem().string(); std::string name = file.stem();
if (!WorldRegions::parseRegionFilename(name, x, z)) { if (!WorldRegions::parseRegionFilename(name, x, z)) {
logger.error() << "could not parse region name " << name; logger.error() << "could not parse region name " << name;
continue; continue;
} }
tasks.push(ConvertTask {taskType, file.path().u8string(), x, z, layerid}); tasks.push(ConvertTask {taskType, file, x, z, layerid});
} }
} }