diff --git a/cos-cpp-sdk/bin/coscli.exe b/cos-cpp-sdk/bin/coscli.exe new file mode 100644 index 0000000..c8fde77 Binary files /dev/null and b/cos-cpp-sdk/bin/coscli.exe differ diff --git a/sgutil/CMakeLists.txt b/sgutil/CMakeLists.txt index b6c39a5..7a5d1b7 100644 --- a/sgutil/CMakeLists.txt +++ b/sgutil/CMakeLists.txt @@ -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 ) diff --git a/sgutil/sgu_download_cos.cpp b/sgutil/sgu_download_cos.cpp index 5227450..fbe6728 100644 --- a/sgutil/sgu_download_cos.cpp +++ b/sgutil/sgu_download_cos.cpp @@ -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 \ No newline at end of file diff --git a/sgutil/sgu_download_cos.h b/sgutil/sgu_download_cos.h index 0fbc0f2..fcb0cf1 100644 --- a/sgutil/sgu_download_cos.h +++ b/sgutil/sgu_download_cos.h @@ -1,3 +1,5 @@ #pragma once bool downloadFileFromCOS(const char* cosFilePath, const char* localFilePath); + +bool uploadFileToCos(const char* localFilePath, const char* cosFilePath); diff --git a/sgutil/sgu_main.cpp b/sgutil/sgu_main.cpp index d5b8656..6b33163 100644 --- a/sgutil/sgu_main.cpp +++ b/sgutil/sgu_main.cpp @@ -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) diff --git a/sgutil/sgu_mode_apply_patch.cpp b/sgutil/sgu_mode_apply_patch.cpp index 94ba230..06a4b73 100644 --- a/sgutil/sgu_mode_apply_patch.cpp +++ b/sgutil/sgu_mode_apply_patch.cpp @@ -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; } - int bz2err; - BZFILE* bzHandle = BZ2_bzReadOpen(&bz2err, patchFile, 0, 0, NULL, 0); - if (bzHandle == nullptr) + BZFILE* bzHandle = nullptr; + ZSTD_DecompressContext* zstdCtx = nullptr; + if (compressMethod == 1) { - printf("BZ2_bzReadOpen, bz2err=%d", bz2err); - break; + int bz2err; + 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; - stream.read = bzPatchFileReader; - stream.opaque = bzHandle; - if (bspatch(pInputBuffer, inputFileSize, pOutputBuffer, outputFileSize, &stream)) + if (compressMethod == 1) + { + stream.read = bzPatchFileReader; + stream.opaque = bzHandle; + } + 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; } - // Clean up the bzip2 reads - BZ2_bzReadClose(&bz2err, bzHandle); + 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)) diff --git a/sgutil/sgu_mode_apply_patch.h b/sgutil/sgu_mode_apply_patch.h index 501fcb7..d0ad09b 100644 --- a/sgutil/sgu_mode_apply_patch.h +++ b/sgutil/sgu_mode_apply_patch.h @@ -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); diff --git a/sgutil/sgu_mode_download.cpp b/sgutil/sgu_mode_download.cpp index 14638d7..73494f5 100644 --- a/sgutil/sgu_mode_download.cpp +++ b/sgutil/sgu_mode_download.cpp @@ -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; +} \ No newline at end of file diff --git a/sgutil/sgu_mode_download.h b/sgutil/sgu_mode_download.h index 05e5e45..85652fd 100644 --- a/sgutil/sgu_mode_download.h +++ b/sgutil/sgu_mode_download.h @@ -1,3 +1,4 @@ #pragma once bool downloadFile(const char* szDownloadUrl, const char* szLocalFile); +bool uploadFile(const char* szLocalFile, const char* szUploadUrl); diff --git a/sgutil/sgu_mode_make_diff.cpp b/sgutil/sgu_mode_make_diff.cpp index f57cc70..e89deb4 100644 --- a/sgutil/sgu_mode_make_diff.cpp +++ b/sgutil/sgu_mode_make_diff.cpp @@ -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 = inputBufRemainSizeinputBuf)+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,31 +209,73 @@ bool createDiff(const char* inputFilename1, const char* inputFilename2, const ch break; } - int bz2err; - BZFILE* bzHandle = BZ2_bzWriteOpen(&bz2err, fpOutput, 9, 0, 0); - if (bzHandle == nullptr || bz2err != BZ_OK) + BZFILE* bzHandle = nullptr; + ZSTD_CompressContext* zstdContext = nullptr; + if (compressMethod == 1) { - printf("BZ2_bzWriteOpen failed, bz2err=%d\n", bz2err); - break; + int bz2err; + 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; - stream.write = bzPatchFileWriter; - stream.opaque = bzHandle; - if (bsdiff(pBuffer1, fileSize1, pBuffer2, fileSize2, &stream)) + if (compressMethod == 1) + { + stream.write = bzPatchFileWriter; + stream.opaque = bzHandle; + } + 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; } - BZ2_bzWriteClose(&bz2err, bzHandle, 0, NULL, NULL); - if (bz2err != BZ_OK) + if (compressMethod == 1) { - printf("BZ2_bzWriteClose failed, bz2err=%d", bz2err); - break; + 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; diff --git a/sgutil/sgu_mode_make_diff.h b/sgutil/sgu_mode_make_diff.h index 4743007..72b4a78 100644 --- a/sgutil/sgu_mode_make_diff.h +++ b/sgutil/sgu_mode_make_diff.h @@ -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);