累计更新:
cos上传 补丁压缩
This commit is contained in:
Binary file not shown.
@@ -42,12 +42,14 @@ PRIVATE
|
||||
../libTinyEncrypt
|
||||
../lua/src
|
||||
../luatinker
|
||||
../zstd/lib
|
||||
)
|
||||
|
||||
target_link_directories(sgutil
|
||||
PRIVATE
|
||||
../cos-cpp-sdk/libs/x64
|
||||
../cos-cpp-sdk/third_party/lib/x64/poco
|
||||
../zstd/precompiled/x64
|
||||
)
|
||||
|
||||
target_link_libraries(sgutil
|
||||
@@ -58,10 +60,11 @@ PRIVATE
|
||||
libTinyEncrypt
|
||||
LuaTinker
|
||||
lua
|
||||
zstd_static.lib
|
||||
shlwapi.lib
|
||||
wininet.lib
|
||||
# cossdk.lib
|
||||
# PocoFoundation.lib
|
||||
cossdk.lib
|
||||
PocoFoundation.lib
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "sgu_stdafx.h"
|
||||
#include "sgu_download_cos.h"
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
bool downloadFileFromCOS(const char* cosFilePathName, const char* localFilePath)
|
||||
{
|
||||
return true;
|
||||
@@ -19,15 +19,21 @@ static void TestLogCallback(const std::string& log)
|
||||
//
|
||||
// https://console.cloud.tencent.com/cam/capi
|
||||
//
|
||||
const uint64_t gAppID = 1313389434ULL;
|
||||
const std::string gSecretId = "AKIDGMFKI2av3g6JPTKzRffS1NWR9eXDgwym";
|
||||
const std::string gSecretKey = "f7LMDtNdnlXDpEQRGxVqxrbBYjlcbP2U";
|
||||
const std::string gRegion = "ap-shanghai";
|
||||
const std::string gBucketName = "dnftest-1313389434";
|
||||
//const uint64_t gAppID = 1313389434ULL;
|
||||
//const std::string gSecretId = "AKIDGMFKI2av3g6JPTKzRffS1NWR9eXDgwym";
|
||||
//const std::string gSecretKey = "f7LMDtNdnlXDpEQRGxVqxrbBYjlcbP2U";
|
||||
//const std::string gRegion = "ap-shanghai";
|
||||
//const std::string gBucketName = "dnftest-1313389434";
|
||||
|
||||
|
||||
const std::string gSecretId = "AKIDfBzQo25vgJl170rV1LRNLExTp27GZhho";
|
||||
const std::string gSecretKey = "2qvqX0FKCrHkBQehYDe2JaggePA4nLir";
|
||||
const std::string gRegion = "ap-nanjing";
|
||||
const std::string gBucketName = "client-fwf-1258765125";
|
||||
|
||||
bool downloadFileFromCOS(const char* cosFilePathName, const char* localFilePath)
|
||||
{
|
||||
qcloud_cos::CosConfig config(gAppID, gSecretId, gSecretKey, gRegion);
|
||||
qcloud_cos::CosConfig config(0, gSecretId, gSecretKey, gRegion);
|
||||
config.SetLogCallback(&TestLogCallback);
|
||||
qcloud_cos::CosAPI cos(config);
|
||||
|
||||
@@ -57,4 +63,35 @@ bool downloadFileFromCOS(const char* cosFilePathName, const char* localFilePath)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uploadFileToCos(const char* localFilePath, const char* cosFilePath)
|
||||
{
|
||||
qcloud_cos::CosConfig config(0, gSecretId, gSecretKey, gRegion);
|
||||
config.SetLogCallback(&TestLogCallback);
|
||||
qcloud_cos::CosAPI cos(config);
|
||||
|
||||
// 构造下载对象的请求
|
||||
std::string objectName = cosFilePath;
|
||||
std::string localPath = localFilePath;
|
||||
|
||||
// 上传对象构造
|
||||
qcloud_cos::PutObjectByFileReq req(gBucketName, objectName, localPath);
|
||||
qcloud_cos::PutObjectByFileResp resp;
|
||||
qcloud_cos::CosResult result = cos.PutObject(req, &resp);
|
||||
if (result.IsSucc()) {
|
||||
// 上传文件成功
|
||||
std::cout << "Upload file success!" << std::endl;
|
||||
}
|
||||
else {
|
||||
// 上传文件失败,可以调用 CosResult 的成员函数输出错误信息,例如 requestID 等
|
||||
std::cout << "HttpStatus=" << result.GetHttpStatus() << std::endl;
|
||||
std::cout << "ErrorCode=" << result.GetErrorCode() << std::endl;
|
||||
std::cout << "ErrorMsg=" << result.GetErrorMsg() << std::endl;
|
||||
std::cout << "ResourceAddr=" << result.GetResourceAddr() << std::endl;
|
||||
std::cout << "XCosRequestId=" << result.GetXCosRequestId() << std::endl;
|
||||
std::cout << "XCosTraceId=" << result.GetXCosTraceId() << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
bool downloadFileFromCOS(const char* cosFilePath, const char* localFilePath);
|
||||
|
||||
bool uploadFileToCos(const char* localFilePath, const char* cosFilePath);
|
||||
|
||||
+33
-8
@@ -60,7 +60,8 @@ static void printUsage(const char* moduleName)
|
||||
printf(" MakeDiff\tCreates a binary diff patch file between two input files using BSDIFF43.\n");
|
||||
printf(" ApplyPatch\tApplies a BSDIFF43 binary patch to an input file and writes the patched result to an output file.\n");
|
||||
printf(" HashFile\tCalculates the hash(MD5|SHA256) of the contents of a specified file.\n");
|
||||
printf(" HttpDownload\tDownloads a file from a specified URL and saves it to a local file.\n");
|
||||
printf(" Download\tDownloads a file from a specified URL and saves it to a local file.\n");
|
||||
printf(" Upload\tUpload a local file to a specified cos server.\n");
|
||||
printf(" RunLuaFile\t xxxx \n");
|
||||
printf("\nSample:\n");
|
||||
printf(" -m GenRandFile -min 500 -max 1k -o rand.bin\n");
|
||||
@@ -71,7 +72,8 @@ static void printUsage(const char* moduleName)
|
||||
printf(" -m ApplyPatch -i ver01.bin -i2 patch_ver01_ver02.diff -o ver02.bin\n");
|
||||
printf(" -m HashFile -t md5 -i ver01.bin\n");
|
||||
printf(" -m HashFile -t sha256 -i ver01.bin\n");
|
||||
printf(" -m HttpDownload -i http://download.com/file.txt -o file.txt\n");
|
||||
printf(" -m Download -i http://download.com/file.txt -o file.txt\n");
|
||||
printf(" -m Upload -i file.txt -o cos:\\path\file.txt \n");
|
||||
printf(" -m RunLuaFile -i script.lua\n");
|
||||
}
|
||||
|
||||
@@ -85,7 +87,8 @@ enum WorkMode {
|
||||
WM_MAKE_DIFF,
|
||||
WM_APPLY_PATCH,
|
||||
WM_HASH_FILE,
|
||||
WM_HTTP_DOWNLOAD,
|
||||
WM_DOWNLOAD,
|
||||
WM_UPLOAD,
|
||||
WM_RUN_LUA_FILE,
|
||||
};
|
||||
|
||||
@@ -124,8 +127,11 @@ WorkMode parserWorkMode(const char* modeStr)
|
||||
else if (_stricmp(modeStr, "HashFile") == 0) {
|
||||
return WM_HASH_FILE;
|
||||
}
|
||||
else if (_stricmp(modeStr, "HttpDownload") == 0) {
|
||||
return WM_HTTP_DOWNLOAD;
|
||||
else if (_stricmp(modeStr, "Download") == 0) {
|
||||
return WM_DOWNLOAD;
|
||||
}
|
||||
else if (_stricmp(modeStr, "Upload") == 0) {
|
||||
return WM_UPLOAD;
|
||||
}
|
||||
else if (_stricmp(modeStr, "RunLuaFile") == 0) {
|
||||
return WM_RUN_LUA_FILE;
|
||||
@@ -151,6 +157,8 @@ HashType parserHashType(const char* typeStr)
|
||||
return HT_NONE; // default to HT_NONE
|
||||
}
|
||||
|
||||
const int kDiffCompressMethod = 2;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CSimpleOptA args(argc, argv, g_rgOptions);
|
||||
@@ -336,7 +344,7 @@ int main(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
printf("Creating diff between %s and %s, output: %s\n", inputFilename, inputFilename2, outputFilename);
|
||||
if (!createDiff(inputFilename, inputFilename2, outputFilename))
|
||||
if (!createDiff(inputFilename, inputFilename2, outputFilename, kDiffCompressMethod))
|
||||
{
|
||||
printf("Error: Failed to create diff file.\n");
|
||||
return 1;
|
||||
@@ -353,14 +361,14 @@ int main(int argc, char* argv[])
|
||||
return 1;
|
||||
}
|
||||
printf("Applying patch from %s with patch %s, output: %s\n", inputFilename, inputFilename2, outputFilename);
|
||||
if (!applyPatch(inputFilename, inputFilename2, outputFilename))
|
||||
if (!applyPatch(inputFilename, inputFilename2, outputFilename, kDiffCompressMethod))
|
||||
{
|
||||
printf("Error: Failed to apply patch.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_HTTP_DOWNLOAD:
|
||||
case WM_DOWNLOAD:
|
||||
{
|
||||
if (inputFilename == nullptr || outputFilename == nullptr)
|
||||
{
|
||||
@@ -377,6 +385,23 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_UPLOAD:
|
||||
{
|
||||
if (inputFilename == nullptr || outputFilename == nullptr)
|
||||
{
|
||||
printf("Error: For 'upload' mode, you must specify input local file and output cos path.\n");
|
||||
printUsage(::PathFindFileNameA(argv[0]));
|
||||
return 1;
|
||||
}
|
||||
printf("Uploading from %s to %s\n", inputFilename, outputFilename);
|
||||
if(!uploadFile(inputFilename, outputFilename))
|
||||
{
|
||||
printf("Error: Failed to upload file.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RUN_LUA_FILE:
|
||||
{
|
||||
if (inputFilename == nullptr)
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
#include "sgu_mode_apply_patch.h"
|
||||
#include "sgu_utils.h"
|
||||
|
||||
#include "bzlib.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "bspatch.h"
|
||||
}
|
||||
|
||||
#include "bzlib.h"
|
||||
#include "zstd.h"
|
||||
|
||||
|
||||
//--------------------------- Not Compress-----------------------------------
|
||||
static int patchFileReader(const struct bspatch_stream* stream, void* buffer, int length)
|
||||
{
|
||||
FILE* fp = (FILE*)stream->opaque;
|
||||
@@ -20,6 +22,7 @@ static int patchFileReader(const struct bspatch_stream* stream, void* buffer, in
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------- BZ2 -----------------------------------
|
||||
static int bzPatchFileReader(const struct bspatch_stream* stream, void* buffer, int length)
|
||||
{
|
||||
BZFILE* bz2 = (BZFILE*)stream->opaque;
|
||||
@@ -32,7 +35,117 @@ static int bzPatchFileReader(const struct bspatch_stream* stream, void* buffer,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool applyPatch(const char* inputFilename, const char* patchFilename, const char* outputFilename)
|
||||
//--------------------------- ZSTD -----------------------------------
|
||||
struct ZSTD_DecompressContext
|
||||
{
|
||||
ZSTD_DCtx* dctx;
|
||||
|
||||
FILE* fpInput;
|
||||
|
||||
void* inputBuf;
|
||||
size_t inputBufSize;
|
||||
size_t inputBufDataSize;
|
||||
size_t inputBufDataReadedPos;
|
||||
|
||||
void* outputBuf;
|
||||
size_t outputBufSize;
|
||||
size_t outputBufDataSize;
|
||||
size_t outputBufDataUploadedPos;
|
||||
};
|
||||
|
||||
ZSTD_DecompressContext* createZSTDDecompressContext(FILE* fpInput)
|
||||
{
|
||||
ZSTD_DecompressContext* ctx = new ZSTD_DecompressContext();
|
||||
ctx->dctx = ZSTD_createDCtx();
|
||||
ctx->fpInput = fpInput;
|
||||
|
||||
ctx->inputBufSize = ZSTD_DStreamInSize();
|
||||
ctx->inputBuf = malloc(ctx->inputBufSize);
|
||||
ctx->inputBufDataSize = 0;
|
||||
ctx->inputBufDataReadedPos = 0;
|
||||
|
||||
ctx->outputBufSize = ZSTD_DStreamOutSize();
|
||||
ctx->outputBuf = malloc(ctx->outputBufSize);
|
||||
ctx->outputBufDataSize = 0;
|
||||
ctx->outputBufDataUploadedPos = 0;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void destoryZSTDDecompressContext(ZSTD_DecompressContext* ctx)
|
||||
{
|
||||
free(ctx->inputBuf);
|
||||
free(ctx->outputBuf);
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
static int zstdPatchFileReader(const struct bspatch_stream* stream, void* buffer, int length)
|
||||
{
|
||||
ZSTD_DecompressContext* ctx = (ZSTD_DecompressContext*)(stream->opaque);
|
||||
if (length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//total uploaded size
|
||||
size_t uploadedSize = 0;
|
||||
|
||||
do {
|
||||
//upload all decompressed data
|
||||
if (ctx->outputBufDataSize > ctx->outputBufDataUploadedPos)
|
||||
{
|
||||
size_t remainDecompressedDataSize = ctx->outputBufDataSize - ctx->outputBufDataUploadedPos;
|
||||
size_t remainNotUploadedSize = (size_t)length - uploadedSize;
|
||||
|
||||
size_t uploadSize = remainNotUploadedSize < remainDecompressedDataSize ? remainNotUploadedSize : remainDecompressedDataSize;
|
||||
if (uploadSize > 0)
|
||||
{
|
||||
memcpy((uint8_t*)buffer + uploadedSize, ((uint8_t*)ctx->outputBuf) + ctx->outputBufDataUploadedPos, uploadSize);
|
||||
|
||||
uploadedSize += uploadSize;
|
||||
ctx->outputBufDataUploadedPos += uploadSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadedSize >= length)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//compressed data empty
|
||||
if (ctx->inputBufDataSize == ctx->inputBufDataReadedPos)
|
||||
{
|
||||
//read file
|
||||
ctx->inputBufDataSize = fread(ctx->inputBuf, 1, ctx->inputBufSize, ctx->fpInput);
|
||||
ctx->inputBufDataReadedPos = 0;
|
||||
|
||||
if (ctx->inputBufDataSize == 0)
|
||||
{
|
||||
//TODO:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//decompress data
|
||||
ZSTD_inBuffer input = { ctx->inputBuf, ctx->inputBufDataSize, ctx->inputBufDataReadedPos };
|
||||
ZSTD_outBuffer output = { ctx->outputBuf, ctx->outputBufSize, 0 };
|
||||
|
||||
const size_t ret = ZSTD_decompressStream(ctx->dctx, &output, &input);
|
||||
if (ZSTD_isError(ret))
|
||||
{
|
||||
//TODO:
|
||||
return -1;
|
||||
}
|
||||
ctx->inputBufDataReadedPos = input.pos;
|
||||
|
||||
ctx->outputBufDataUploadedPos = 0;
|
||||
ctx->outputBufDataSize = output.pos;
|
||||
} while (true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool applyPatch(const char* inputFilename, const char* patchFilename, const char* outputFilename, int32_t compressMethod)
|
||||
{
|
||||
if (!inputFilename || inputFilename[0] == 0 || !patchFilename || patchFilename[0] == 0)
|
||||
{
|
||||
@@ -88,32 +201,82 @@ bool applyPatch(const char* inputFilename, const char* patchFilename, const char
|
||||
// Read output file lengths from header
|
||||
int64_t outputFileSize = *(int64_t*)(header + 16);
|
||||
pOutputBuffer = new uint8_t[outputFileSize + 1];
|
||||
if(pOutputBuffer == nullptr)
|
||||
if (pOutputBuffer == nullptr)
|
||||
{
|
||||
printf("Error: Failed to allocate memory[%lld] for output buffer\n", outputFileSize+1);
|
||||
printf("Error: Failed to allocate memory[%lld] for output buffer\n", outputFileSize + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
BZFILE* bzHandle = nullptr;
|
||||
ZSTD_DecompressContext* zstdCtx = nullptr;
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
int bz2err;
|
||||
BZFILE* bzHandle = BZ2_bzReadOpen(&bz2err, patchFile, 0, 0, NULL, 0);
|
||||
bzHandle = BZ2_bzReadOpen(&bz2err, patchFile, 0, 0, NULL, 0);
|
||||
if (bzHandle == nullptr)
|
||||
{
|
||||
printf("BZ2_bzReadOpen, bz2err=%d", bz2err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(compressMethod==2)
|
||||
{
|
||||
zstdCtx = createZSTDDecompressContext(patchFile);
|
||||
if (zstdCtx == 0)
|
||||
{
|
||||
printf("create zstd context failed!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the patch
|
||||
struct bspatch_stream stream;
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
stream.read = bzPatchFileReader;
|
||||
stream.opaque = bzHandle;
|
||||
if (bspatch(pInputBuffer, inputFileSize, pOutputBuffer, outputFileSize, &stream))
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
stream.read = zstdPatchFileReader;
|
||||
stream.opaque = zstdCtx;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.read = patchFileReader;
|
||||
stream.opaque = patchFile;
|
||||
}
|
||||
|
||||
if (bspatch(pInputBuffer, inputFileSize, pOutputBuffer, outputFileSize, &stream) !=0 )
|
||||
{
|
||||
printf("Error: Failed to apply patch\n");
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
// Clean up the bzip2 reads
|
||||
int bz2err;
|
||||
BZ2_bzReadClose(&bz2err, bzHandle);
|
||||
bzHandle = nullptr;
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
destoryZSTDDecompressContext(zstdCtx);
|
||||
zstdCtx = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
// Clean up the bzip2 reads
|
||||
int bz2err;
|
||||
BZ2_bzReadClose(&bz2err, bzHandle);
|
||||
bzHandle = nullptr;
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
destoryZSTDDecompressContext(zstdCtx);
|
||||
zstdCtx = nullptr;
|
||||
}
|
||||
|
||||
// Write the output buffer to the output file
|
||||
if (outputFileSize != fwrite(pOutputBuffer, 1, outputFileSize, outputFile))
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* @param inputFilename The path to the original input file to be patched.
|
||||
* @param patchFilename The path to the BSDIFF43 patch file (bzip2-compressed).
|
||||
* @param outputFilename The path to the output file where the patched result will be written.
|
||||
* @param compressMethod 0:Not compress 1: bzip 2:zstd
|
||||
* @return true if the patch is applied successfully; false otherwise.
|
||||
*
|
||||
* The function performs the following steps:
|
||||
@@ -18,4 +19,4 @@
|
||||
* 7. Writes the patched data to the output file.
|
||||
* 8. Cleans up all resources and returns true on success, or false if any error occurs.
|
||||
*/
|
||||
bool applyPatch(const char* inputFilename, const char* patchFilename, const char* outputFilename);
|
||||
bool applyPatch(const char* inputFilename, const char* patchFilename, const char* outputFilename, int32_t compressMethod);
|
||||
|
||||
@@ -30,3 +30,25 @@ bool downloadFile(const char* szDownloadUrl, const char* szLocalFile)
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uploadFile(const char* szLocalFile, const char* szUploadUrl)
|
||||
{
|
||||
if (szLocalFile == nullptr || szUploadUrl == nullptr)
|
||||
{
|
||||
printf("Error: upload url or local file is null.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string urlStr = szUploadUrl;
|
||||
|
||||
if (_stricmp(urlStr.substr(0, 6).c_str(), "cos://") == 0)
|
||||
{
|
||||
uploadFileToCos(szLocalFile, urlStr.substr(6).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: unsupported upload url scheme: %s\n", szUploadUrl);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
bool downloadFile(const char* szDownloadUrl, const char* szLocalFile);
|
||||
bool uploadFile(const char* szLocalFile, const char* szUploadUrl);
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
#include "sgu_mode_make_diff.h"
|
||||
#include "sgu_utils.h"
|
||||
|
||||
#include "bzlib.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "bsdiff.h"
|
||||
}
|
||||
|
||||
#include "bzlib.h"
|
||||
#include "zstd.h"
|
||||
|
||||
static int bzPatchFileWriter(struct bsdiff_stream* stream, const void* buffer, int size)
|
||||
{
|
||||
BZFILE* bz2 = (BZFILE*)stream->opaque;
|
||||
@@ -22,7 +23,143 @@ static int bzPatchFileWriter(struct bsdiff_stream* stream, const void* buffer, i
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool createDiff(const char* inputFilename1, const char* inputFilename2, const char* outputFilename)
|
||||
struct ZSTD_CompressContext
|
||||
{
|
||||
ZSTD_CCtx* cctx;
|
||||
|
||||
void* inputBuf;
|
||||
size_t inputBufSize;
|
||||
size_t inputBufDataSize;
|
||||
|
||||
void* outputBuf;
|
||||
size_t outputBufSize;
|
||||
|
||||
FILE* fpOutput;
|
||||
|
||||
FILE* fpDebugOutput;
|
||||
FILE* fpDebugOutput2;
|
||||
};
|
||||
|
||||
ZSTD_CompressContext* createZSTDCompressContext(FILE* fpOutput)
|
||||
{
|
||||
ZSTD_CompressContext* ctx = new ZSTD_CompressContext();
|
||||
if (ctx == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ctx->cctx = ZSTD_createCCtx();
|
||||
if (ctx->cctx == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZSTD_CCtx_setParameter(ctx->cctx, ZSTD_c_compressionLevel, ZSTD_CLEVEL_DEFAULT);
|
||||
ZSTD_CCtx_setParameter(ctx->cctx, ZSTD_c_checksumFlag, 1);
|
||||
|
||||
ctx->inputBufSize = ZSTD_CStreamInSize();
|
||||
ctx->inputBuf = malloc(ctx->inputBufSize);
|
||||
if (ctx->inputBuf == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
ctx->inputBufDataSize = 0;
|
||||
|
||||
ctx->outputBufSize = ZSTD_CStreamOutSize();
|
||||
ctx->outputBuf = malloc(ctx->outputBufSize);
|
||||
if (ctx->outputBuf == nullptr)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ctx->fpOutput = fpOutput;
|
||||
|
||||
ctx->fpDebugOutput = fopen("org.patch", "wb");
|
||||
ctx->fpDebugOutput2 = fopen("org.patch.2", "wb");
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void destoryZSTDCompressContext(ZSTD_CompressContext* ctx)
|
||||
{
|
||||
fclose(ctx->fpDebugOutput);
|
||||
fclose(ctx->fpDebugOutput2);
|
||||
|
||||
free(ctx->inputBuf);
|
||||
free(ctx->outputBuf);
|
||||
delete ctx;
|
||||
}
|
||||
|
||||
void zstdCompressData(ZSTD_CompressContext* ctx, ZSTD_EndDirective mode)
|
||||
{
|
||||
/* Set the input buffer to what we just read.
|
||||
* We compress until the input buffer is empty, each time flushing the
|
||||
* output.
|
||||
*/
|
||||
ZSTD_inBuffer input = { ctx->inputBuf, ctx->inputBufDataSize, 0 };
|
||||
bool finished;
|
||||
do {
|
||||
/* Compress into the output buffer and write all of the output to
|
||||
* the file so we can reuse the buffer next iteration.
|
||||
*/
|
||||
ZSTD_outBuffer output = { ctx->outputBuf, ctx->outputBufSize, 0 };
|
||||
const size_t remaining = ZSTD_compressStream2(ctx->cctx, &output, &input, mode);
|
||||
|
||||
//write to output file
|
||||
fwrite(ctx->outputBuf, 1, output.pos, ctx->fpOutput);
|
||||
|
||||
fwrite(ctx->outputBuf, 1, output.pos, ctx->fpDebugOutput2);
|
||||
|
||||
/* If we're on the last chunk we're finished when zstd returns 0,
|
||||
* which means its consumed all the input AND finished the frame.
|
||||
* Otherwise, we're finished when we've consumed all the input.
|
||||
*/
|
||||
finished = (mode== ZSTD_e_end) ? (remaining == 0) : (input.pos == input.size);
|
||||
} while (!finished);
|
||||
ctx->inputBufDataSize = 0;
|
||||
}
|
||||
|
||||
void zstdPatchFileClose(ZSTD_CompressContext* ctx)
|
||||
{
|
||||
zstdCompressData(ctx, ZSTD_e_end);
|
||||
}
|
||||
|
||||
static int zstdPatchFileWriter(struct bsdiff_stream* stream, const void* inputData, int inputSize)
|
||||
{
|
||||
ZSTD_CompressContext* ctx = (ZSTD_CompressContext*)(stream->opaque);
|
||||
|
||||
fwrite(inputData, 1, inputSize, ctx->fpDebugOutput);
|
||||
|
||||
size_t readedSize = 0;
|
||||
|
||||
for (;;) {
|
||||
size_t inputBufRemainSize = ctx->inputBufSize - ctx->inputBufDataSize;
|
||||
size_t remainDataSize = (size_t)inputSize - readedSize;
|
||||
size_t readSize = inputBufRemainSize<remainDataSize ? inputBufRemainSize : remainDataSize;
|
||||
memcpy(((uint8_t*)ctx->inputBuf)+ctx->inputBufDataSize, (const uint8_t*)inputData + readedSize, readSize);
|
||||
readedSize += readSize;
|
||||
ctx->inputBufDataSize += readSize;
|
||||
|
||||
if (ctx->inputBufDataSize >= ctx->inputBufSize)
|
||||
{
|
||||
zstdCompressData(ctx, ZSTD_e_continue);
|
||||
}
|
||||
|
||||
if (readedSize >= (size_t)inputSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int patchFileWriter(struct bsdiff_stream* stream, const void* inputData, int inputSize)
|
||||
{
|
||||
FILE* fpOutput = (FILE*)(stream->opaque);
|
||||
fwrite(inputData, 1, inputSize, fpOutput);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool createDiff(const char* inputFilename1, const char* inputFilename2, const char* outputFilename, int32_t compressMethod)
|
||||
{
|
||||
if (!inputFilename1 || inputFilename1[0] == 0 || !inputFilename2 || inputFilename2[0] == 0)
|
||||
{
|
||||
@@ -72,32 +209,74 @@ bool createDiff(const char* inputFilename1, const char* inputFilename2, const ch
|
||||
break;
|
||||
}
|
||||
|
||||
BZFILE* bzHandle = nullptr;
|
||||
ZSTD_CompressContext* zstdContext = nullptr;
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
int bz2err;
|
||||
BZFILE* bzHandle = BZ2_bzWriteOpen(&bz2err, fpOutput, 9, 0, 0);
|
||||
bzHandle = BZ2_bzWriteOpen(&bz2err, fpOutput, 9, 0, 0);
|
||||
if (bzHandle == nullptr || bz2err != BZ_OK)
|
||||
{
|
||||
printf("BZ2_bzWriteOpen failed, bz2err=%d\n", bz2err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
zstdContext = createZSTDCompressContext(fpOutput);
|
||||
if (zstdContext == nullptr)
|
||||
{
|
||||
printf("Failed create zstd context!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
}
|
||||
//generate diff
|
||||
struct bsdiff_stream stream;
|
||||
stream.malloc = malloc;
|
||||
stream.free = free;
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
stream.write = bzPatchFileWriter;
|
||||
stream.opaque = bzHandle;
|
||||
if (bsdiff(pBuffer1, fileSize1, pBuffer2, fileSize2, &stream))
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
stream.write = zstdPatchFileWriter;
|
||||
stream.opaque = zstdContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.write = patchFileWriter;
|
||||
stream.opaque = fpOutput;
|
||||
}
|
||||
|
||||
if (bsdiff(pBuffer1, fileSize1, pBuffer2, fileSize2, &stream) !=0 )
|
||||
{
|
||||
printf("bsdiff error!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (compressMethod == 1)
|
||||
{
|
||||
int bz2err;
|
||||
BZ2_bzWriteClose(&bz2err, bzHandle, 0, NULL, NULL);
|
||||
if (bz2err != BZ_OK)
|
||||
{
|
||||
printf("BZ2_bzWriteClose failed, bz2err=%d", bz2err);
|
||||
break;
|
||||
}
|
||||
bzHandle = nullptr;
|
||||
}
|
||||
else if (compressMethod == 2)
|
||||
{
|
||||
zstdPatchFileClose(zstdContext);
|
||||
destoryZSTDCompressContext(zstdContext);
|
||||
zstdContext = nullptr;
|
||||
}
|
||||
|
||||
result = true;
|
||||
printf("Diff file created successfully: %s\n", outputFilename);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* @param inputFilename1 The path to the original (old) input file.
|
||||
* @param inputFilename2 The path to the new input file to compare against.
|
||||
* @param outputFilename The path to the output file where the diff patch will be written.
|
||||
* @param compressMethod 0:Not compress 1: bzip 2:zstd
|
||||
* @return true if the diff file is created successfully; false otherwise.
|
||||
*
|
||||
* The function performs the following steps:
|
||||
@@ -17,4 +18,4 @@
|
||||
* 6. Finalizes the bzip2 stream and closes all files and buffers.
|
||||
* 7. Returns true on success, or false if any error occurs during processing.
|
||||
*/
|
||||
bool createDiff(const char* inputFilename, const char* inputFilename2, const char* outputFilename);
|
||||
bool createDiff(const char* inputFilename, const char* inputFilename2, const char* outputFilename, int32_t compressMethod);
|
||||
|
||||
Reference in New Issue
Block a user