From c858f8a9146f20525152bacf1913415ff7d44acc Mon Sep 17 00:00:00 2001 From: Alex Macocian Date: Fri, 17 Nov 2023 13:37:08 +0100 Subject: [PATCH] Implemented complete parsing --- source/gMod_FileLoader.cpp | 126 +++++++++++++++++++++++++++++++++++-- 1 file changed, 121 insertions(+), 5 deletions(-) diff --git a/source/gMod_FileLoader.cpp b/source/gMod_FileLoader.cpp index 52595f0..2c44d35 100644 --- a/source/gMod_FileLoader.cpp +++ b/source/gMod_FileLoader.cpp @@ -38,7 +38,7 @@ std::vector gMod_FileLoader::GetTpfContents() auto zipArchive = libzippp::ZipArchive::fromBuffer(buffer.data(), buffer.size(), false, password); zipArchive->setErrorHandlerCallback([](const std::string& message, const std::string& strerror, int zip_error_code, int system_error_code) -> void { Message("GetTpfContents: %s %s %d %d\n", message.c_str(), strerror.c_str(), zip_error_code, system_error_code); - }); + }); zipArchive->open(); LoadEntries(*zipArchive, entries); } @@ -65,14 +65,130 @@ std::vector gMod_FileLoader::GetFileContents() return entries; } -void gMod_FileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector& entries) -{ - // Iterate over the files in the zip archive +void ParseSimpleArchive(libzippp::ZipArchive& archive, std::vector& entries) { for (const auto& entry : archive.getEntries()) { if (entry.isFile()) { + //TODO: #6 - Implement regex search const auto dataPtr = entry.readAsBinary(); const auto size = entry.getSize(); - entries.push_back({entry.getName(), entry.getName(), 0, dataPtr, size}); // Assuming ZipEntry is a string + auto name = entry.getName(); + + // Remove the part before the last underscore (if any) + size_t firstIndex = name.find_last_of('_'); + while (firstIndex != std::string::npos) { + if (firstIndex >= entry.getName().length() - 1) { + name = entry.getName(); + } + else { + name = entry.getName().substr(firstIndex + 1); + } + + firstIndex = name.find_last_of('_'); + } + + // Remove the file extension (if any) + size_t lastIndex = name.find_last_of('.'); + if (lastIndex != std::string::npos) { + name = name.substr(0, lastIndex); + } + + uint32_t crcHash; + try { + crcHash = std::stoul(name, nullptr, 16); + } + catch (const std::invalid_argument& e) { + Message("Failed to parse %s as a hash", name.c_str()); + continue; + } + catch (const std::out_of_range& e) { + Message("Out of range while parsing %s as a hash", name.c_str()); + continue; + } + + entries.push_back({ name, entry.getName(), crcHash, dataPtr, size }); } } } + +void ParseTexmodArchive(std::vector& lines, libzippp::ZipArchive& archive, std::vector& entries) { + for (const auto& line : lines) { + std::istringstream iss(line); + std::string part; + std::vector splits; + + // Split the line by '|' + while (std::getline(iss, part, '|')) { + splits.push_back(part); + } + + if (splits.size() != 2) { + continue; + } + + std::string addrstr = splits[0]; + std::string path = splits[1]; + + // Remove unwanted characters from the beginning of the path + while (!path.empty() && (path[0] == '.' && (path[1] == '/' || path[1] == '\\')) || path[0] == '/' || path[0] == '\\') { + path.erase(0, 1); + } + + // Remove trailing newline and carriage return characters + size_t endpos = path.find_last_not_of("\r\n"); + if (endpos != std::string::npos) { + path.erase(endpos + 1); + } + else if (!path.empty()) { + path.clear(); + } + + const auto entry = archive.getEntry(path); + if (entry.isNull()) { + continue; + } + + if (!entry.isFile()) { + continue; + } + + const auto dataPtr = entry.readAsBinary(); + const auto size = entry.getSize(); + uint32_t crcHash; + try { + crcHash = std::stoul(addrstr, nullptr, 16); + } + catch (const std::invalid_argument& e) { + Message("Failed to parse %s as a hash", addrstr.c_str()); + continue; + } + catch (const std::out_of_range& e) { + Message("Out of range while parsing %s as a hash", addrstr.c_str()); + continue; + } + + entries.push_back({ addrstr, entry.getName(), crcHash, dataPtr, size }); + } +} + +void gMod_FileLoader::LoadEntries(libzippp::ZipArchive& archive, std::vector& entries) +{ + // Iterate over the files in the zip archive + auto maybeDefiniton = archive.getEntry("texmod.def"); + if (maybeDefiniton.isNull() || !maybeDefiniton.isFile()) { + ParseSimpleArchive(archive, entries); + } + else { + const auto def = maybeDefiniton.readAsText(); + std::istringstream iss(def); + std::vector lines; + std::string line; + + while (std::getline(iss, line)) { + lines.push_back(line); + } + + ParseTexmodArchive(lines, archive, entries); + } +} + +