mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-22 03:46:53 +02:00
launcher: compress game folders to ZAR
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -143,6 +144,72 @@ void CheckMalformedArchives(const std::filesystem::path &source,
|
||||
"recover by reading an unaffected compressed block");
|
||||
}
|
||||
|
||||
void WriteHostFile(const std::filesystem::path &path, const void *data, size_t size) {
|
||||
std::ofstream stream(path, std::ios::binary);
|
||||
stream.write(static_cast<const char *>(data), static_cast<std::streamsize>(size));
|
||||
Check(stream.good(), "write pack source file");
|
||||
}
|
||||
|
||||
void CheckPackArchive(const std::filesystem::path &root, const std::vector<uint8_t> &payload) {
|
||||
const auto source = root / "pack-source";
|
||||
const auto unicode = Common::PathFromUtf8(ArchiveTests::UnicodeFilename);
|
||||
std::error_code error;
|
||||
Check(std::filesystem::create_directories(source / "assets/subdir", error) &&
|
||||
std::filesystem::create_directories(source / "empty", error),
|
||||
"create pack source tree");
|
||||
WriteHostFile(source / "eboot.bin", ArchiveTests::Eboot.data(), ArchiveTests::Eboot.size());
|
||||
WriteHostFile(source / "assets/subdir/data.bin", payload.data(), payload.size());
|
||||
WriteHostFile(source / unicode, nullptr, 0);
|
||||
uint64_t expected = ArchiveTests::Eboot.size() + payload.size();
|
||||
#if !defined(_WIN32)
|
||||
std::filesystem::create_directory_symlink("assets", source / "linked", error);
|
||||
Check(!error, "link a pack source directory");
|
||||
expected += payload.size();
|
||||
#endif
|
||||
|
||||
const auto archive = root / "packed.zar";
|
||||
uint64_t done = 0;
|
||||
uint64_t total = 0;
|
||||
Check(Common::PackArchive(source, archive,
|
||||
[&](uint64_t packed, uint64_t size) {
|
||||
done = packed;
|
||||
total = size;
|
||||
return true;
|
||||
}),
|
||||
"pack a host directory");
|
||||
Check(done == expected && total == expected, "report every packed byte");
|
||||
|
||||
const auto packed = Common::MakeArchivePath(archive);
|
||||
const auto check_payload = [&](const std::filesystem::path &member) {
|
||||
Common::File file(packed / member, Common::File::Mode::Read);
|
||||
const auto data = file.ReadWholeBuffer();
|
||||
Check(data.size() == payload.size() &&
|
||||
std::memcmp(data.data(), payload.data(), payload.size()) == 0,
|
||||
"round-trip packed file contents");
|
||||
};
|
||||
check_payload("assets/subdir/data.bin");
|
||||
#if !defined(_WIN32)
|
||||
check_payload("linked/subdir/data.bin");
|
||||
#endif
|
||||
const auto empty_file = Common::File::GetInfo(packed / unicode);
|
||||
Check(empty_file && empty_file->is_file && empty_file->size == 0 &&
|
||||
Common::File::IsDirectoryExisting(packed / "empty"),
|
||||
"keep empty files and directories");
|
||||
|
||||
const auto failed = root / "failed.zar";
|
||||
const auto rejected = [&](const std::filesystem::path &directory, bool proceed) {
|
||||
return !Common::PackArchive(directory, failed, [=](uint64_t, uint64_t) { return proceed; }) &&
|
||||
!std::filesystem::exists(failed, error);
|
||||
};
|
||||
Check(rejected(source, false), "cancelling removes the partial archive");
|
||||
Check(rejected(root / "missing", true), "reject a missing source directory");
|
||||
#if defined(__linux__)
|
||||
// Archive names compare case-insensitively, so such a folder cannot be packed faithfully.
|
||||
WriteHostFile(source / "EBOOT.BIN", nullptr, 0);
|
||||
Check(rejected(source, true), "reject names that differ only in case");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) || defined(_GLIBCXX_GCC_GTHR_POSIX_H)
|
||||
void CheckCancellation(const std::filesystem::path &path,
|
||||
const std::vector<uint8_t> &payload) {
|
||||
@@ -395,6 +462,8 @@ int main() {
|
||||
std::memcmp(replaced_data.data(), replacement.data(), replacement.size()) == 0,
|
||||
"reopening after the final reader closes sees replacement contents");
|
||||
|
||||
CheckPackArchive(temporary.Path(), payload);
|
||||
|
||||
std::printf("ArchiveFileTests: all cases passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user