/* * This file is part of VoidArchiveTool. * * Copyright (C) 2025 Yanczi * * Void Archive Toolis free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "ExtractCargo.h" ExtractCargo::ExtractCargo() :filesLen(0) , tablePosition(0) , filesHeadsOffset(0) , version(VERSION) , signature(SIGNATURE) { // TODO Auto-generated constructor stub } ExtractCargo::~ExtractCargo() { if (cargoFile.is_open()) { cargoFile.close(); } } //----------------------------------------------------------------------------- // Punkt wejścia //----------------------------------------------------------------------------- bool ExtractCargo::Extract(const std::string& cFile) { cargoFileName = cFile; std::cout << "START EXTRACT " << cFile << std::endl; //Sprawdź czy plik istnieje if (!std::filesystem::exists(cargoFileName)) { std::cerr << "Error: The given file is not exist!" << std::endl; return false; } //Sprawdź czy plik jets plikiem if (!std::filesystem::is_regular_file(cargoFileName)) { std::cerr << "Error: The given file is a directory!" << std::endl; return false; } // Wczytaj klucz deszyfrujący std::filesystem::path kdir = cargoFileName.stem(); if (std::filesystem::exists(kdir.string() + ".key")) { std::cout << "Decryption key detected" << std::endl; eman.loadKey(kdir.string()); } //Otwieranie kontenera cargoFile.open(cargoFileName, std::ios::binary); if (!CheckCargoFile()) { return false; } LoadFilesTable(); ExtractingFilesFromCargo(); return true; } //----------------------------------------------------------------------------- // Sprawdzenie poprawności archiwum //----------------------------------------------------------------------------- bool ExtractCargo::CheckCargoFile() { std::vector magic(signature.size()); short cargoVer = 0; if (!cargoFile.is_open()) { std::cerr << "Error: Failed to open container" << std::endl; return false; } cargoFile.read(magic.data(), magic.size()); cargoFile.read(reinterpret_cast(&cargoVer), sizeof(cargoVer)); cargoFile.read(reinterpret_cast(&filesLen), sizeof(filesLen)); cargoFile.read(reinterpret_cast(&tablePosition), sizeof(tablePosition)); if (std::string(magic.begin(), magic.end()) != signature) { std::cerr << "Error: Corrupted Cargo" << std::endl; return false; } if (cargoVer != version) { std::cerr << "Error: Wrong cargo version" << std::endl; return false; } filesHeadsOffset = signature.length() + sizeof(cargoVer) + sizeof(filesLen); return true; } //----------------------------------------------------------------------------- // Sprawdzanie sumy kontrolnej //----------------------------------------------------------------------------- bool ExtractCargo::HashValid(const std::vector& data, const uint64_t& crc) { uint64_t actualCrc = XXH64(data.data(), data.size(), VERSION); if (actualCrc != crc) { return false; } return true; } //----------------------------------------------------------------------------- // Magiczna funkcja do dekompresji i deszyfracji danych //----------------------------------------------------------------------------- void ExtractCargo::computingBytes(const std::vector& input, std::vector& output, const int16_t& flag) { ChunkManager cm(eman); switch (flag) { case 1: output = cm.dechunked(input, false); break; case 2: output = eman.decrypt(input); break; case 3: output = cm.dechunked(input, false); break; default: output = input; break; } } //----------------------------------------------------------------------------- // Pobieranie nagłówków plików //----------------------------------------------------------------------------- void ExtractCargo::LoadFilesTable() { cargoFile.seekg(tablePosition); for (uint32_t i = 0; i < filesLen; ++i) { FilesTable fhTmp; cargoFile.read(reinterpret_cast(&fhTmp.nameLen), sizeof(fhTmp.nameLen)); std::vector nameBuffor(fhTmp.nameLen); cargoFile.read(nameBuffor.data(), fhTmp.nameLen); fhTmp.nameFile = std::string(nameBuffor.begin(), nameBuffor.end()); cargoFile.read(reinterpret_cast(&fhTmp.hashName), sizeof(fhTmp.hashName)); cargoFile.read(reinterpret_cast(&fhTmp.offset), sizeof(fhTmp.offset)); cargoFile.read(reinterpret_cast(&fhTmp.size), sizeof(fhTmp.size)); cargoFile.read(reinterpret_cast(&fhTmp.crc), sizeof(fhTmp.crc)); cargoFile.read(reinterpret_cast(&fhTmp.flag), sizeof(fhTmp.flag)); filesHeads.push_back(fhTmp); } } //----------------------------------------------------------------------------- // Wypakowywanie plików //----------------------------------------------------------------------------- void ExtractCargo::ExtractingFilesFromCargo() { for (const auto& fh : filesHeads) { std::filesystem::path dir = cargoFileName.stem() / fh.nameFile; CreateDirections(dir); std::ofstream file(dir, std::ios::binary); cargoFile.seekg(fh.offset); std::vector buffor(fh.size); cargoFile.read(buffor.data(), fh.size); std::vector rawBuffor; computingBytes(buffor, rawBuffor, fh.flag); if (!HashValid(rawBuffor, fh.crc)) { std::cerr << fh.nameFile << " Error: Corrupted data integration CRC" << std::endl; } file.write(reinterpret_cast(rawBuffor.data()), rawBuffor.size()); file.close(); } std::cout << "Unpacking complete!" << std::endl; } //----------------------------------------------------------------------------- // Utwórz katalog //----------------------------------------------------------------------------- void ExtractCargo::CreateDirections(std::filesystem::path path) { if (!std::filesystem::exists(path.parent_path())) { std::filesystem::create_directories(path.parent_path()); } }