diff options
author | Mateusz Moscicki <m.moscicki2@partner.samsung.com> | 2022-02-14 18:14:32 +0100 |
---|---|---|
committer | Mateusz Moscicki <m.moscicki2@partner.samsung.com> | 2022-02-21 15:59:47 +0100 |
commit | 8f93f088bdc02e5261eac99e2c7b6409fce5605d (patch) | |
tree | b4dd1ef9725f53dee0dfee8979ba5c7a8cb80053 | |
parent | 2b0a9620607a0bea83a86ffb45e582d2e9b12ee3 (diff) | |
download | libtota-8f93f088bdc02e5261eac99e2c7b6409fce5605d.tar.gz libtota-8f93f088bdc02e5261eac99e2c7b6409fce5605d.tar.bz2 libtota-8f93f088bdc02e5261eac99e2c7b6409fce5605d.zip |
ss_bsdiff: Add Brotli compression method
ss_bsdiff can produce patches compressed with both LZMA (default) and
Brotli method.
Use the '-c <lzma|brotli>' to select appropriate method.
Change-Id: I05b6c1cf22826530f823b72940af8d8ff7f602c9
-rwxr-xr-x | bsdiff/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | bsdiff/ss_bsdiff.c | 116 |
2 files changed, 114 insertions, 4 deletions
diff --git a/bsdiff/CMakeLists.txt b/bsdiff/CMakeLists.txt index 497299c..ecd7205 100755 --- a/bsdiff/CMakeLists.txt +++ b/bsdiff/CMakeLists.txt @@ -10,7 +10,7 @@ SET(ss_bspatch_SRCS INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/bsdiff) INCLUDE(FindPkgConfig) -pkg_check_modules(${PROJECT_NAME}_pkgs REQUIRED liblzma-tool libdivsufsort) +pkg_check_modules(${PROJECT_NAME}_pkgs REQUIRED liblzma-tool libdivsufsort libbrotlienc) FOREACH(flag ${${PROJECT_NAME}_pkgs_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") diff --git a/bsdiff/ss_bsdiff.c b/bsdiff/ss_bsdiff.c index 13ef124..209f2e9 100755 --- a/bsdiff/ss_bsdiff.c +++ b/bsdiff/ss_bsdiff.c @@ -31,7 +31,10 @@ #define _CRT_SECURE_NO_WARNINGS #include <assert.h> #include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> #include <err.h> +#include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> @@ -45,6 +48,7 @@ #include <7zVersion.h> #include <LzmaDec.h> #include <LzmaEnc.h> +#include <brotli/encode.h> #define SUFSORT_MOD // Change suffix sorting algorithm from Qsufsort to Divsufsort //#define ZLIB_MOD // Change compression algorithm @@ -55,6 +59,7 @@ #define MULTI_THREADING 1 // only with #define CONST_MEMORY_USAGE or #define MAX_MATCH_SIZE #define TIME_LIMIT_CHECK 300 #define TEMP_PATCH_NAME "temp_patch" +#define BROTLI_COMPRESSION_QUALITY 9 /* Take care : 1) Use either (MAX_MATCH_SIZE or CONST_MEMORY_USAGE) or (none of both). @@ -110,6 +115,7 @@ struct data_thread { enum compression_method { CM_LZMA, + CM_BROTLI, }; struct bsdiff_info { @@ -526,7 +532,8 @@ static SRes lzma_encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 int lzma_compress(const char *input_file, const char *output_file, char *rs, int rs_size) { - assert(patch_file); + assert(input_file); + assert(output_file); assert(rs); CFileSeqInStream inStream; @@ -573,10 +580,96 @@ int lzma_compress(const char *input_file, const char *output_file, char *rs, int return 0; } +int brotli_compress_internal(int input_fd, int output_fd, int quality) +{ + int res = -1; + size_t input_size = lseek(input_fd, 0, SEEK_END); + lseek(input_fd, 0, SEEK_SET); + void *input_file_ptr = mmap(NULL, input_size, PROT_READ, MAP_PRIVATE, input_fd, 0); + + if (input_file_ptr == MAP_FAILED) { + printf("Can not mmap input file: %d - %m\n", errno); + goto exit; + } + + BrotliEncoderState *bstate = BrotliEncoderCreateInstance(NULL, NULL, NULL); + if (bstate == 0) { + printf("Can not create BrotliEncoder instance\n"); + goto exit; + } + size_t max_output_size = BrotliEncoderMaxCompressedSize(input_size); + + if (max_output_size == 0) { + printf("Brotli engine error\n"); + goto exit; + } + + if (ftruncate(output_fd, max_output_size) == -1) { + printf("Can not truncate output file: %d - %m\n", errno); + goto exit; + } + + void *output_file_ptr = mmap(NULL, max_output_size, PROT_WRITE, MAP_SHARED, output_fd, 0); + if (output_file_ptr == MAP_FAILED) { + printf("Can not mmap output file: %d - %m\n", errno); + goto exit; + } + + if(!BrotliEncoderCompress(quality, + BROTLI_DEFAULT_WINDOW, + BROTLI_DEFAULT_MODE, + input_size, + input_file_ptr, + &max_output_size, + output_file_ptr)) { + printf("Compression error\n"); + goto exit; + } + if (ftruncate(output_fd, max_output_size) == -1) { + printf("Can not truncate output file after compression: %d - %m\n", errno); + goto exit; + } + + res = 0; +exit: + if (input_file_ptr) + munmap(input_file_ptr, input_size); + if (output_file_ptr) + munmap(output_file_ptr, max_output_size); + + return res; +} + +int brotli_compress(const char *input_file, const char *output_file, int quality) +{ + assert(input_file); + assert(output_file); + int res = -1; + + int input_fd = open(input_file, O_RDONLY); + if (input_fd < 0) { + printf("Can not open file: %s for read\n", input_file); + return res; + } + int output_fd = open(output_file, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR); + if (output_fd < 0) { + printf("Can not open file: %s for write (%d: %m)\n", output_file, errno); + close(input_fd); + return res; + } + + res = brotli_compress_internal(input_fd, output_fd, quality); + + close(input_fd); + close(output_fd); + + return res; +} + void print_help(const char *arg0) { assert(arg0); - errx(1, "ss_bsdiff Version 5.0\nUsage: %s oldfile newfile patchfile\n", arg0); + errx(1, "ss_bsdiff Version 5.0\nUsage: %s [-c <lzma|brotli>] oldfile newfile patchfile\n", arg0); } int parse_args(struct bsdiff_info *info, int argc, char *argv[]) @@ -584,6 +677,8 @@ int parse_args(struct bsdiff_info *info, int argc, char *argv[]) assert(info); assert(argv); + info->comp_method = CM_LZMA; // default compression method + struct option long_options[] = { {"compression", optional_argument, NULL, 'c'}, {0, 0 , 0, 0} @@ -596,6 +691,8 @@ int parse_args(struct bsdiff_info *info, int argc, char *argv[]) case 'c': if (strcmp("lzma", optarg) == 0) info->comp_method = CM_LZMA; + else if (strcmp("brotli", optarg) == 0) + info->comp_method = CM_BROTLI; else { err(1, "Unknown compression method: %s", optarg); return -1; @@ -637,7 +734,20 @@ int MY_CDECL main(int argc, char *argv[]) if (ret != 0) err(1, "bsdiff fails to create delta within timelimit"); #endif - int res = lzma_compress(TEMP_PATCH_NAME, info.patch_file, rs, sizeof(rs)); + int res = 0; + switch(info.comp_method) { + case CM_LZMA: + res = lzma_compress(TEMP_PATCH_NAME, info.patch_file, rs, sizeof(rs)); + break; + case CM_BROTLI: + res = brotli_compress(TEMP_PATCH_NAME, info.patch_file, BROTLI_COMPRESSION_QUALITY); + break; + default: + printf("Unknown compression method\n"); + res = -1; + break; + } + if (remove(TEMP_PATCH_NAME) < 0) printf("Failed to remove %s\n", TEMP_PATCH_NAME); fputs(rs, stdout); |