XNSim/XNServiceGenServer/XNCodeZip.cpp

216 lines
5.5 KiB
C++

#include "XNCodeZip.h"
#include <filesystem>
#include <fstream>
#include <zip.h>
#include <cstring>
#include <functional>
namespace fs = std::filesystem;
int XNCodeZip::Zip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg)
{
// 检查源路径是否存在
if (!fs::exists(srcPath)) {
errorMsg = "源路径不存在: " + srcPath;
return -1;
}
// 确保目标目录存在
fs::path dstDir = fs::path(dstPath).parent_path();
if (!fs::exists(dstDir)) {
fs::create_directories(dstDir);
}
// 打开zip文件
int err = 0;
zip_t *zip = zip_open(dstPath.c_str(), ZIP_CREATE | ZIP_TRUNCATE, &err);
if (zip == nullptr) {
char errstr[1024];
zip_error_to_str(errstr, sizeof(errstr), err, errno);
errorMsg = "无法创建zip文件: " + std::string(errstr);
return -1;
}
// 递归添加文件和目录
std::function<void(const fs::path &, const fs::path &)> addToZip =
[&](const fs::path &currentPath, const fs::path &relativePath) {
if (fs::is_directory(currentPath)) {
// 添加目录
std::string dirName = relativePath.string() + "/";
zip_dir_add(zip, dirName.c_str(), ZIP_FL_OVERWRITE);
// 递归处理子目录和文件
for (const auto &entry : fs::directory_iterator(currentPath)) {
fs::path newRelativePath = relativePath / entry.path().filename();
addToZip(entry.path(), newRelativePath);
}
} else if (fs::is_regular_file(currentPath)) {
// 添加文件
std::string fileName = relativePath.string();
zip_source_t *source = zip_source_file(zip, currentPath.c_str(), 0, 0);
if (source == nullptr) {
errorMsg = "无法创建zip源: " + fileName;
return;
}
if (zip_file_add(zip, fileName.c_str(), source, ZIP_FL_OVERWRITE) < 0) {
zip_source_free(source);
errorMsg = "无法添加文件到zip: " + fileName;
return;
}
}
};
// 开始压缩
fs::path srcDir(srcPath);
fs::path baseName = srcDir.filename();
addToZip(srcDir, baseName);
// 关闭zip文件
zip_close(zip);
return 0;
}
int XNCodeZip::Unzip(const std::string &srcPath, const std::string &dstPath, std::string &errorMsg)
{
// 检查源路径是否存在
if (!fs::exists(srcPath)) {
errorMsg = "源路径不存在: " + srcPath;
return -1;
}
// 确保目标目录存在
fs::path dstDir = fs::path(dstPath);
if (!fs::exists(dstDir)) {
fs::create_directories(dstDir);
}
// 打开zip文件
int err = 0;
zip_t *zip = zip_open(srcPath.c_str(), 0, &err);
if (zip == nullptr) {
char errstr[1024];
zip_error_to_str(errstr, sizeof(errstr), err, errno);
errorMsg = "无法打开zip文件: " + std::string(errstr);
return -1;
}
// 获取zip文件中的条目数量
zip_int64_t numEntries = zip_get_num_entries(zip, 0);
if (numEntries < 0) {
errorMsg = "无法获取zip文件条目数量";
zip_close(zip);
return -1;
}
// 检测根目录名称(去除额外层级)
std::string rootDirName;
bool hasRootDir = false;
// 检查第一个条目来确定根目录结构
if (numEntries > 0) {
struct zip_stat st;
if (zip_stat_index(zip, 0, 0, &st) >= 0) {
std::string firstEntry = st.name;
size_t slashPos = firstEntry.find('/');
if (slashPos != std::string::npos) {
rootDirName = firstEntry.substr(0, slashPos);
hasRootDir = true;
}
}
}
// 遍历并解压所有条目
for (zip_int64_t i = 0; i < numEntries; ++i) {
// 获取条目信息
struct zip_stat st;
if (zip_stat_index(zip, i, 0, &st) < 0) {
errorMsg = "无法获取zip条目信息";
zip_close(zip);
return -1;
}
// 跳过空条目
if (st.size == 0 && st.name[strlen(st.name) - 1] == '/') {
continue;
}
// 构建目标文件路径,去除根目录层级
std::string relativePath = st.name;
if (hasRootDir && relativePath.find(rootDirName + "/") == 0) {
relativePath = relativePath.substr(rootDirName.length() + 1);
}
// 如果去除根目录后路径为空,跳过
if (relativePath.empty()) {
continue;
}
fs::path targetPath = dstDir / relativePath;
// 如果是目录,创建目录
if (relativePath[relativePath.length() - 1] == '/') {
fs::create_directories(targetPath);
continue;
}
// 确保文件的父目录存在
fs::create_directories(targetPath.parent_path());
// 检查文件是否已存在
if (fs::exists(targetPath)) {
// 可以选择跳过、覆盖或询问用户
// 这里选择覆盖已有文件
fs::remove(targetPath);
}
// 打开zip条目
zip_file_t *zipFile = zip_fopen_index(zip, i, 0);
if (zipFile == nullptr) {
errorMsg = "无法打开zip条目: " + std::string(st.name);
zip_close(zip);
return -1;
}
// 创建目标文件
std::ofstream outFile(targetPath, std::ios::binary);
if (!outFile.is_open()) {
errorMsg = "无法创建目标文件: " + targetPath.string();
zip_fclose(zipFile);
zip_close(zip);
return -1;
}
// 读取并写入文件内容
char buffer[8192];
zip_int64_t bytesRead;
while ((bytesRead = zip_fread(zipFile, buffer, sizeof(buffer))) > 0) {
outFile.write(buffer, bytesRead);
if (!outFile.good()) {
errorMsg = "写入文件失败: " + targetPath.string();
outFile.close();
zip_fclose(zipFile);
zip_close(zip);
return -1;
}
}
// 检查读取是否成功
if (bytesRead < 0) {
errorMsg = "读取zip条目失败: " + std::string(st.name);
outFile.close();
zip_fclose(zipFile);
zip_close(zip);
return -1;
}
// 关闭文件
outFile.close();
zip_fclose(zipFile);
}
// 关闭zip文件
zip_close(zip);
return 0;
}