// EterPack writer -> reader round trip (no external pack file needed). #include "../src/pack/eterpack.h" #include "../src/pack/pack_mount.h" #include #include #include #include #include using namespace mtpack; static int g_fail = 0; #define CHECK(c, msg) \ do { \ if (!(c)) { \ std::fprintf(stderr, "FAIL: %s\n", msg); \ ++g_fail; \ } \ } while (0) static std::vector bytes(const std::string &s) { return std::vector(s.begin(), s.end()); } static bool roundtrip(bool encrypt, const char *tag) { std::vector in; in.push_back({"d:/ymir work/pc/warrior/warrior.gr2", bytes(std::string(5000, 'A'))}); // compressible { std::vector rnd(4096); for (size_t i = 0; i < rnd.size(); ++i) { rnd[i] = static_cast((i * 2654435761u) >> 13); } in.push_back({"textureset/metin2_a1.txt", rnd}); } in.push_back({"tiny.dat", bytes("x")}); in.push_back({"nested/deep/path/file.bin", bytes("hello \x00 world binary\xff\xfe")}); std::string path = std::string(std::getenv("TMPDIR") ? std::getenv("TMPDIR") : "/tmp") + "/mtpack_test_" + tag + ".epk"; std::string err; if (!write_pack(path, in, encrypt, &err)) { std::fprintf(stderr, "write_pack(%s): %s\n", tag, err.c_str()); return false; } EterPack pk; if (!pk.open(path, &err)) { std::fprintf(stderr, "open(%s): %s\n", tag, err.c_str()); return false; } CHECK(pk.count() == in.size(), "entry count"); CHECK(pk.name_field() == PACK_NAME_FIELD_DEFAULT, "derived name field == default"); for (const auto &f : in) { CHECK(pk.has(f.name), (std::string("has ") + f.name).c_str()); // case / slash insensitivity std::string up = f.name; for (auto &c : up) { c = static_cast(std::toupper((unsigned char)c)); } std::replace(up.begin(), up.end(), '/', '\\'); CHECK(pk.has(up), (std::string("has (norm) ") + f.name).c_str()); std::vector got; if (!pk.read(f.name, got, &err)) { std::fprintf(stderr, "read(%s): %s\n", f.name.c_str(), err.c_str()); ++g_fail; continue; } CHECK(got == f.data, (std::string("bytes match ") + f.name).c_str()); } CHECK(!pk.read("does/not/exist", *(new std::vector()), &err), "missing file -> false"); std::remove(path.c_str()); return true; } static std::string tmp(const char *n) { return std::string(std::getenv("TMPDIR") ? std::getenv("TMPDIR") : "/tmp") + "/mtpack_" + n; } static bool mount_test() { // pack A: base assets, "ymir work/" layout std::vector a; a.push_back({"ymir work/ui/pattern/board_base.tga", bytes("BASE-BOARD-v1")}); a.push_back({"ymir work/tree/b1_pagoda.spt", bytes(std::string(2000, 'S'))}); a.push_back({"locale/loading.png", bytes("PNGDATA")}); std::string pa = tmp("mount_a.epk"); std::string err; if (!write_pack(pa, a, false, &err)) { std::fprintf(stderr, "write A: %s\n", err.c_str()); return false; } // pack B: a patch that overrides board_base std::vector b; b.push_back({"ymir work/ui/pattern/board_base.tga", bytes("BASE-BOARD-v2-PATCHED")}); std::string pb = tmp("metin2_patch_x.epk"); if (!write_pack(pb, b, true, &err)) { std::fprintf(stderr, "write B: %s\n", err.c_str()); return false; } mtpack::PackMount m; CHECK(m.mount(pa, &err), ("mount A: " + err).c_str()); CHECK(m.mount(pb, &err), ("mount B: " + err).c_str()); CHECK(m.pack_count() == 2, "2 packs mounted"); std::vector out; // full path CHECK(m.has("ymir work/tree/b1_pagoda.spt"), "has by full path"); CHECK(m.read("ymir work/tree/b1_pagoda.spt", out) && out.size() == 2000, "read by full path"); // virtual path with drive + backslashes + case CHECK(m.has("D:\\YMIR WORK\\Tree\\B1_Pagoda.spt"), "has by d:\\ virtual path"); CHECK(m.read("d:/ymir work/tree/b1_pagoda.spt", out) && out.size() == 2000, "read by virtual"); // "ymir work/"-suffix keying: a vpath that omits the leading dirs CHECK(m.read("somewhere/ymir work/ui/pattern/board_base.tga", out), "read via ymir-suffix"); // later pack (patch) wins CHECK(std::string(out.begin(), out.end()) == "BASE-BOARD-v2-PATCHED", "patch pack overrides base"); // non-ymir path still works CHECK(m.read("locale/loading.png", out) && std::string(out.begin(), out.end()) == "PNGDATA", "non-ymir path"); CHECK(!m.has("does/not/exist"), "missing -> false"); std::remove(pa.c_str()); std::remove(pb.c_str()); return true; } int main() { CHECK(roundtrip(false, "plain"), "plain roundtrip ran"); CHECK(roundtrip(true, "enc"), "encrypted roundtrip ran"); CHECK(mount_test(), "PackMount test ran"); if (g_fail) { std::fprintf(stderr, "%d check(s) failed\n", g_fail); return 1; } std::printf("all checks passed\n"); return 0; }