From 74ef6118b649cfe21f3ec389aef779b762de033e Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Tue, 18 Nov 2025 21:13:56 +0000 Subject: [PATCH] feat: include user files in iwd --- src/ObjCommon/SearchPath/ISearchPath.h | 2 +- .../SearchPath/SearchPathFilesystem.cpp | 84 +++++++++++++++++-- .../SearchPath/SearchPathSearchOptions.cpp | 7 ++ .../SearchPath/SearchPathSearchOptions.h | 16 ++-- src/ObjCompiling/Iwd/IwdCreator.cpp | 67 ++++++++++++++- 5 files changed, 157 insertions(+), 19 deletions(-) diff --git a/src/ObjCommon/SearchPath/ISearchPath.h b/src/ObjCommon/SearchPath/ISearchPath.h index c174f2f3..53ed4639 100644 --- a/src/ObjCommon/SearchPath/ISearchPath.h +++ b/src/ObjCommon/SearchPath/ISearchPath.h @@ -15,7 +15,7 @@ public: std::unique_ptr m_stream; int64_t m_length; - _NODISCARD bool IsOpen() const; + [[nodiscard]] bool IsOpen() const; SearchPathOpenFile(); SearchPathOpenFile(std::unique_ptr stream, int64_t length); diff --git a/src/ObjCommon/SearchPath/SearchPathFilesystem.cpp b/src/ObjCommon/SearchPath/SearchPathFilesystem.cpp index 4cd54d62..6e5e4c07 100644 --- a/src/ObjCommon/SearchPath/SearchPathFilesystem.cpp +++ b/src/ObjCommon/SearchPath/SearchPathFilesystem.cpp @@ -3,13 +3,42 @@ #include "Utils/Logging/Log.h" #include "Utils/ObjFileStream.h" +#include #include #include #include -#include namespace fs = std::filesystem; +namespace +{ + bool CheckOptionsPrefix(std::string& prefix, std::string& path) + { + if (prefix.empty()) + return true; + + const auto combinedPath = fs::path(path) / prefix; + if (fs::status(combinedPath).type() == std::filesystem::file_type::directory) + { + prefix = std::string(); + path = combinedPath.string(); + return true; + } + + const auto parentDir = combinedPath.parent_path(); + if (!parentDir.empty()) + { + if (fs::status(parentDir).type() != std::filesystem::file_type::directory) + return false; + + path = parentDir.string(); + prefix = combinedPath.filename().string(); + } + + return true; + } +} // namespace + SearchPathFilesystem::SearchPathFilesystem(std::string path) : m_path(std::move(path)) { @@ -33,28 +62,65 @@ SearchPathOpenFile SearchPathFilesystem::Open(const std::string& fileName) void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function& callback) { + std::string prefix = options.m_prefix; + std::string path = m_path; + if (!CheckOptionsPrefix(prefix, path)) + return; + try { if (options.m_should_include_subdirectories) { - std::filesystem::recursive_directory_iterator iterator(m_path); + std::filesystem::recursive_directory_iterator iterator(path); for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator) { - auto path = entry->path(); - if (options.m_filter_extensions && path.extension().string() != options.m_extension) + if (!entry->is_regular_file()) continue; - callback(options.m_absolute_paths ? absolute(path).string() : path.string()); + + auto entryPath = entry->path(); + if (!prefix.empty() && !entryPath.filename().string().starts_with(prefix)) + continue; + + if (options.m_filter_extensions && entryPath.extension().string() != options.m_extension) + continue; + + const auto absolutePath = absolute(entryPath); + if (options.m_absolute_paths) + { + callback(absolutePath.string()); + } + else + { + const auto relativePath = fs::relative(entryPath, m_path); + callback(relativePath.string()); + } } } else { - std::filesystem::directory_iterator iterator(m_path); + std::filesystem::directory_iterator iterator(path); for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator) { - auto path = entry->path(); - if (options.m_filter_extensions && path.extension().string() != options.m_extension) + if (!entry->is_regular_file()) continue; - callback(options.m_absolute_paths ? absolute(path).string() : path.string()); + + auto entryPath = entry->path(); + if (!prefix.empty() && !entryPath.filename().string().starts_with(prefix)) + continue; + + if (options.m_filter_extensions && entryPath.extension().string() != options.m_extension) + continue; + + const auto absolutePath = absolute(entryPath); + if (options.m_absolute_paths) + { + callback(absolutePath.string()); + } + else + { + const auto relativePath = fs::relative(absolutePath, m_path); + callback(relativePath.string()); + } } } } diff --git a/src/ObjCommon/SearchPath/SearchPathSearchOptions.cpp b/src/ObjCommon/SearchPath/SearchPathSearchOptions.cpp index 679929c7..0c297791 100644 --- a/src/ObjCommon/SearchPath/SearchPathSearchOptions.cpp +++ b/src/ObjCommon/SearchPath/SearchPathSearchOptions.cpp @@ -39,3 +39,10 @@ SearchPathSearchOptions& SearchPathSearchOptions::FilterExtensions(std::string e return *this; } + +SearchPathSearchOptions& SearchPathSearchOptions::FilterPrefix(std::string prefix) +{ + m_prefix = std::move(prefix); + + return *this; +} diff --git a/src/ObjCommon/SearchPath/SearchPathSearchOptions.h b/src/ObjCommon/SearchPath/SearchPathSearchOptions.h index eb9cfdc4..bd073d41 100644 --- a/src/ObjCommon/SearchPath/SearchPathSearchOptions.h +++ b/src/ObjCommon/SearchPath/SearchPathSearchOptions.h @@ -5,17 +5,19 @@ class SearchPathSearchOptions { public: - bool m_should_include_subdirectories; - bool m_disk_files_only; - bool m_absolute_paths; - - bool m_filter_extensions; - std::string m_extension; - SearchPathSearchOptions(); SearchPathSearchOptions& IncludeSubdirectories(bool value); SearchPathSearchOptions& OnlyDiskFiles(bool value); SearchPathSearchOptions& AbsolutePaths(bool value); SearchPathSearchOptions& FilterExtensions(std::string extension); + SearchPathSearchOptions& FilterPrefix(std::string prefix); + + bool m_should_include_subdirectories; + bool m_disk_files_only; + bool m_absolute_paths; + bool m_filter_extensions; + + std::string m_extension; + std::string m_prefix; }; diff --git a/src/ObjCompiling/Iwd/IwdCreator.cpp b/src/ObjCompiling/Iwd/IwdCreator.cpp index aa79fce1..a584ee48 100644 --- a/src/ObjCompiling/Iwd/IwdCreator.cpp +++ b/src/ObjCompiling/Iwd/IwdCreator.cpp @@ -3,12 +3,71 @@ #include "Utils/FileToZlibWrapper.h" #include "Utils/Logging/Log.h" +#include #include +#include #include -#include -#include #include +namespace fs = std::filesystem; + +namespace +{ + void FillFileInfoTime(zip_fileinfo& fileInfo) + { + const auto localNow = std::chrono::zoned_time{std::chrono::current_zone(), std::chrono::system_clock::now()}.get_local_time(); + const auto nowDays = std::chrono::floor(localNow); + const std::chrono::year_month_day ymd(std::chrono::floor(localNow)); + const std::chrono::hh_mm_ss hms(std::chrono::floor(localNow - nowDays)); + + fileInfo.dosDate = 0u; + fileInfo.tmz_date.tm_year = static_cast(ymd.year()); + fileInfo.tmz_date.tm_mon = static_cast(static_cast(ymd.month()) - static_cast(std::chrono::January)); + fileInfo.tmz_date.tm_mday = static_cast(static_cast(ymd.day())); + fileInfo.tmz_date.tm_hour = static_cast(hms.hours().count()); + fileInfo.tmz_date.tm_min = static_cast(hms.minutes().count()); + fileInfo.tmz_date.tm_sec = static_cast(hms.seconds().count()); + } + + void AddCustomUserInclusions(ISearchPath& searchPath, zipFile zipFile, const std::string& iwdName) + { + const auto prefix = std::format("iwd/{}", iwdName); + searchPath.Find(SearchPathSearchOptions().OnlyDiskFiles(true).FilterPrefix(prefix).IncludeSubdirectories(true), + [&searchPath, &zipFile, &prefix, &iwdName](const std::string& path) + { + const auto relativePath = fs::relative(path, prefix); + + std::string normalizedPath(relativePath.string()); + std::ranges::replace(normalizedPath, '\\', '/'); + + const auto readFile = searchPath.Open(path); + if (!readFile.IsOpen()) + { + con::error("Failed to open file for iwd: {}", path); + return; + } + + zip_fileinfo fileInfo{}; + FillFileInfoTime(fileInfo); + zipOpenNewFileInZip(zipFile, normalizedPath.c_str(), &fileInfo, nullptr, 0, nullptr, 0, nullptr, Z_DEFLATED, Z_DEFAULT_COMPRESSION); + + char tempBuffer[0x1000]; + + do + { + readFile.m_stream->read(tempBuffer, sizeof(tempBuffer)); + const auto readCount = readFile.m_stream->gcount(); + if (readCount > 0) + zipWriteInFileInZip(zipFile, tempBuffer, static_cast(readCount)); + } while (!readFile.m_stream->eof()); + + zipCloseFileInZip(zipFile); + + con::debug("Added {} to iwd {}", normalizedPath, iwdName); + }); + } +} // namespace + IwdToCreate::IwdToCreate(std::string name) : m_name(std::move(name)) { @@ -73,8 +132,12 @@ void IwdToCreate::Build(ISearchPath& searchPath, IOutputPath& outPath) } while (!readFile.m_stream->eof()); zipCloseFileInZip(zipFile); + + con::debug("Added {} to iwd {}", filePath, m_name); } + AddCustomUserInclusions(searchPath, zipFile, m_name); + zipClose(zipFile, nullptr); con::info("Created iwd {} with {} entries", m_name, m_file_paths.size());