From 827c667b8834e06b8c1a0595d794f4692fc57415 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Fri, 23 Nov 2018 18:49:44 +0700 Subject: [PATCH] vfs: trace, extract --- headers/enduro2d/core/vfs.hpp | 15 ++++++++ sources/enduro2d/core/vfs.cpp | 52 ++++++++++++++++++++++++++++ untests/bin/resources.zip | 4 +-- untests/sources/untests_core/vfs.cpp | 43 +++++++++++++++++++++++ 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/headers/enduro2d/core/vfs.hpp b/headers/enduro2d/core/vfs.hpp index f2ff2ae6..efba595c 100644 --- a/headers/enduro2d/core/vfs.hpp +++ b/headers/enduro2d/core/vfs.hpp @@ -30,6 +30,7 @@ namespace e2d virtual input_stream_uptr open(str_view path) const = 0; virtual std::pair load(str_view path) const = 0; virtual output_stream_uptr write(str_view path, bool append) const = 0; + virtual bool trace(str_view path, filesystem::trace_func func) const = 0; }; using file_source_uptr = std::unique_ptr; @@ -47,6 +48,10 @@ namespace e2d output_stream_uptr write(const url& url, bool append) const; std::future> load_async(const url& url) const; + template < typename Iter > + bool extract(const url& url, Iter result_iter) const; + bool trace(const url& url, filesystem::trace_func func) const; + url resolve_scheme_aliases(const url& url) const; private: class state; @@ -62,6 +67,7 @@ namespace e2d input_stream_uptr open(str_view path) const final; std::pair load(str_view path) const final; output_stream_uptr write(str_view path, bool append) const final; + bool trace(str_view path, filesystem::trace_func func) const final; private: class state; std::unique_ptr state_; @@ -76,6 +82,7 @@ namespace e2d input_stream_uptr open(str_view path) const final; std::pair load(str_view path) const final; output_stream_uptr write(str_view path, bool append) const final; + bool trace(str_view path, filesystem::trace_func func) const final; }; } @@ -87,4 +94,12 @@ namespace e2d scheme, std::make_unique(std::forward(args)...)); } + + template < typename Iter > + bool vfs::extract(const url& url, Iter result_iter) const { + return trace(url, [&result_iter](str_view filename, bool directory){ + *result_iter++ = std::pair{filename, directory}; + return true; + }); + } } diff --git a/sources/enduro2d/core/vfs.cpp b/sources/enduro2d/core/vfs.cpp index c5324e6c..7091ac99 100644 --- a/sources/enduro2d/core/vfs.cpp +++ b/sources/enduro2d/core/vfs.cpp @@ -173,6 +173,14 @@ namespace e2d }, open(url)); } + bool vfs::trace(const url& url, filesystem::trace_func func) const { + std::lock_guard guard(state_->mutex); + return state_->with_file_source(url, + [&func](const file_source_uptr& source, const str& path) { + return source->trace(path, func); + }, false); + } + url vfs::resolve_scheme_aliases(const url& url) const { std::lock_guard guard(state_->mutex); return state_->resolve_url(url); @@ -276,6 +284,46 @@ namespace e2d return nullptr; } + bool archive_file_source::trace(str_view path, filesystem::trace_func func) const { + str parent = make_utf8(path); + if ( !parent.empty() ) { + if ( parent.back() != '/' ) { + parent += '/'; + } + mz_uint32 dir_index = 0; + if ( !mz_zip_reader_locate_file_v2( + state_->archive.get(), + parent.c_str(), + nullptr, + MZ_ZIP_FLAG_CASE_SENSITIVE, + &dir_index) ) + { + return false; + } + mz_zip_archive_file_stat dir_stat; + if ( !mz_zip_reader_file_stat( + state_->archive.get(), + dir_index, &dir_stat) ) + { + return false; + } + if ( !dir_stat.m_is_directory ) { + return false; + } + } + mz_uint num_files = mz_zip_reader_get_num_files(state_->archive.get()); + for ( mz_uint i = 0; i < num_files; ++i ) { + mz_zip_archive_file_stat file_stat; + if ( mz_zip_reader_file_stat(state_->archive.get(), i, &file_stat) ) { + const str_view filename{file_stat.m_filename}; + if ( filename.length() > parent.length() && filename.starts_with(parent) ) { + func(file_stat.m_filename, file_stat.m_is_directory); + } + } + } + return true; + } + // // filesystem_file_source // @@ -308,4 +356,8 @@ namespace e2d } return make_write_file(path, append); } + + bool filesystem_file_source::trace(str_view path, filesystem::trace_func func) const { + return filesystem::trace_directory_recursive(path, func); + } } diff --git a/untests/bin/resources.zip b/untests/bin/resources.zip index 173b57dc..39ff6d40 100644 --- a/untests/bin/resources.zip +++ b/untests/bin/resources.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c72ff0ca4cd5c914d557f6e1c08c1f63f7d4da3339c15f1c2b5def5fe13d32d2 -size 440 +oid sha256:7f9dbd20a52c39630253723d3e5c0f478c8cd70de48048966c0ca5becaa97fe3 +size 1423 diff --git a/untests/sources/untests_core/vfs.cpp b/untests/sources/untests_core/vfs.cpp index 873c2387..1fb55608 100644 --- a/untests/sources/untests_core/vfs.cpp +++ b/untests/sources/untests_core/vfs.cpp @@ -78,6 +78,49 @@ TEST_CASE("vfs"){ REQUIRE_FALSE(v.exists({"archive", "test2.txt"})); REQUIRE_FALSE(v.exists({"archive", "folder/file2.txt"})); + { + vector> result; + REQUIRE(v.extract(url("archive://"), std::back_inserter(result))); + REQUIRE(result == vector>{ + {"folder/", true}, + {"folder/file.txt", false}, + {"test.txt", false}, + {"folder/subfolder/", true}, + {"folder/subfolder/file.txt", false}, + {"folder2/", true}, + {"folder2/file.txt", false}, + {"folder2/subfolder2/", true}, + {"folder2/subfolder2/file.txt", false} + }); + } + { + vector> result; + REQUIRE(v.extract(url("archive://folder"), std::back_inserter(result))); + REQUIRE(result == vector>{ + {"folder/file.txt", false}, + {"folder/subfolder/", true}, + {"folder/subfolder/file.txt", false} + }); + } + { + vector> result; + REQUIRE(v.extract(url("archive://folder2/subfolder2"), std::back_inserter(result))); + REQUIRE(result == vector>{ + {"folder2/subfolder2/file.txt", false} + }); + } + { + vector> result, result2; + REQUIRE(v.extract(url("archive://folder"), std::back_inserter(result))); + REQUIRE(v.extract(url("archive://folder/"), std::back_inserter(result2))); + REQUIRE(result == result2); + } + { + vector> result; + REQUIRE_FALSE(v.extract(url("archive://fold"), std::back_inserter(result))); + REQUIRE_FALSE(v.extract(url("archive://folder3"), std::back_inserter(result))); + REQUIRE_FALSE(v.extract(url("archive://test.txt"), std::back_inserter(result))); + } { auto f = v.open(url("archive://test.txt")); REQUIRE(f);