mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-11-19 19:52:06 +00:00
Merge pull request #583 from Laupetin/feature/iwd-include
feat: include user files in iwd
This commit is contained in:
@@ -15,7 +15,7 @@ public:
|
|||||||
std::unique_ptr<std::istream> m_stream;
|
std::unique_ptr<std::istream> m_stream;
|
||||||
int64_t m_length;
|
int64_t m_length;
|
||||||
|
|
||||||
_NODISCARD bool IsOpen() const;
|
[[nodiscard]] bool IsOpen() const;
|
||||||
|
|
||||||
SearchPathOpenFile();
|
SearchPathOpenFile();
|
||||||
SearchPathOpenFile(std::unique_ptr<std::istream> stream, int64_t length);
|
SearchPathOpenFile(std::unique_ptr<std::istream> stream, int64_t length);
|
||||||
|
|||||||
@@ -3,13 +3,42 @@
|
|||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
#include "Utils/ObjFileStream.h"
|
#include "Utils/ObjFileStream.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
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)
|
SearchPathFilesystem::SearchPathFilesystem(std::string path)
|
||||||
: m_path(std::move(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<void(const std::string&)>& callback)
|
void SearchPathFilesystem::Find(const SearchPathSearchOptions& options, const std::function<void(const std::string&)>& callback)
|
||||||
{
|
{
|
||||||
|
std::string prefix = options.m_prefix;
|
||||||
|
std::string path = m_path;
|
||||||
|
if (!CheckOptionsPrefix(prefix, path))
|
||||||
|
return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (options.m_should_include_subdirectories)
|
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)
|
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||||
{
|
{
|
||||||
auto path = entry->path();
|
if (!entry->is_regular_file())
|
||||||
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
|
|
||||||
continue;
|
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
|
else
|
||||||
{
|
{
|
||||||
std::filesystem::directory_iterator iterator(m_path);
|
std::filesystem::directory_iterator iterator(path);
|
||||||
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
for (const auto entry = begin(iterator); iterator != end(iterator); ++iterator)
|
||||||
{
|
{
|
||||||
auto path = entry->path();
|
if (!entry->is_regular_file())
|
||||||
if (options.m_filter_extensions && path.extension().string() != options.m_extension)
|
|
||||||
continue;
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,3 +39,10 @@ SearchPathSearchOptions& SearchPathSearchOptions::FilterExtensions(std::string e
|
|||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SearchPathSearchOptions& SearchPathSearchOptions::FilterPrefix(std::string prefix)
|
||||||
|
{
|
||||||
|
m_prefix = std::move(prefix);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,17 +5,19 @@
|
|||||||
class SearchPathSearchOptions
|
class SearchPathSearchOptions
|
||||||
{
|
{
|
||||||
public:
|
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();
|
||||||
|
|
||||||
SearchPathSearchOptions& IncludeSubdirectories(bool value);
|
SearchPathSearchOptions& IncludeSubdirectories(bool value);
|
||||||
SearchPathSearchOptions& OnlyDiskFiles(bool value);
|
SearchPathSearchOptions& OnlyDiskFiles(bool value);
|
||||||
SearchPathSearchOptions& AbsolutePaths(bool value);
|
SearchPathSearchOptions& AbsolutePaths(bool value);
|
||||||
SearchPathSearchOptions& FilterExtensions(std::string extension);
|
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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,12 +3,71 @@
|
|||||||
#include "Utils/FileToZlibWrapper.h"
|
#include "Utils/FileToZlibWrapper.h"
|
||||||
#include "Utils/Logging/Log.h"
|
#include "Utils/Logging/Log.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <filesystem>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <fstream>
|
|
||||||
#include <iostream>
|
|
||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
|
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<std::chrono::days>(localNow);
|
||||||
|
const std::chrono::year_month_day ymd(std::chrono::floor<std::chrono::days>(localNow));
|
||||||
|
const std::chrono::hh_mm_ss hms(std::chrono::floor<std::chrono::milliseconds>(localNow - nowDays));
|
||||||
|
|
||||||
|
fileInfo.dosDate = 0u;
|
||||||
|
fileInfo.tmz_date.tm_year = static_cast<int>(ymd.year());
|
||||||
|
fileInfo.tmz_date.tm_mon = static_cast<int>(static_cast<unsigned>(ymd.month()) - static_cast<unsigned>(std::chrono::January));
|
||||||
|
fileInfo.tmz_date.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));
|
||||||
|
fileInfo.tmz_date.tm_hour = static_cast<int>(hms.hours().count());
|
||||||
|
fileInfo.tmz_date.tm_min = static_cast<int>(hms.minutes().count());
|
||||||
|
fileInfo.tmz_date.tm_sec = static_cast<int>(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<unsigned>(readCount));
|
||||||
|
} while (!readFile.m_stream->eof());
|
||||||
|
|
||||||
|
zipCloseFileInZip(zipFile);
|
||||||
|
|
||||||
|
con::debug("Added {} to iwd {}", normalizedPath, iwdName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
IwdToCreate::IwdToCreate(std::string name)
|
IwdToCreate::IwdToCreate(std::string name)
|
||||||
: m_name(std::move(name))
|
: m_name(std::move(name))
|
||||||
{
|
{
|
||||||
@@ -73,8 +132,12 @@ void IwdToCreate::Build(ISearchPath& searchPath, IOutputPath& outPath)
|
|||||||
} while (!readFile.m_stream->eof());
|
} while (!readFile.m_stream->eof());
|
||||||
|
|
||||||
zipCloseFileInZip(zipFile);
|
zipCloseFileInZip(zipFile);
|
||||||
|
|
||||||
|
con::debug("Added {} to iwd {}", filePath, m_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddCustomUserInclusions(searchPath, zipFile, m_name);
|
||||||
|
|
||||||
zipClose(zipFile, nullptr);
|
zipClose(zipFile, nullptr);
|
||||||
|
|
||||||
con::info("Created iwd {} with {} entries", m_name, m_file_paths.size());
|
con::info("Created iwd {} with {} entries", m_name, m_file_paths.size());
|
||||||
|
|||||||
Reference in New Issue
Block a user