/* * 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) , xxhState(XXH64_createState()) , signature(SIGNATURE) { // TODO Auto-generated constructor stub XXH64_reset(xxhState, 0); } 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()); int8_t cargoVer = 0; if (!cargoFile.is_open()) { std::cerr << "Error: Failed to open container" << std::endl; return false; } cargoFile.read(magic.data(), magic.size()); if (std::string(magic.begin(), magic.end()) != signature) { std::cerr << "Error: Corrupted Cargo" << std::endl; return false; } // Pobierz pozycję tablicy plików i jej rozmiar cargoFile.read(reinterpret_cast(&tablePosition), sizeof(tablePosition)); cargoFile.read(reinterpret_cast(&filesLen), sizeof(filesLen)); return true; } //----------------------------------------------------------------------------- // 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.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::cout << dir.string() << std::endl; std::ofstream file(dir, std::ios::binary); cargoFile.seekg(fh.offset); XXH64_reset(xxhState, 0); // Strumień wyciągający if (fh.flag == flag::raw) { for (uint64_t sc = 0; sc < fh.size; sc += ds::chunk_stream) { const uint32_t streamChunk = std::min(ds::chunk_stream, static_cast(fh.size - sc)); std::vector buffer(streamChunk); cargoFile.read(buffer.data(), streamChunk); XXH64_update(xxhState, buffer.data(), buffer.size()); file.write(reinterpret_cast(buffer.data()), streamChunk); } } else { uint32_t chunkLen; uint32_t chunkBeforeSize; uint32_t chunkLastSize; cargoFile.read(reinterpret_cast(&chunkLen), sizeof(chunkLen)); cargoFile.read(reinterpret_cast(&chunkBeforeSize), sizeof(chunkBeforeSize)); cargoFile.read(reinterpret_cast(&chunkLastSize), sizeof(chunkLastSize)); std::vector chunksString; // Dekompresja bloków for (size_t i = 0; i < chunkLen; ++i) { // Pobierz rozmiar chunków przed i po skompresowaniem uint32_t chunkSize = i < chunkLen - 1 ? chunkBeforeSize : chunkLastSize; uint32_t chunkZipSize; cargoFile.read(reinterpret_cast(&chunkZipSize), sizeof(chunkZipSize)); // Pobierz blok chunka std::vector buffer(chunkZipSize); cargoFile.read(buffer.data(), chunkZipSize); std::vector rawBuffer(chunkSize); if ((fh.flag & flag::zip) == flag::zip) { rawBuffer = (fh.flag & flag::enc) == flag::enc ? cman.decompress(eman.decrypt(buffer), chunkSize) : cman.decompress(buffer, chunkSize); } else { rawBuffer = eman.decrypt(buffer); } XXH64_update(xxhState, rawBuffer.data(), rawBuffer.size()); file.write(reinterpret_cast(rawBuffer.data()), chunkSize); } } file.close(); if (XXH64_digest(xxhState) != fh.crc) { std::cerr << dir.string() << " Error: Corrupted data integration CRC" << std::endl; } } 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()); } }