new pack system
This commit is contained in:
11
src/PackLib/CMakeLists.txt
Normal file
11
src/PackLib/CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
file(GLOB_RECURSE FILE_SOURCES "*.h" "*.c" "*.cpp")
|
||||
|
||||
add_library(PackLib STATIC ${FILE_SOURCES})
|
||||
|
||||
target_link_libraries(PackLib
|
||||
libzstd_static
|
||||
cryptopp-static
|
||||
mio
|
||||
)
|
||||
|
||||
GroupSourcesByFolder(PackLib)
|
||||
71
src/PackLib/Pack.cpp
Normal file
71
src/PackLib/Pack.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "Pack.h"
|
||||
#include <zstd.h>
|
||||
|
||||
bool CPack::Open(const std::string& path, TPackFileMap& entries)
|
||||
{
|
||||
std::error_code ec;
|
||||
m_file.map(path, ec);
|
||||
|
||||
if (ec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t file_size = m_file.size();
|
||||
if (file_size < sizeof(TPackFileHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(&m_header, m_file.data(), sizeof(TPackFileHeader));
|
||||
m_decryption.SetKeyWithIV(PACK_KEY.data(), PACK_KEY.size(), m_header.iv, CryptoPP::Camellia::BLOCKSIZE);
|
||||
|
||||
if (file_size < sizeof(TPackFileHeader) + m_header.entry_num * sizeof(TPackFileEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_header.entry_num; i++) {
|
||||
TPackFileEntry entry;
|
||||
memcpy(&entry, m_file.data() + sizeof(TPackFileHeader) + i * sizeof(TPackFileEntry), sizeof(TPackFileEntry));
|
||||
m_decryption.ProcessData((CryptoPP::byte*)&entry, (CryptoPP::byte*)&entry, sizeof(TPackFileEntry));
|
||||
|
||||
entries[entry.file_name] = std::make_pair(shared_from_this(), entry);
|
||||
|
||||
if (file_size < m_header.data_begin + entry.offset + entry.compressed_size) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPack::GetFile(const TPackFileEntry& entry, TPackFile& result)
|
||||
{
|
||||
result.resize(entry.file_size);
|
||||
|
||||
size_t offset = m_header.data_begin + entry.offset;
|
||||
switch (entry.encryption)
|
||||
{
|
||||
case 0: {
|
||||
size_t decompressed_size = ZSTD_decompress(result.data(), result.size(), m_file.data() + offset, entry.compressed_size);
|
||||
if (decompressed_size != entry.file_size) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 1: {
|
||||
std::vector<uint8_t> compressed_data(entry.compressed_size);
|
||||
memcpy(compressed_data.data(), m_file.data() + offset, entry.compressed_size);
|
||||
|
||||
m_decryption.Resynchronize(entry.iv, sizeof(entry.iv));
|
||||
m_decryption.ProcessData(compressed_data.data(), compressed_data.data(), entry.compressed_size);
|
||||
|
||||
size_t decompressed_size = ZSTD_decompress(result.data(), result.size(), compressed_data.data(), compressed_data.size());
|
||||
if (decompressed_size != entry.file_size) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
21
src/PackLib/Pack.h
Normal file
21
src/PackLib/Pack.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <mio/mmap.hpp>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
class CPack : public std::enable_shared_from_this<CPack>
|
||||
{
|
||||
public:
|
||||
CPack() = default;
|
||||
~CPack() = default;
|
||||
|
||||
bool Open(const std::string& path, TPackFileMap& entries);
|
||||
bool GetFile(const TPackFileEntry& entry, TPackFile& result);
|
||||
|
||||
private:
|
||||
TPackFileHeader m_header;
|
||||
mio::mmap_source m_file;
|
||||
|
||||
CryptoPP::CTR_Mode<CryptoPP::Camellia>::Decryption m_decryption;
|
||||
};
|
||||
40
src/PackLib/PackManager.cpp
Normal file
40
src/PackLib/PackManager.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "PackManager.h"
|
||||
|
||||
bool CPackManager::AddPack(const std::string& path)
|
||||
{
|
||||
std::shared_ptr<CPack> pack = std::make_shared<CPack>();
|
||||
return pack->Open(path, m_entries);
|
||||
}
|
||||
|
||||
bool CPackManager::GetFile(std::string_view path, TPackFile& result)
|
||||
{
|
||||
thread_local std::string buf;
|
||||
NormalizePath(path, buf);
|
||||
|
||||
auto it = m_entries.find(buf);
|
||||
if (it != m_entries.end()) {
|
||||
return it->second.first->GetFile(it->second.second, result);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPackManager::IsExist(std::string_view path) const
|
||||
{
|
||||
thread_local std::string buf;
|
||||
NormalizePath(path, buf);
|
||||
|
||||
auto it = m_entries.find(buf);
|
||||
return it != m_entries.end();
|
||||
}
|
||||
|
||||
void CPackManager::NormalizePath(std::string_view in, std::string& out) const
|
||||
{
|
||||
out.resize(in.size());
|
||||
for (std::size_t i = 0; i < out.size(); ++i) {
|
||||
if (in[i] == '\\')
|
||||
out[i] = '/';
|
||||
else
|
||||
out[i] = static_cast<char>(std::tolower(in[i]));
|
||||
}
|
||||
}
|
||||
22
src/PackLib/PackManager.h
Normal file
22
src/PackLib/PackManager.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
|
||||
#include "EterBase/Singleton.h"
|
||||
#include "Pack.h"
|
||||
|
||||
class CPackManager : public CSingleton<CPackManager>
|
||||
{
|
||||
public:
|
||||
CPackManager() = default;
|
||||
virtual ~CPackManager() = default;
|
||||
|
||||
bool AddPack(const std::string& path);
|
||||
bool GetFile(std::string_view path, TPackFile& result);
|
||||
bool IsExist(std::string_view path) const;
|
||||
|
||||
private:
|
||||
void NormalizePath(std::string_view in, std::string& out) const;
|
||||
|
||||
private:
|
||||
TPackFileMap m_entries;
|
||||
};
|
||||
43
src/PackLib/config.h
Normal file
43
src/PackLib/config.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gcm.h>
|
||||
#include <modes.h>
|
||||
#include <osrng.h>
|
||||
#include <secblock.h>
|
||||
#include <camellia.h>
|
||||
|
||||
constexpr std::array<uint8_t, 32> PACK_KEY = {
|
||||
0x00,0x11,0x22,0x33, 0x44,0x55,0x66,0x77,
|
||||
0x88,0x99,0xAA,0xBB, 0xCC,0xDD,0xEE,0xFF,
|
||||
0x01,0x23,0x45,0x67, 0x89,0xAB,0xCD,0xEF,
|
||||
0xFE,0xDC,0xBA,0x98, 0x76,0x54,0x32,0x10
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct TPackFileHeader
|
||||
{
|
||||
uint64_t entry_num;
|
||||
uint64_t data_begin;
|
||||
uint8_t iv[CryptoPP::Camellia::BLOCKSIZE];
|
||||
};
|
||||
struct TPackFileEntry
|
||||
{
|
||||
char file_name[FILENAME_MAX+1];
|
||||
uint64_t offset;
|
||||
uint64_t file_size;
|
||||
uint64_t compressed_size;
|
||||
uint8_t encryption;
|
||||
uint8_t iv[CryptoPP::Camellia::BLOCKSIZE];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class CPack;
|
||||
using TPackFile = std::vector<uint8_t>;
|
||||
using TPackFileMapEntry = std::pair<std::shared_ptr<CPack>, TPackFileEntry>;
|
||||
using TPackFileMap = std::unordered_map<std::string, TPackFileMapEntry>;
|
||||
Reference in New Issue
Block a user