From 07f25198da701b9ef6a0e1e60ef335c40fdbb47c Mon Sep 17 00:00:00 2001 From: yanczi Date: Sat, 1 Nov 2025 23:53:25 +0100 Subject: [PATCH 1/3] =?UTF-8?q?Przywr=C3=B3cono=20xxHash?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CreateCargo.cpp | 12 +----------- CreateCargo.h | 3 +-- DataStruct.h | 2 +- ExtractCargo.cpp | 14 ++------------ ExtractCargo.h | 8 ++------ license/crc/LICENSE_1_0.txt | 23 ----------------------- 6 files changed, 7 insertions(+), 55 deletions(-) delete mode 100644 license/crc/LICENSE_1_0.txt diff --git a/CreateCargo.cpp b/CreateCargo.cpp index 622f0c5..40cfbe6 100644 --- a/CreateCargo.cpp +++ b/CreateCargo.cpp @@ -224,7 +224,7 @@ std::vector CreateCargo::ComputingHeadFiles() f.close(); //Tworzenie hashu CRC - uint32_t crc = crc32(buffor); + uint64_t crc = XXH64(buffor.data(), buffor.size(), VERSION); //Kompresjia std::vector zip; @@ -331,16 +331,6 @@ uint64_t CreateCargo::fnv64(const std::string& data) return hash; } -//----------------------------------------------------------------------------- -// Wygenerój CRC32 HASH integralności -//----------------------------------------------------------------------------- -uint32_t CreateCargo::crc32(const std::vector& buffer) -{ - boost::crc_32_type crc; - crc.process_bytes(buffer.data(), buffer.size()); - return crc.checksum(); -} - //----------------------------------------------------------------------------- // Sprawdzanie czy plik znajduje się na liście //----------------------------------------------------------------------------- diff --git a/CreateCargo.h b/CreateCargo.h index ddf0967..3f020f4 100644 --- a/CreateCargo.h +++ b/CreateCargo.h @@ -30,11 +30,10 @@ #include #include #include -#include +#include #include "DataStruct.h" #include "Txtpp.h" -#include "xxhash.h" #include "CompressingManager.h" diff --git a/DataStruct.h b/DataStruct.h index c5c9556..2579c79 100644 --- a/DataStruct.h +++ b/DataStruct.h @@ -62,6 +62,6 @@ struct FilesTable uint64_t hashName; uint64_t offset; uint32_t size; - uint32_t crc; + uint64_t crc; uint8_t isZip; }; \ No newline at end of file diff --git a/ExtractCargo.cpp b/ExtractCargo.cpp index 6cdf136..bf5e028 100644 --- a/ExtractCargo.cpp +++ b/ExtractCargo.cpp @@ -114,9 +114,9 @@ bool ExtractCargo::CheckCargoFile() //----------------------------------------------------------------------------- // Sprawdzanie sumy kontrolnej //----------------------------------------------------------------------------- -bool ExtractCargo::HashValid(const std::vector& data, const uint32_t& crc) +bool ExtractCargo::HashValid(const std::vector& data, const uint64_t& crc) { - uint32_t actualCrc = crc32(data); + uint64_t actualCrc = XXH64(data.data(), data.size(), VERSION); if (actualCrc != crc) { @@ -126,16 +126,6 @@ bool ExtractCargo::HashValid(const std::vector& data, const uint32_t& crc) return true; } -//----------------------------------------------------------------------------- -// Wygenerój CRC32 HASH integralności -//----------------------------------------------------------------------------- -uint32_t ExtractCargo::crc32(const std::vector& buffer) -{ - boost::crc_32_type crc; - crc.process_bytes(buffer.data(), buffer.size()); - return crc.checksum(); -} - //----------------------------------------------------------------------------- // Pobieranie nagłówków plików //----------------------------------------------------------------------------- diff --git a/ExtractCargo.h b/ExtractCargo.h index 411d160..e7d89b3 100644 --- a/ExtractCargo.h +++ b/ExtractCargo.h @@ -28,10 +28,9 @@ #include #include #include -#include +#include #include "DataStruct.h" -#include "xxhash.h" #include "CompressingManager.h" class ExtractCargo { @@ -69,10 +68,7 @@ private: void LoadFilesTable(); // Sprawdzanie sumy kontrolnej - bool HashValid(const std::vector&, const uint32_t&); - - // CRC - uint32_t crc32(const std::vector&); + bool HashValid(const std::vector&, const uint64_t&); // Utwórz katalog void CreateDirections(std::filesystem::path); diff --git a/license/crc/LICENSE_1_0.txt b/license/crc/LICENSE_1_0.txt deleted file mode 100644 index 36b7cd9..0000000 --- a/license/crc/LICENSE_1_0.txt +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. From 3bf98ba47205c00e41b8c56b6fca5bbde77f8cc0 Mon Sep 17 00:00:00 2001 From: yanczi Date: Wed, 19 Nov 2025 22:01:25 +0100 Subject: [PATCH 2/3] =?UTF-8?q?Zcalanie=20r=C4=99czne.=20Jak=20git=20nie?= =?UTF-8?q?=20chce=20po=20dobroci=20to=20b=C4=99dzie=20si=C5=82=C4=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 16 +- CompressingManager.cpp => ChunkManager.cpp | 59 +++-- CompressingManager.h => ChunkManager.h | 23 +- CompressionManager.cpp | 95 ++++++++ CompressionManager.h | 29 +++ CreateCargo.cpp | 246 +++++++++------------ CreateCargo.h | 56 +++-- DataStruct.h | 25 ++- EncryptionManager.cpp | 181 +++++++++++++++ EncryptionManager.h | 47 ++++ ExtractCargo.cpp | 53 ++++- ExtractCargo.h | 11 +- README.md | 4 +- TimeStamp.h | 47 ++++ Txtpp.h | 174 --------------- ViewCargo.cpp | 35 ++- license/libsodium/LICENSE.txt | 19 ++ license/xxhash/LICENSE.txt | 26 +++ voidcmd.cpp | 55 +++-- voidcmd.vcxproj | 21 +- voidcmd.vcxproj.filters | 25 ++- xxhash.dll | Bin 0 -> 97280 bytes 22 files changed, 790 insertions(+), 457 deletions(-) rename CompressingManager.cpp => ChunkManager.cpp (66%) rename CompressingManager.h => ChunkManager.h (67%) create mode 100644 CompressionManager.cpp create mode 100644 CompressionManager.h create mode 100644 EncryptionManager.cpp create mode 100644 EncryptionManager.h create mode 100644 TimeStamp.h delete mode 100644 Txtpp.h create mode 100644 license/libsodium/LICENSE.txt create mode 100644 license/xxhash/LICENSE.txt create mode 100644 xxhash.dll diff --git a/.gitignore b/.gitignore index 92b3625..47fe4dc 100644 --- a/.gitignore +++ b/.gitignore @@ -367,4 +367,18 @@ test/ test2/ *.pak expak/ -x64/ \ No newline at end of file +x64/ +test.* +pest2.* +*.hh +*.key +test3/ +test4/ +test5/ +test6/ +test7/ +test8/ +test9/ +test10/ +testx/ +testv/ \ No newline at end of file diff --git a/CompressingManager.cpp b/ChunkManager.cpp similarity index 66% rename from CompressingManager.cpp rename to ChunkManager.cpp index 74d0b93..1579fb3 100644 --- a/CompressingManager.cpp +++ b/ChunkManager.cpp @@ -1,9 +1,10 @@ -#include "CompressingManager.h" +#include "ChunkManager.h" -CompressingManager::CompressingManager() +ChunkManager::ChunkManager(EncryptionManager& em) + :eman(em) { } -CompressingManager::~CompressingManager() +ChunkManager::~ChunkManager() { } //----------------------------------------------------------------------------- @@ -12,7 +13,7 @@ CompressingManager::~CompressingManager() // Dzielenie vectora na chunki dokładnie po 128KB // Kompresowanie chunków bez nagłówka //----------------------------------------------------------------------------- -std::vector CompressingManager::compress(const std::vector& raw) +std::vector ChunkManager::chunked(const std::vector& raw, const bool& compress, const bool& encrypt) { //std::vector blockSizes; @@ -34,25 +35,27 @@ std::vector CompressingManager::compress(const std::vector& raw) // Skopiuj fragment danych do chunka std::vector chunk(begin, end); - // Obliczanie rozmiaru skompresowanego bloku - int maxZipChunkSize = LZ4_compressBound(chunkSize); + std::vector outChunk; - // Buffor wyjściowy nadpisany skompresowanymi danymi - std::vector zipChunk(maxZipChunkSize); - - // Kompresja - int zipSize = LZ4_compress_default(chunk.data(), zipChunk.data(), chunkSize, maxZipChunkSize); - - // Zmiana rozmiaru do faktycznego rozmiaru po kompresji - zipChunk.resize(zipSize); + // Przetwórz chunki i przetwórz + if (compress) + { + // Zaszyfruj i skompresuj lub tylko skompresuj + outChunk = encrypt ? eman.encrypt(cman.compress(chunk)) : cman.compress(chunk); + } + else + { + // Zaszyfruj lub skopiuj + outChunk = encrypt ? eman.encrypt(chunk) : std::move(chunk); + } uint32_t chs = chunk.size(); - uint32_t zch = zipChunk.size(); + uint32_t zch = outChunk.size(); //addIntToVector(compressedBlocks, chs); lastChunkRawSize = chs; addIntToVector(compressedBlocks, zch); - compressedBlocks.insert(compressedBlocks.end(), zipChunk.begin(), zipChunk.end()); + compressedBlocks.insert(compressedBlocks.end(), outChunk.begin(), outChunk.end()); blockLen++; } @@ -60,7 +63,7 @@ std::vector CompressingManager::compress(const std::vector& raw) std::vector zip; // Wstaw liczbę o ilości bloków do vectora; // Przekonpwertuj usigned int32 na ciąg znkaów - //uint16_t blockLen = blockSizes .size(); + // uint16_t blockLen = blockSizes .size(); addIntToVector(zip, blockLen); addIntToVector(zip, maxBlockSize); addIntToVector(zip, lastChunkRawSize); @@ -76,7 +79,7 @@ std::vector CompressingManager::compress(const std::vector& raw) //----------------------------------------------------------------------------- // Dekompresja blokowa //----------------------------------------------------------------------------- -std::vector CompressingManager::decompress(const std::vector& zip) +std::vector ChunkManager::dechunked(const std::vector& zip, const bool& compress, const bool& encrypt) { size_t offset = 0; const uint16_t chunkLen = getIntFromVector(zip, offset); @@ -93,23 +96,15 @@ std::vector CompressingManager::decompress(const std::vector& zip) uint32_t chunkZipSize = getIntFromVector(zip, offset); // Pobierz blok chunka - std::vector zipChunk(chunkZipSize); - std::memcpy(zipChunk.data(), zip.data() + offset, chunkZipSize); + std::vector inChunk(chunkZipSize); + std::memcpy(inChunk.data(), zip.data() + offset, chunkZipSize); offset += chunkZipSize; + // Jeśli flaga encrypt jest aktywna najpierw zdeszyfruj blok + std::vector zipChunk = encrypt ? eman.decrypt(inChunk) : std::move(inChunk); + // Zdeklarój pusty chunk - std::vector chunk(chunkSize); - - // Dekompresja chunka - int sizeData = LZ4_decompress_safe(zipChunk.data(), chunk.data(), static_cast(chunkZipSize), static_cast(chunkSize)); - - if (sizeData < 0) - { - throw std::runtime_error("LZ4 Decompressing Error"); - } - - // Dostosowanie rozmiaru vectora po skompresowaniu - chunk.resize(sizeData); + std::vector chunk = compress ? cman.decompress(zipChunk, chunkSize) : std::move(zipChunk); // Scal chunki chunksString.insert(chunksString.end(), chunk.begin(), chunk.end()); diff --git a/CompressingManager.h b/ChunkManager.h similarity index 67% rename from CompressingManager.h rename to ChunkManager.h index e3fd839..f7f662e 100644 --- a/CompressingManager.h +++ b/ChunkManager.h @@ -3,33 +3,30 @@ #include #include #include -#include #include #include #include +#include "EncryptionManager.h" +#include "CompressionManager.h" + #define BLOCK_SIZE 131072 // 128KB -struct BlockSize -{ - uint32_t raw; - uint32_t zip; -}; - -class CompressingManager +class ChunkManager { public: - CompressingManager(); - ~CompressingManager(); + ChunkManager(EncryptionManager& em); + ~ChunkManager(); // Kompresja danych - std::vector compress(const std::vector&); + std::vector chunked(const std::vector&, const bool&, const bool&); // Dekompresja - std::vector decompress(const std::vector&); + std::vector dechunked(const std::vector&, const bool&, const bool&); private: - std::vector blockSizes; + EncryptionManager eman; + CompressionManager cman; // Przekonwertuj zmienną na ciąg na vector template diff --git a/CompressionManager.cpp b/CompressionManager.cpp new file mode 100644 index 0000000..56825a4 --- /dev/null +++ b/CompressionManager.cpp @@ -0,0 +1,95 @@ +#include "CompressionManager.h" + +CompressionManager::CompressionManager() + :cctx(ZSTD_createCCtx()) + ,dctx(ZSTD_createDCtx()) +{ + // Tu ustawienia pod kompresję + const int level = COMPRESSION_LEVEL; + + // Ustawienia frameless + size_t rc = 0; + + // Wyłącza ramkę i przestawia strumień na czyste bloki + rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_format, ZSTD_f_zstd1_magicless); + + // Wyłącza sumę kontrolną na poziomie ramki + rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 0); + + // Wyłącza zapisywanie „content size” w nagłówku ramki + rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, 0); + + // Wyłącza zapisywanie identyfikatora słownika + rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, 0); + + // Ustawia poziom kompresji + rc |= ZSTD_CCtx_setParameter(cctx, ZSTD_c_compressionLevel, level); + + if (ZSTD_isError(rc)) { + std::cerr << "ZSTD_CCtx_setParameter error" << std::endl; + ZSTD_freeCCtx(cctx); + } + + /*====Tutaj Dekompresja=============================================================*/ + + size_t r = 0; + + // Przestawia dekompresję na czyste bloki bez nagłówka + r |= ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, ZSTD_f_zstd1_magicless); + if (ZSTD_isError(r)) + { + std::cerr << "ZSTD_DCtx_setParameter error" << std::endl; + ZSTD_freeDCtx(dctx); + } +} + +CompressionManager::~CompressionManager() +{ + ZSTD_freeCCtx(cctx); + ZSTD_freeDCtx(dctx); +} + +//----------------------------------------------------------------------------- +// Kompresja ZSTD frameless +//----------------------------------------------------------------------------- +std::vector CompressionManager::compress(const std::vector& input) +{ + // Obsługa pustego chunku: zwracamy pusty wynik (0 bajtów). + if (input.empty()) return {}; + + const size_t srcSize = input.size(); + + // Szacowanie rozmiaru skompresowanego vectoru + const size_t maxDst = ZSTD_compressBound(srcSize); + + std::vector out(maxDst); + + // Faktyczna kompresja + size_t written = ZSTD_compress2(cctx, out.data(), maxDst, + input.data(), srcSize); + + if (ZSTD_isError(written)) { + std::cerr << "ZSTD_compress error: " << ZSTD_getErrorName(written) << std::endl; + return {}; + } + + out.resize(written); + return out; +} + +//----------------------------------------------------------------------------- +// Dekompresja ZSTD +//----------------------------------------------------------------------------- +std::vector CompressionManager::decompress(const std::vector& input, const size_t& expected) +{ + std::vector output(expected); + + size_t dsize = ZSTD_decompressDCtx(dctx, output.data(), expected, input.data(), input.size()); + + if (ZSTD_isError(dsize)) { + std::cerr << "ZSTD_decompressDCtx error: " << ZSTD_getErrorName(dsize) << "\n"; + return {}; + } + + return output; +} \ No newline at end of file diff --git a/CompressionManager.h b/CompressionManager.h new file mode 100644 index 0000000..e49956a --- /dev/null +++ b/CompressionManager.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include +#define ZSTD_STATIC_LINKING_ONLY +#include + +#if ZSTD_VERSION_NUMBER < 10400 +#error "Wymagane zstd >= 1.4.0 dla ZSTD_c_format / ZSTD_f_zstd1_magicless" +#endif + +#define COMPRESSION_LEVEL 3 + +class CompressionManager +{ +public: + CompressionManager(); + ~CompressionManager(); + + std::vector compress(const std::vector&); + std::vector decompress(const std::vector&, const size_t&); + +private: + ZSTD_CCtx* cctx; + ZSTD_DCtx* dctx; +}; + diff --git a/CreateCargo.cpp b/CreateCargo.cpp index 40cfbe6..845a915 100644 --- a/CreateCargo.cpp +++ b/CreateCargo.cpp @@ -20,12 +20,12 @@ #include "CreateCargo.h" CreateCargo::CreateCargo() - :compressingFlag(false) - , filteringFlag(false) - , signature(SIGNATURE) + : signature(SIGNATURE) , extension(EXTENSION) , version(VERSION) + , methodFlags(0) , offset(0) + , hppKey(false) { // TODO Auto-generated constructor stub } @@ -38,12 +38,11 @@ CreateCargo::~CreateCargo() { //----------------------------------------------------------------------------- // Punk wejścia do tworzenia archivum //----------------------------------------------------------------------------- -bool CreateCargo::Create(const std::string& path, bool compress, bool filters) +bool CreateCargo::Create(const std::string& path, const int16_t& flag) { cargoFile = path + "." + extension; catalogPath = path; - compressingFlag = compress; - filteringFlag = filters; + methodFlags = flag; //Sprawdzanie pakowanego kontentu if (!std::filesystem::is_directory(path)) @@ -59,9 +58,9 @@ bool CreateCargo::Create(const std::string& path, bool compress, bool filters) } // Pobieranie listy plików wyjątków - if (filters) + if (flag == -1) { - std::string filterFile = path + ".txt"; + std::string filterFile = path + ".json"; if (!std::filesystem::exists(filterFile)) { std::cerr << "Error: Missing " << filterFile << " file!" << std::endl; @@ -88,6 +87,12 @@ bool CreateCargo::Create(const std::string& path, bool compress, bool filters) return false; } + // Zapisywanie klucza szyfrującego + if (flag == 2 || flag == 3 || encList.size() > 0) + { + crypt.saveKey(catalogPath, hppKey); + } + return true; } @@ -105,14 +110,35 @@ bool CreateCargo::GetFileList(const std::string& path) } else { - if (CheckIgnorePath(tmpPath)) + std::string fileRef = RemoveStartPath(PathToUnixLike(tmpPath)); + PathConf pc; + if (methodFlags > -1) { - filesList.push_back(PathToUnixLike(tmpPath)); + pc.path = PathToUnixLike(tmpPath); + pc.parameter = methodFlags; + filesPaths.push_back(pc); + } + else + { + if (!FindOnTheList(ignoreList, fileRef) || !CheckFileExtension(fileRef, ignoreList)) + { + if (FindOnTheList(zipList, fileRef) || CheckFileExtension(fileRef, zipList)) + { + pc.parameter = FindOnTheList(encList, fileRef) || CheckFileExtension(fileRef, encList) ? 3 : 1; + } + else + { + pc.parameter = FindOnTheList(encList, fileRef) || CheckFileExtension(fileRef, encList) ? 2 : 0; + } + pc.path = PathToUnixLike(tmpPath); + std::cout << pc.path << " - " << pc.parameter << std::endl; + filesPaths.push_back(pc); + } } } } - return filesList.size() > 0 ? true : false; + return filesPaths.size() > 0 ? true : false; } //----------------------------------------------------------------------------- @@ -160,35 +186,34 @@ CargoHead CreateCargo::CreateCargoHead(const uint32_t& filesLen, const uint64_t& //----------------------------------------------------------------------------- // Sprawdza czy plik znajduje się na liście //----------------------------------------------------------------------------- -uint8_t CreateCargo::CheckFileOnTheList(const std::string& path, std::vector& input, std::vector& output) +void CreateCargo::computingBytes(const int16_t& flag, std::vector& input, std::vector& output) { //Flaga aktywna sprawdza czy plik jest na liście. Jeśli jest to zwraca surowedane //Przeciwnie kompresuje dane - CompressingManager cm; + ChunkManager cm(crypt); - if (filteringFlag) { - if (FilteringData(path)) - { - output = cm.compress(input); - return ZIP_FILE; - } - else - { - output = std::move(input); - return RAW_FILE; - } - } - - //Flaga aktywna kompresuje dane - if (compressingFlag) + switch (flag) { + case 1: + output = cm.chunked(input, true, false); + break; - output = cm.compress(input); - return ZIP_FILE; + case 2: + output = cm.chunked(input, false, true); + break; + + case 3: + output = cm.chunked(input, true, true); + break; + + case 4: + output = cm.chunked(input, false, false); + break; + + default: + output = std::move(input); + break; } - - output = std::move(input); - return RAW_FILE; } //----------------------------------------------------------------------------- @@ -200,7 +225,7 @@ std::vector CreateCargo::ComputingHeadFiles() CargoHead cargoHead = CreateCargoHead(0, 0); offset += cargoHead.signature.length() + sizeof(cargoHead.version) + sizeof(cargoHead.files) + sizeof(cargoHead.table); - //Zapisanie TMP nagłowka do pliku + //Zapisanie tymczasowego nagłowka jako rezerwacja miejsca cargo.write(cargoHead.signature.data(), cargoHead.signature.length()); cargo.write(reinterpret_cast(&cargoHead.version), sizeof(cargoHead.version)); cargo.write(reinterpret_cast(&cargoHead.files), sizeof(cargoHead.files)); @@ -208,41 +233,41 @@ std::vector CreateCargo::ComputingHeadFiles() std::vector filesTable; - //Tworzenie nagłówków plików - for (const auto& file : filesList) + //Tworzenie nagłówków plików jednocześnie zapisywanie plików + for (const auto& file : filesPaths) { - std::string path = PathToUnixLike(RemoveStartPath(file)); - std::ifstream f(file, std::ios::binary | std::ios::ate); + std::string path = PathToUnixLike(RemoveStartPath(file.path)); + std::ifstream f(file.path, std::ios::binary | std::ios::ate); //Obliczanie rozmiaru pliku size_t size = f.tellg(); f.seekg(0, std::ios::beg); //Wczytanie pliku do pamięci - std::vector buffor(size); - f.read(buffor.data(), size); + std::vector buffer(size); + f.read(buffer.data(), size); f.close(); //Tworzenie hashu CRC - uint64_t crc = XXH64(buffor.data(), buffor.size(), VERSION); + const uint64_t crc = XXH64(buffer.data(), buffer.size(), VERSION); //Kompresjia - std::vector zip; - uint8_t method = CheckFileOnTheList(path, buffor, zip); + std::vector pakBuffer; + computingBytes(file.parameter, buffer, pakBuffer); FilesTable ft; ft.nameFile = path; ft.nameLen = path.length(); ft.hashName = fnv64(path); ft.offset = offset; - ft.size = zip.size(); - ft.isZip = method; + ft.size = pakBuffer.size(); + ft.flag = file.parameter; ft.crc = crc; - cargo.write(reinterpret_cast(zip.data()), zip.size()); + cargo.write(reinterpret_cast(pakBuffer.data()), pakBuffer.size()); filesTable.push_back(ft); - offset += zip.size(); + offset += pakBuffer.size(); } return filesTable; } @@ -254,18 +279,32 @@ void CreateCargo::GetFilters(const std::string& filterFile) { std::cout << "Downloading the exception list" << std::endl; - Txtpp ff(filterFile); + std::ifstream file(filterFile); + nlohmann::json jslist; + file >> jslist; + file.close(); // Lista plików do skompresowania - zipList = ff.Get(KEY_ZIP); + if (jslist.contains(KEY_ZIP)) + { + zipList = jslist[KEY_ZIP].get>(); + } + + // Lista plików do zaszyfrowania + if (jslist.contains(KEY_ENCRYPT)) + { + encList = jslist[KEY_ENCRYPT].get>(); + } // Lista plików do pominięcia - ignoreList = ff.Get(KEY_IGNORE); + if (jslist.contains(KEY_IGNORE)) + { + ignoreList = jslist[KEY_IGNORE].get>(); + } - ff.Close(); + hppKey = jslist.value("keyhpp", false); } - //----------------------------------------------------------------------------- // Znajdź wskazany element na liście //----------------------------------------------------------------------------- @@ -275,33 +314,23 @@ bool CreateCargo::FindOnTheList(const std::vector& list, const std: return it == list.end() ? false : true; } -//----------------------------------------------------------------------------- -// Rozdzielanie paternu od ścieżki -//----------------------------------------------------------------------------- -void CreateCargo::ExtPatternAndPathDetection(const std::vector& data, std::vector& pattern, std::vector& path) -{ - for (const auto& d : data) - { - if (d.front() == '*') - { - std::string tmpPattern = d; - tmpPattern.erase(tmpPattern.begin()); - pattern.push_back(UpperString(tmpPattern)); - } - else - { - path.push_back(d); - } - } -} - //----------------------------------------------------------------------------- // Sprawdzanie rozszeżeń plików //----------------------------------------------------------------------------- -bool CreateCargo::CheckFileExtension(const std::filesystem::path& p, const std::vector& patterns) { - std::string ext = UpperString(p.extension().string()); +bool CreateCargo::CheckFileExtension(const std::string& p, const std::vector& patterns) { + std::filesystem::path _p = p; + std::string ext = "*" + UpperString(_p.extension().string()); - return FindOnTheList(patterns, ext); + for (const auto& e : patterns) + { + std::string element = UpperString(e); + if (element == ext) + { + return true; + } + } + + return false; } //----------------------------------------------------------------------------- @@ -331,69 +360,6 @@ uint64_t CreateCargo::fnv64(const std::string& data) return hash; } -//----------------------------------------------------------------------------- -// Sprawdzanie czy plik znajduje się na liście -//----------------------------------------------------------------------------- -bool CreateCargo::FilteringData(const std::string& path) -{ - std::vector cmPatterns; - std::vector cmPaths; - - // Rozdziel ścieżki i patterny na osobne listy - ExtPatternAndPathDetection(zipList, cmPatterns, cmPaths); - - if (FindOnTheList(cmPatterns, ALL_FILE)) - { - return true; - } - - // Sprawdż czy istnieje plik o danym rozszeżeniu - if (CheckFileExtension(path, cmPatterns)) - { - return true; - } - - // Sprawdź czy instnieje dany plik w danej lokalizacji - if (FindOnTheList(cmPaths, path)) - { - return true; - } - - return false; -} - -//----------------------------------------------------------------------------- -// Kasowanie z listy plików ignorow -//----------------------------------------------------------------------------- -bool CreateCargo::CheckIgnorePath(const std::string& path) -{ - std::vector igPatterns; - std::vector igPaths; - - ExtPatternAndPathDetection(ignoreList, igPatterns, igPaths); - - // Sprawdż czy istnieje plik o danym rozszeżeniu - if (CheckFileExtension(path, igPatterns)) - { - return false; - } - - // Obrubka ścierzki - // Usuwanie katalogu root - std::string cleanPath = RemoveStartPath(path); - - // Przekształcenie ścierzki na format unixowy - std::string unixPath = PathToUnixLike(cleanPath); - - // Sprawdź czy instnieje dany plik w danej lokalizacji - if (FindOnTheList(igPaths, unixPath)) - { - return false; - } - - return true; -} - //----------------------------------------------------------------------------- // Trworzenie archiwum //----------------------------------------------------------------------------- @@ -401,7 +367,7 @@ bool CreateCargo::WriteCargo() { std::cout << "Packing files..." << std::endl; - uint32_t filesLen = filesList.size(); + uint32_t filesLen = filesPaths.size(); //Przygotowanie nagłówków plików i przetworzenie danych std::vector filesHead = ComputingHeadFiles(); @@ -424,7 +390,7 @@ bool CreateCargo::WriteCargo() cargo.write(reinterpret_cast(&head.offset), sizeof(head.offset)); cargo.write(reinterpret_cast(&head.size), sizeof(head.size)); cargo.write(reinterpret_cast(&head.crc), sizeof(head.crc)); - cargo.write(reinterpret_cast(&head.isZip), sizeof(head.isZip)); + cargo.write(reinterpret_cast(&head.flag), sizeof(head.flag)); } //Cofnij się na początek pliku diff --git a/CreateCargo.h b/CreateCargo.h index 3f020f4..e11d253 100644 --- a/CreateCargo.h +++ b/CreateCargo.h @@ -25,29 +25,30 @@ #include #include #include -#include #include #include #include #include #include +#include #include "DataStruct.h" -#include "Txtpp.h" -#include "CompressingManager.h" +#include "ChunkManager.h" +#include "EncryptionManager.h" +#define KEY_ZIP "compress" // Pliki do skompresowania +#define KEY_RAW "raw" // Pliki które mają pozostać w oryginalnej formie +#define KEY_IGNORE "ignore" // Pliki pominięte przy pakowaniu +#define KEY_ENCRYPT "encrypt" // Plili które mają być zaszyfrowane +#define ALL_FILE ".*" // Wszystkie pliki -#define COMPRESSION_LEVEL 12 // Poziom kompresji plików (3 < 12) - -#define KEY_ZIP "COMPRESS" // Pliki do skompresowania -#define KEY_RAW "RAW" // Pliki które mają pozostać w oryginalnej formie -#define KEY_IGNORE "IGNORE" // Pliki pominięte przy pakowaniu -#define KEY_CRYPT "CRYPT" // Plili które mają być zaszyfrowane - -#define ALL_FILE ".*" // Wszystkie pliki - +struct PathConf +{ + std::string path; + int16_t parameter; +}; class CreateCargo { public: @@ -55,14 +56,14 @@ public: virtual ~CreateCargo(); // Punk wejścia do tworzenia archivum - bool Create(const std::string&, bool, bool); + bool Create(const std::string&, const int16_t&); private: - bool compressingFlag; - bool filteringFlag; const std::string signature; const std::string extension; - const uint8_t version; + const short version; + + short methodFlags; std::string catalogPath; @@ -71,11 +72,16 @@ private: std::vector filesList; - + EncryptionManager crypt; + bool hppKey; // listy wyjątków std::vector ignoreList; std::vector zipList; + std::vector encList; + + // Główna lista plików z parametrami + std::vector filesPaths; std::ofstream cargo; @@ -101,20 +107,14 @@ private: // Przygotowanie nagłówków i plików std::vector ComputingHeadFiles(); - // Sprawdzanie czy plik znajduje się na liście - bool FilteringData(const std::string&); - // Wczytanie filtrów wyjątków void GetFilters(const std::string&); // Sprawdza czy plik znajduje się na liście - uint8_t CheckFileOnTheList(const std::string&, std::vector&, std::vector&); - - // Kasowanie z listy plików ignorow - bool CheckIgnorePath(const std::string&); + void computingBytes(const int16_t&, std::vector&, std::vector&); // Sprawdzanie rozszeżeń plików - bool CheckFileExtension(const std::filesystem::path&, const std::vector&); + bool CheckFileExtension(const std::string&, const std::vector&); // Zamień cały ciąg na duże litery std::string UpperString(std::string); @@ -122,12 +122,6 @@ private: // Wygenerój FNV-1a HASH uint64_t fnv64(const std::string& data); - // CRC - uint32_t crc32(const std::vector&); - - // Rozdzielanie paternu od ścieżki - void ExtPatternAndPathDetection(const std::vector&, std::vector&, std::vector&); - // Znajdź wskazany element na liście bool FindOnTheList(const std::vector&, const std::string&); }; diff --git a/DataStruct.h b/DataStruct.h index 2579c79..d941faf 100644 --- a/DataStruct.h +++ b/DataStruct.h @@ -21,20 +21,29 @@ #include #include -#include - #define EXTENSION "pak" #define SIGNATURE "XPAK" -#define VERSION 100 +#define SIGNATURE_KEY_FILE 1497713496 // XKEY + +#define VERSION 300 + +enum StoreMethod +{ + FILTERING = -1, + RAW = 0, + COMPRESS = 1, + ENCRYPT = 2, + COMPRESSxENCRYPT = 3 +}; //Prgoram title #define PROGRAM_TITLE "eXtendet PAK" -#define PROGRAM_VERSION "v1.1" +#define PROGRAM_VERSION "v1.3" #define PROGRAM_AUTHOR "Yanczi" -#define PROGRAM_COMPILING "24 October 2025" +#define PROGRAM_COMPILING "16 November 2025" #define PROGRAM_LICENSE "GNU LGPL v3" //Limity @@ -50,18 +59,18 @@ struct CargoHead { std::string signature; - uint16_t version; + int16_t version; uint32_t files; uint64_t table; }; struct FilesTable { - uint8_t nameLen; + int16_t nameLen; std::string nameFile; uint64_t hashName; uint64_t offset; uint32_t size; uint64_t crc; - uint8_t isZip; + int16_t flag; }; \ No newline at end of file diff --git a/EncryptionManager.cpp b/EncryptionManager.cpp new file mode 100644 index 0000000..aa49bd8 --- /dev/null +++ b/EncryptionManager.cpp @@ -0,0 +1,181 @@ +#include "EncryptionManager.h" + +EncryptionManager::EncryptionManager() + :keyReady(false) +{ + if (sodium_init() < 0) { + throw std::runtime_error("libsodium init failed"); + } + + keyReady = false; + generateKeys(); +} + +std::vector EncryptionManager::encrypt(const std::vector& raw) +{ + std::array nonce_local; + randombytes_buf(nonce_local.data(), nonce_local.size()); + + std::vector tmp(raw.size()); + if (crypto_stream_chacha20_ietf_xor_ic( + reinterpret_cast(tmp.data()), + reinterpret_cast(raw.data()), + static_cast(raw.size()), + nonce_local.data(), 0, key.data()) != 0) + { + throw std::runtime_error("crypto_stream_chacha20_ietf_xor_ic failed"); + } + + std::vector output; + output.insert(output.end(), + reinterpret_cast(nonce_local.data()), + reinterpret_cast(nonce_local.data()) + nonce_local.size()); + + output.insert(output.end(), tmp.begin(), tmp.end()); + + return output; +} + +void EncryptionManager::generateKeys() +{ + if (keyReady) return; + + //randombytes_buf(key.data(), key.size()); + crypto_stream_chacha20_ietf_keygen(key.data()); + + keyReady = true; +} + +void EncryptionManager::saveKey(const std::string& path, bool hpp) +{ + const int sig = SIGNATURE_KEY_FILE; + const short ver = VERSION; + + // Wygeneruj time stamp + std::time_t now = std::time(nullptr); + const int time = static_cast(now); + + // Wygeneruj crc kluczy + std::vector keyVec(reinterpret_cast(key.data()), + reinterpret_cast(key.data()) + key.size()); + + const uint64_t crcKey = XXH64(keyVec.data(), keyVec.size(), VERSION); + + // Zapisz ten śmietnik do pliku KEY + std::ofstream file(path + ".key", std::ios::binary); + if (!file) { std::cout << "Failed to save encryption key to file" << std::endl; } + + file.write(reinterpret_cast(&sig), sizeof(sig)); + file.write(reinterpret_cast(&ver), sizeof(ver)); + file.write(reinterpret_cast(&time), sizeof(time)); + file.write(reinterpret_cast(keyVec.data()), keyVec.size()); + file.write(reinterpret_cast(&crcKey), sizeof(crcKey)); + + file.close(); + + if (hpp) {saveCppHeadFile(path);} +} + +// Generowanie pliku nagłówkowego CPP z kluczem i nonce +void EncryptionManager::saveCppHeadFile(const std::string& path) +{ + const uint32_t keySize = crypto_stream_chacha20_ietf_KEYBYTES; + + std::ofstream file(path + ".hpp"); + + file << "// Plik wygenerowany przez " << PROGRAM_TITLE << " " << PROGRAM_VERSION << std::endl; + file << std::endl; + file << std::endl; + file << "#pragma once" << std::endl; + file << "#include " << std::endl; + file << "#include " << std::endl; + file << std::endl; + file << "namespace enc" << std::endl; + file << "{" << std::endl; + file << " // Klucz deszyfrujący" << std::endl; + file << " const std::array key{" << std::endl; + file << " " << toHex(key.data(), key.size()) << std::endl; + file << " };" << std::endl; + file << std::endl; + file << "} //namespace" << std::endl; + + file.close(); +} + +std::string EncryptionManager::toHex(const unsigned char* data, size_t len) +{ + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (size_t i = 0; i < len; ++i) { + oss << "0x" << std::setw(2) << static_cast(data[i]); + if (i + 1 != len) oss << ", "; + if ((i + 1) % 12 == 0 && i + 1 != len) oss << "\n "; + } + return oss.str(); +} + +// Wczytaj klucz +void EncryptionManager::loadKey(const std::string& path) +{ + std::ifstream file(path + ".key", std::ios::binary); + + int sig; + short ver; + int time; + + // Wczytaj + file.read(reinterpret_cast(&sig), sizeof(sig)); + file.read(reinterpret_cast(&ver), sizeof(ver)); + + // Sprawdź czy plik klucza jest poprawny + if (sig != SIGNATURE_KEY_FILE || ver != VERSION) + { + throw std::runtime_error("Invalid key file!"); + } + + std::vector keyVec(key.size()); + uint64_t crcKey; + + file.read(reinterpret_cast(&time), sizeof(time)); + file.read(keyVec.data(), keyVec.size()); + file.read(reinterpret_cast(&crcKey), sizeof(crcKey)); + + // Sprawdź integralność klucza + if (XXH64(keyVec.data(), keyVec.size(), VERSION) != crcKey) + { + throw std::runtime_error("Key integrity error!"); + } + + file.close(); + + // Przekonwertuj vector na array + key = toArray(keyVec); +} + +// Deszyfracja +std::vector EncryptionManager::decrypt(const std::vector& crypt) +{ + const size_t cryptoSize = crypto_stream_chacha20_ietf_NONCEBYTES; + + std::array nonce_local; + std::memcpy(nonce_local.data(), + reinterpret_cast(crypt.data()), cryptoSize); + + + const size_t rawSize = crypt.size() - cryptoSize; + std::vector tmp(rawSize); + std::memcpy(tmp.data(), crypt.data() + cryptoSize, rawSize); + + std::vector raw(rawSize); + + if (crypto_stream_chacha20_ietf_xor( + reinterpret_cast(raw.data()), + reinterpret_cast(tmp.data()), + static_cast(tmp.size()), + nonce_local.data(), key.data()) != 0) + { + throw std::runtime_error("Data decryption error!"); + } + + return raw; +} \ No newline at end of file diff --git a/EncryptionManager.h b/EncryptionManager.h new file mode 100644 index 0000000..61a03e4 --- /dev/null +++ b/EncryptionManager.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DataStruct.h" + +class EncryptionManager +{ +public: + EncryptionManager(); + ~EncryptionManager() = default; + + std::vector encrypt(const std::vector&); + std::vector decrypt(const std::vector&); + + void saveKey(const std::string&, bool); + void loadKey(const std::string&); + +private: + std::array key{}; + bool keyReady; + + void generateKeys(); + std::string toHex(const unsigned char*, size_t); + void saveCppHeadFile(const std::string&); + + template + std::array toArray(const std::vector& vec) { + if (vec.size() < N) { + throw std::runtime_error("Too small vector to convert to array"); + } + + std::array arr{}; + std::memcpy(arr.data(), vec.data(), N); + return arr; + } +}; \ No newline at end of file diff --git a/ExtractCargo.cpp b/ExtractCargo.cpp index bf5e028..4b3e0be 100644 --- a/ExtractCargo.cpp +++ b/ExtractCargo.cpp @@ -45,6 +45,8 @@ 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)) { @@ -59,6 +61,14 @@ bool ExtractCargo::Extract(const std::string& cFile) 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); @@ -79,7 +89,7 @@ bool ExtractCargo::Extract(const std::string& cFile) bool ExtractCargo::CheckCargoFile() { std::vector magic(signature.size()); - uint16_t cargoVer = 0; + short cargoVer = 0; if (!cargoFile.is_open()) { @@ -92,8 +102,6 @@ bool ExtractCargo::CheckCargoFile() cargoFile.read(reinterpret_cast(&filesLen), sizeof(filesLen)); cargoFile.read(reinterpret_cast(&tablePosition), sizeof(tablePosition)); - std::cout << std::string(magic.begin(), magic.end()) << std::endl; - if (std::string(magic.begin(), magic.end()) != signature) { std::cerr << "Error: Corrupted Cargo" << std::endl; @@ -126,13 +134,43 @@ bool ExtractCargo::HashValid(const std::vector& data, const uint64_t& crc) 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, true, false); + break; + + case 2: + output = cm.dechunked(input, false, true); + break; + + case 3: + output = cm.dechunked(input, true, true); + break; + + case 4: + output = cm.dechunked(input, false, 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; @@ -146,7 +184,7 @@ void ExtractCargo::LoadFilesTable() 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.isZip), sizeof(fhTmp.isZip)); + cargoFile.read(reinterpret_cast(&fhTmp.flag), sizeof(fhTmp.flag)); filesHeads.push_back(fhTmp); } @@ -157,8 +195,6 @@ void ExtractCargo::LoadFilesTable() //----------------------------------------------------------------------------- void ExtractCargo::ExtractingFilesFromCargo() { - CompressingManager cm; - for (const auto& fh : filesHeads) { std::filesystem::path dir = cargoFileName.stem() / fh.nameFile; @@ -170,7 +206,8 @@ void ExtractCargo::ExtractingFilesFromCargo() cargoFile.read(buffor.data(), fh.size); - std::vector rawBuffor = fh.isZip ? cm.decompress(buffor) : buffor; + std::vector rawBuffor; + computingBytes(buffor, rawBuffor, fh.flag); if (!HashValid(rawBuffor, fh.crc)) { diff --git a/ExtractCargo.h b/ExtractCargo.h index e7d89b3..0681494 100644 --- a/ExtractCargo.h +++ b/ExtractCargo.h @@ -31,7 +31,8 @@ #include #include "DataStruct.h" -#include "CompressingManager.h" +#include "ChunkManager.h" +#include "EncryptionManager.h" class ExtractCargo { public: @@ -46,9 +47,9 @@ private: uint32_t filesLen; uint64_t tablePosition; - uint8_t filesHeadsOffset; + int filesHeadsOffset; - const uint8_t version; + const short version; const std::string signature; std::vector filesHeads; @@ -56,6 +57,7 @@ private: std::ifstream cargoFile; + EncryptionManager eman; // Sprawdzenie poprawności archiwum @@ -73,4 +75,7 @@ private: // Utwórz katalog void CreateDirections(std::filesystem::path); + // Magiczna funkcja do dekompresji i deszyfracji danych + void computingBytes(const std::vector&, std::vector&, const int16_t&); + }; diff --git a/README.md b/README.md index 3d1d178..704bf0a 100644 --- a/README.md +++ b/README.md @@ -89,9 +89,11 @@ +**libsodium - https://github.com/jedisct1/libsodium** + **xxHash - https://github.com/Cyan4973/xxHash.git** -**LZ4 - https://github.com/lz4/lz4.git** +**Zstd - https://github.com/facebook/zstd.git** **FTXUI - https://github.com/ArthurSonzogni/FTXUI.git** diff --git a/TimeStamp.h b/TimeStamp.h new file mode 100644 index 0000000..b862f6e --- /dev/null +++ b/TimeStamp.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +class TimeStamp +{ +public: + TimeStamp() + :time(std::time(nullptr)) + {} + ~TimeStamp() = default; + + uint32_t get() + { +#if defined(_WIN32) localtime_s(<, &time); +#else localtime_r(<, &time); +#endif + + uint16_t d = dosDate(lt); + uint16_t t = dosTime(lt); + + uint32_t combined = ((uint32_t)d << 16) | t; + return combined; + } + +private: + std::time_t time; + std::tm lt{}; + + uint16_t dosDate(const std::tm& t) + { + int year = t.tm_year + 1900; + int y = (year >= 1980) ? (year - 1980) : 0; + int m = t.tm_mon + 1; + int d = t.tm_mday; + return static_cast((y << 9) | (m << 5) | d); + } + + uint16_t dosTime(const std::tm& t) + { + int h = t.tm_hour; + int min = t.tm_min; + int s2 = t.tm_sec / 2; + return static_cast((h << 11) | (min << 5) | s2); + } +}; \ No newline at end of file diff --git a/Txtpp.h b/Txtpp.h deleted file mode 100644 index 70940bb..0000000 --- a/Txtpp.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 . - */ - - - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -class Txtpp { -public: - Txtpp(const std::string& path = "") - { - if (path != "") - { - Load(path); - } - } - - ~Txtpp() - { - if (file.is_open()) - { - file.close(); - } - } - - bool Load(const std::string& path) - { - if (!std::filesystem::exists(path)) - { - return false; - } - - file.open(path); - - return file.is_open(); - } - - void Close() - { - file.close(); - } - - std::vector Get(const std::string& key) - { - std::vector tmp; - Parse(key, tmp); - return tmp; - } - - template - T getValue(const std::string& key, const std::string& val) - { - std::vector tmp; - Parse(key, tmp); - - for (const auto& line : tmp) - { - std::string cleanLine = RemoveSpaces(line); - std::string t; - std::string v; - - bool tv = false; - - for (const char& c : cleanLine) - { - if (c != ":") {tv = true;} - - if (!tv) { t += c; } - else { v += c; } - } - } - - return tmp; - } - -private: - const char sectionStart = '{'; - const char sectionEnd = '}'; - - std::ifstream file; - - //----------------------------------------------------------------------------- - // Wyszukiwanie danych po kluczu - //----------------------------------------------------------------------------- - void Parse(const std::string& key, std::vector& data) - { - std::string fullkey = sectionStart + key + sectionEnd; - std::string line; - bool wr = false; - - file.clear(); - file.seekg(std::ios::beg); - - while (getline(file, line)) - { - std::string tmp = RemoveSpaces(line); - if (tmp != "") - { - if (CheckKey(tmp)) - { - wr = UpperString(tmp) == fullkey ? true : false; - } - else - { - if (wr) { data.push_back(tmp); } - } - } - } - } - - //----------------------------------------------------------------------------- - // Usuwa spacje - //----------------------------------------------------------------------------- - std::string RemoveSpaces(std::string _line) - { - std::stringstream ss(_line); - char word; - std::string tmp; - std::string beforeWord = ""; - - while (ss >> word) - { - tmp += word; - } - - return tmp; - } - - //----------------------------------------------------------------------------- - // Sprawdza czy dany ciąg jest kluczem - //----------------------------------------------------------------------------- - bool CheckKey(std::string key) - { - if (key[0] == sectionStart && key[key.length() - 1]) - { - return true; - } - return false; - } - - //----------------------------------------------------------------------------- - // Zamień cały ciąg na duże litery - //----------------------------------------------------------------------------- - std::string UpperString(std::string s) { - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c) { return static_cast(std::toupper(c)); }); - return s; - } -}; - diff --git a/ViewCargo.cpp b/ViewCargo.cpp index 2a2860e..6eafe9c 100644 --- a/ViewCargo.cpp +++ b/ViewCargo.cpp @@ -58,7 +58,8 @@ bool ViewCargo::View(const std::string& path) //Table Header std::vector headElements; - headElements.push_back(ftxui::text(" Zip ") | ftxui::bold); + headElements.push_back(ftxui::text(" Compressed ") | ftxui::bold); + headElements.push_back(ftxui::text(" Encrypted ") | ftxui::bold); headElements.push_back(ftxui::text("Nazwa pliku") | ftxui::bold | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 56)); headElements.push_back(ftxui::text("Hash Name") | ftxui::bold | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 20)); @@ -80,7 +81,7 @@ bool ViewCargo::View(const std::string& path) bool ViewCargo::CheckCargoFile(const std::string& path) { std::vector magic(signature.length()); - uint16_t cargoVer = 0; + short cargoVer = 0; std::ifstream cargo(path, std::ios::binary); @@ -143,10 +144,10 @@ void ViewCargo::GetFileList(const std::string& path) cargo.read(reinterpret_cast(&fhTmp.offset), sizeof(fhTmp.offset)); cargo.read(reinterpret_cast(&fhTmp.size), sizeof(fhTmp.size)); cargo.read(reinterpret_cast(&fhTmp.crc), sizeof(fhTmp.crc)); - cargo.read(reinterpret_cast(&fhTmp.isZip), sizeof(fhTmp.isZip)); + cargo.read(reinterpret_cast(&fhTmp.flag), sizeof(fhTmp.flag)); //Tworzenie wierszy tabeli - CreateTableRow(fhTmp.nameFile, fhTmp.isZip, fhTmp.hashName); + CreateTableRow(fhTmp.nameFile, fhTmp.flag, fhTmp.hashName); } cargo.close(); @@ -164,19 +165,35 @@ void ViewCargo::CreateTableRow(const std::string& file, const uint8_t& zip, cons std::vector cell; ftxui::Element eZip; + ftxui::Element eEnc; - //Dodawanie check boxa czy plik jest spakowany czy nie - if (zip == 1) + // Ustawianie checkboxów + switch (zip) { + case 1: eZip = ftxui::text(" [x] ") | ftxui::color(ftxui::Color::Cyan); - } - else - { + eEnc = ftxui::text(" [ ] ") | ftxui::color(ftxui::Color::White); + break; + + case 2: eZip = ftxui::text(" [ ] ") | ftxui::color(ftxui::Color::White); + eEnc = ftxui::text(" [x] ") | ftxui::color(ftxui::Color::Cyan); + break; + + case 3: + eZip = ftxui::text(" [x] ") | ftxui::color(ftxui::Color::Cyan); + eEnc = ftxui::text(" [x] ") | ftxui::color(ftxui::Color::Cyan); + break; + + default: + eZip = ftxui::text(" [ ] ") | ftxui::color(ftxui::Color::White); + eEnc = ftxui::text(" [ ] ") | ftxui::color(ftxui::Color::White); + break; } //Dodawanie komurek cell.push_back(eZip); + cell.push_back(eEnc | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 7)); cell.push_back(ftxui::text(file) | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 56)); cell.push_back(ftxui::text(ss.str()) | ftxui::size(ftxui::WIDTH, ftxui::EQUAL, 20)); diff --git a/license/libsodium/LICENSE.txt b/license/libsodium/LICENSE.txt new file mode 100644 index 0000000..bb85d39 --- /dev/null +++ b/license/libsodium/LICENSE.txt @@ -0,0 +1,19 @@ +/* + * ISC License + * + * Copyright (c) 2013-2025 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + diff --git a/license/xxhash/LICENSE.txt b/license/xxhash/LICENSE.txt new file mode 100644 index 0000000..52b4c4e --- /dev/null +++ b/license/xxhash/LICENSE.txt @@ -0,0 +1,26 @@ +xxHash Library +Copyright (c) 2012-2021 Yann Collet +All rights reserved. + +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/voidcmd.cpp b/voidcmd.cpp index bd326ff..c719bae 100644 --- a/voidcmd.cpp +++ b/voidcmd.cpp @@ -40,34 +40,35 @@ void RenderHelp() const std::string HelpInstruction = "pakcmd \n" " \n" - " -c Pack and compress with LZ4 \n" - " -p Pack files from the specified directory \n" - " -e Pack and encrypted from the specified directory \n" - " -f Pack the files according to the guidelines given in the .txt \n" + " -c Compressing \n" + " -r Raw files \n" + " -e Encrypted \n" + " -s Compressing and Encrypted \n" + " -f Pack the files according to the guidelines given in the .json \n" " \n" "Extracting: \n" " -x Extract files from the specified container \n" + " \n" + "Others: \n" " -ls List files stored in a container \n" " \n" - " \n" - ".txt \n" + ".json \n" " \n" "Keys: \n" " \n" - " {compress} - Compressing files \n" - " {crypt} - Encrypted files with AES256 \n" + " {compress} - Compressing files \n" + " {crypt} - Encrypted files \n" " {ignore} - Ignoring concrete files \n" " \n" " /path/to/file.ext - Concrete file \n" " *.ext - All files with concrete extension \n" - " *.* - All files !NOT WORKING WITH {ignore} KEY! \n" - " \n"; + " *.* - All files !NOT WORKING WITH {ignore} KEY! \n"; - Interface tui; - tui.TextBorder(HelpTitle, HelpInstruction); + //Interface tui; + //tui.TextBorder(HelpTitle, HelpInstruction); } -bool EmptyPath(std::string path) +static bool EmptyPath(std::string path) { if (path == "") { @@ -109,17 +110,37 @@ int main(int argc, char* argv[]) { if (!EmptyPath(path)) { return 1; } - if (!cargo.Create(path, true, false)) + if (!cargo.Create(path, 1)) { return 1; } i++; } - if (arg == "-p" && i + 1 < argc) + if (arg == "-r" && i + 1 < argc) { path = argv[i + 1]; - if (!cargo.Create(path, false, false)) + if (!cargo.Create(path, 0)) + { + return 1; + } + i++; + } + + if (arg == "-e" && i + 1 < argc) + { + path = argv[i + 1]; + if (!cargo.Create(path, 2)) + { + return 1; + } + i++; + } + + if (arg == "-s" && i + 1 < argc) + { + path = argv[i + 1]; + if (!cargo.Create(path, 3)) { return 1; } @@ -130,7 +151,7 @@ int main(int argc, char* argv[]) { { path = argv[i + 1]; if (!EmptyPath(path)) { return 1; } - if (!cargo.Create(path, false, true)) + if (!cargo.Create(path, -1)) { return 1; } diff --git a/voidcmd.vcxproj b/voidcmd.vcxproj index 35415ae..cd5c1f3 100644 --- a/voidcmd.vcxproj +++ b/voidcmd.vcxproj @@ -104,13 +104,13 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 - 3rd\crc\include;3rd\ftxui\include;3rd\lz4\include + 3rd\ftxui\include;3rd\libsodium\include;3rd\json\include;3rd\zstd\include;3rd\xxhash\include;3rd\xxhash\include Console true - 3rd\ftxui\Debug;3rd\lz4\lib - liblz4_static.lib;ftxui-component.lib;ftxui-dom.lib;ftxui-screen.lib + 3rd\zstd\lib\Debug;3rd\ftxui\Debug;3rd\xxhash\lib\Debug;3rd\libsodium\lib\Debug + ftxui-component.lib;ftxui-dom.lib;ftxui-screen.lib;libsodium.lib;zstd_static.lib;xxhash.lib @@ -122,30 +122,33 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp17 - 3rd\crc\include;3rd\ftxui\include;3rd\lz4\include + 3rd\ftxui\include;3rd\libsodium\include;3rd\json\include;3rd\zstd\include;3rd\xxhash\include; Console true - 3rd\ftxui\Release;3rd\lz4\lib - liblz4_static.lib;ftxui-component.lib;ftxui-dom.lib;ftxui-screen.lib + 3rd\zstd\lib\Release;3rd\libsodium\lib\Release;3rd\xxhash\lib\Release;3rd\ftxui\Release + ftxui-component.lib;ftxui-dom.lib;ftxui-screen.lib;libsodium.lib;zstd_static.lib;xxhash.lib - + + + - + + + - diff --git a/voidcmd.vcxproj.filters b/voidcmd.vcxproj.filters index b2edffa..d4a64b3 100644 --- a/voidcmd.vcxproj.filters +++ b/voidcmd.vcxproj.filters @@ -27,13 +27,16 @@ Pliki ĹşrĂłdĹ‚owe - - Pliki ĹşrĂłdĹ‚owe - Pliki ĹşrĂłdĹ‚owe - + + Pliki ĹşrĂłdĹ‚owe + + + Pliki ĹşrĂłdĹ‚owe + + Pliki ĹşrĂłdĹ‚owe @@ -47,19 +50,19 @@ Pliki nagłówkowe - - Pliki nagłówkowe - Pliki nagłówkowe - - Pliki nagłówkowe - Pliki nagłówkowe - + + Pliki nagłówkowe + + + Pliki nagłówkowe + + Pliki nagłówkowe diff --git a/xxhash.dll b/xxhash.dll new file mode 100644 index 0000000000000000000000000000000000000000..4ee9ba00f85c6a1f2283ce7a91c3149bdf52c2ae GIT binary patch literal 97280 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 literal 0 HcmV?d00001 From c63417571a2fee021c653cf65fb601f17738be0b Mon Sep 17 00:00:00 2001 From: yanczi Date: Thu, 27 Nov 2025 15:48:04 +0100 Subject: [PATCH 3/3] Aktualizuj README.md --- README.md | 46 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 704bf0a..20f79de 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ **Visual Studio 2022** +**CMAKE** +--soon-- **=========================================================================================** @@ -34,7 +36,13 @@   \*\*-c - Packing catalog width compressing all files\*\* - \*\*-p - Packing catalog width out compressing\*\* + \*\*-r - Raw files\*\* + + \*\*-c - Compressing\*\* + + \*\*-e - Encrypted\*\* + + \*\*-s - Compressing and encrypted\*\* \*\*-f - Packing catalog width unique config for individual files (look on under section)\*\* @@ -47,42 +55,6 @@ -**-f Parameters instruction** - - - -**Create regular txt file in same directory on catalog width same name.** - - - -**This is a config file width parameters** - - - -**{COMPRESS} - key for compress files list** - - - -**{COMPRESS}** - -**textures/texture.png** - -**\*.png** - - - -**{IGNORE} - key for ignoring files list** - - - -**{IGNORE}** - -**testfile.odt** - -**\*.odt** - - - **=========================================================================================** ### **Components:**