Extra2D/Extra2D/src/asset/data_processor.cpp

450 lines
11 KiB
C++

#include "extra2d/asset/data_processor.h"
#include <algorithm>
#include <cstring>
#ifdef E2D_USE_ZSTD
#include <zstd.h>
#endif
#ifdef E2D_USE_LZ4
#include <lz4.h>
#endif
#ifdef E2D_USE_ZLIB
#include <zlib.h>
#endif
namespace extra2d {
// ---------------------------------------------------------------------------
// Decryptor 实现
// ---------------------------------------------------------------------------
Decryptor::Decryptor(const std::string& key, Type type)
: key_(key), type_(type) {
}
std::vector<u8> Decryptor::process(const std::vector<u8>& input) {
if (input.empty() || type_ == Type::None) {
return processNext(input);
}
std::vector<u8> result;
switch (type_) {
case Type::XOR:
result = decryptXOR(input);
break;
case Type::AES256:
result = decryptAES256(input);
break;
default:
result = input;
break;
}
return processNext(result);
}
std::vector<u8> Decryptor::decryptXOR(const std::vector<u8>& input) {
if (key_.empty()) {
return input;
}
std::vector<u8> result(input.size());
const size_t keyLen = key_.size();
for (size_t i = 0; i < input.size(); ++i) {
result[i] = input[i] ^ static_cast<u8>(key_[i % keyLen]);
}
return result;
}
std::vector<u8> Decryptor::decryptAES256(const std::vector<u8>& input) {
return decryptXOR(input);
}
// ---------------------------------------------------------------------------
// Decompressor 实现
// ---------------------------------------------------------------------------
Decompressor::Decompressor(Compression algo)
: algo_(algo) {
}
std::vector<u8> Decompressor::process(const std::vector<u8>& input) {
if (input.empty() || algo_ == Compression::None) {
return processNext(input);
}
std::vector<u8> result;
switch (algo_) {
case Compression::Zstd:
result = decompressZstd(input);
break;
case Compression::LZ4:
result = decompressLZ4(input);
break;
case Compression::Zlib:
result = decompressZlib(input);
break;
default:
result = input;
break;
}
return processNext(result);
}
std::vector<u8> Decompressor::decompressZstd(const std::vector<u8>& input) {
#ifdef E2D_USE_ZSTD
unsigned long long const decompressedSize = ZSTD_getFrameContentSize(input.data(), input.size());
if (decompressedSize == ZSTD_CONTENTSIZE_ERROR ||
decompressedSize == ZSTD_CONTENTSIZE_UNKNOWN) {
return {};
}
std::vector<u8> result(static_cast<size_t>(decompressedSize));
size_t const actualSize = ZSTD_decompress(
result.data(), result.size(),
input.data(), input.size()
);
if (ZSTD_isError(actualSize)) {
return {};
}
result.resize(actualSize);
return result;
#else
return input;
#endif
}
std::vector<u8> Decompressor::decompressLZ4(const std::vector<u8>& input) {
#ifdef E2D_USE_LZ4
if (input.size() < sizeof(u32)) {
return {};
}
u32 originalSize;
std::memcpy(&originalSize, input.data(), sizeof(u32));
std::vector<u8> result(originalSize);
int const decompressedSize = LZ4_decompress_safe(
reinterpret_cast<const char*>(input.data() + sizeof(u32)),
reinterpret_cast<char*>(result.data()),
static_cast<int>(input.size() - sizeof(u32)),
static_cast<int>(originalSize)
);
if (decompressedSize < 0) {
return {};
}
return result;
#else
return input;
#endif
}
std::vector<u8> Decompressor::decompressZlib(const std::vector<u8>& input) {
#ifdef E2D_USE_ZLIB
std::vector<u8> result;
result.reserve(input.size() * 4);
const size_t CHUNK = 16384;
u8 out[CHUNK];
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = static_cast<uInt>(input.size());
strm.next_in = const_cast<Bytef*>(input.data());
if (inflateInit(&strm) != Z_OK) {
return {};
}
int ret;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
inflateEnd(&strm);
return {};
}
result.insert(result.end(), out, out + CHUNK - strm.avail_out);
} while (strm.avail_out == 0);
inflateEnd(&strm);
return result;
#else
return input;
#endif
}
// ---------------------------------------------------------------------------
// Encryptor 实现
// ---------------------------------------------------------------------------
Encryptor::Encryptor(const std::string& key, Decryptor::Type type)
: key_(key), type_(type) {
}
std::vector<u8> Encryptor::process(const std::vector<u8>& input) {
if (input.empty() || type_ == Decryptor::Type::None) {
return processNext(input);
}
std::vector<u8> result;
switch (type_) {
case Decryptor::Type::XOR:
result = encryptXOR(input);
break;
case Decryptor::Type::AES256:
result = encryptAES256(input);
break;
default:
result = input;
break;
}
return processNext(result);
}
std::vector<u8> Encryptor::encryptXOR(const std::vector<u8>& input) {
if (key_.empty()) {
return input;
}
std::vector<u8> result(input.size());
const size_t keyLen = key_.size();
for (size_t i = 0; i < input.size(); ++i) {
result[i] = input[i] ^ static_cast<u8>(key_[i % keyLen]);
}
return result;
}
std::vector<u8> Encryptor::encryptAES256(const std::vector<u8>& input) {
return encryptXOR(input);
}
// ---------------------------------------------------------------------------
// Compressor 实现
// ---------------------------------------------------------------------------
Compressor::Compressor(Compression algo, int level)
: algo_(algo), level_(level) {
}
std::vector<u8> Compressor::process(const std::vector<u8>& input) {
if (input.empty() || algo_ == Compression::None) {
return processNext(input);
}
std::vector<u8> result;
switch (algo_) {
case Compression::Zstd:
result = compressZstd(input);
break;
case Compression::LZ4:
result = compressLZ4(input);
break;
case Compression::Zlib:
result = compressZlib(input);
break;
default:
result = input;
break;
}
return processNext(result);
}
std::vector<u8> Compressor::compressZstd(const std::vector<u8>& input) {
#ifdef E2D_USE_ZSTD
size_t const bound = ZSTD_compressBound(input.size());
std::vector<u8> result(bound);
size_t const compressedSize = ZSTD_compress(
result.data(), result.size(),
input.data(), input.size(),
level_
);
if (ZSTD_isError(compressedSize)) {
return {};
}
result.resize(compressedSize);
return result;
#else
return input;
#endif
}
std::vector<u8> Compressor::compressLZ4(const std::vector<u8>& input) {
#ifdef E2D_USE_LZ4
int const bound = LZ4_compressBound(static_cast<int>(input.size()));
std::vector<u8> result(sizeof(u32) + bound);
u32 originalSize = static_cast<u32>(input.size());
std::memcpy(result.data(), &originalSize, sizeof(u32));
int const compressedSize = LZ4_compress_default(
reinterpret_cast<const char*>(input.data()),
reinterpret_cast<char*>(result.data() + sizeof(u32)),
static_cast<int>(input.size()),
bound
);
if (compressedSize <= 0) {
return {};
}
result.resize(sizeof(u32) + compressedSize);
return result;
#else
return input;
#endif
}
std::vector<u8> Compressor::compressZlib(const std::vector<u8>& input) {
#ifdef E2D_USE_ZLIB
std::vector<u8> result;
result.reserve(input.size() / 2);
const size_t CHUNK = 16384;
u8 out[CHUNK];
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
if (deflateInit(&strm, level_) != Z_OK) {
return {};
}
strm.avail_in = static_cast<uInt>(input.size());
strm.next_in = const_cast<Bytef*>(input.data());
int ret;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, Z_FINISH);
if (ret == Z_STREAM_ERROR) {
deflateEnd(&strm);
return {};
}
result.insert(result.end(), out, out + CHUNK - strm.avail_out);
} while (strm.avail_out == 0);
deflateEnd(&strm);
return result;
#else
return input;
#endif
}
// ---------------------------------------------------------------------------
// DataPipe 实现
// ---------------------------------------------------------------------------
DataPipe& DataPipe::decrypt(const std::string& key, Decryptor::Type type) {
processors_.push_back(std::make_unique<Decryptor>(key, type));
return *this;
}
DataPipe& DataPipe::decompress(Compression algo) {
processors_.push_back(std::make_unique<Decompressor>(algo));
return *this;
}
DataPipe& DataPipe::encrypt(const std::string& key, Decryptor::Type type) {
processors_.push_back(std::make_unique<Encryptor>(key, type));
return *this;
}
DataPipe& DataPipe::compress(Compression algo, int level) {
processors_.push_back(std::make_unique<Compressor>(algo, level));
return *this;
}
DataPipe& DataPipe::add(Unique<DataProcessor> processor) {
processors_.push_back(std::move(processor));
return *this;
}
std::vector<u8> DataPipe::process(const std::vector<u8>& input) {
if (processors_.empty()) {
return input;
}
std::vector<u8> result = input;
for (auto& processor : processors_) {
result = processor->process(result);
}
return result;
}
void DataPipe::clear() {
processors_.clear();
}
// ---------------------------------------------------------------------------
// 工具函数实现
// ---------------------------------------------------------------------------
std::vector<u8> computeChecksum(const std::vector<u8>& data) {
std::vector<u8> result(32, 0);
u64 hash1 = 14695981039346656037ULL;
u64 hash2 = 14695981039346656037ULL;
for (size_t i = 0; i < data.size(); ++i) {
hash1 ^= static_cast<u64>(data[i]);
hash1 *= 1099511628211ULL;
hash2 ^= static_cast<u64>(data[i]) << ((i % 8) * 8);
hash2 *= 1099511628211ULL;
}
for (size_t i = 0; i < 8; ++i) {
result[i] = static_cast<u8>((hash1 >> (i * 8)) & 0xFF);
result[i + 8] = static_cast<u8>((hash2 >> (i * 8)) & 0xFF);
}
for (size_t i = 16; i < 32; ++i) {
result[i] = static_cast<u8>((hash1 ^ hash2) >> ((i - 16) * 8) & 0xFF);
}
return result;
}
bool verifyChecksum(const std::vector<u8>& data, const std::vector<u8>& checksum) {
if (checksum.size() != 32) {
return false;
}
auto computed = computeChecksum(data);
return std::equal(computed.begin(), computed.end(), checksum.begin());
}
}