// Round-trip verification tool: opens a pack read-only, reads every entry via // the same CEterPack::Get() path the game engine uses, and byte-compares it // against the corresponding file under a source folder. // // Usage: PackVerify.exe // e.g. PackVerify.exe "Y:\scratch\pack" root "Y:\Metin2Dev\Exec_Client\Eternexus\root" #include #include #include #include #include #include "../EterPack/EterPack.h" int main(int argc, char** argv) { if (argc < 4) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } const char* pathName = argv[1]; const char* dbname = argv[2]; std::string sourceFolder = argv[3]; if (!SetCurrentDirectoryA(pathName)) { fprintf(stderr, "FAILED to chdir to '%s'\n", pathName); return 4; } CEterFileDict dict; CEterPack pack; if (!pack.Create(dict, dbname, "", true)) { fprintf(stderr, "FAILED to open pack '%s' in '%s'\n", dbname, pathName); return 2; } std::vector names; if (!pack.GetNames(&names)) { fprintf(stderr, "FAILED GetNames\n"); return 3; } long okCount = 0, mismatchCount = 0, missingSrcCount = 0, getFailCount = 0; for (auto& name : names) { std::string srcPath = sourceFolder + "\\" + name; for (auto& c : srcPath) if (c == '/') c = '\\'; std::ifstream srcFile(srcPath, std::ios::binary | std::ios::ate); if (!srcFile) { fprintf(stderr, "MISSING SOURCE: %s (expected at %s)\n", name.c_str(), srcPath.c_str()); ++missingSrcCount; continue; } std::streamsize srcSize = srcFile.tellg(); srcFile.seekg(0); std::vector srcData(srcSize); srcFile.read(srcData.data(), srcSize); CMappedFile mappedFile; LPCVOID packData = NULL; if (!pack.Get(mappedFile, name.c_str(), &packData)) { fprintf(stderr, "Get() FAILED: %s\n", name.c_str()); ++getFailCount; continue; } DWORD packSize = mappedFile.Size(); if ((std::streamsize)packSize != srcSize || memcmp(packData, srcData.data(), srcSize) != 0) { fprintf(stderr, "MISMATCH: %s (src %lld bytes, pack %lu bytes)\n", name.c_str(), (long long)srcSize, packSize); ++mismatchCount; continue; } ++okCount; } printf("Verified %ld entries: %ld OK, %ld mismatched, %ld missing-source, %ld get-failed\n", (long)names.size(), okCount, mismatchCount, missingSrcCount, getFailCount); return (mismatchCount > 0 || getFailCount > 0) ? 5 : 0; }