summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMateusz Moscicki <m.moscicki2@partner.samsung.com>2022-02-14 18:14:32 +0100
committerMateusz Moscicki <m.moscicki2@partner.samsung.com>2022-02-21 15:59:47 +0100
commit8f93f088bdc02e5261eac99e2c7b6409fce5605d (patch)
treeb4dd1ef9725f53dee0dfee8979ba5c7a8cb80053
parent2b0a9620607a0bea83a86ffb45e582d2e9b12ee3 (diff)
downloadlibtota-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-xbsdiff/CMakeLists.txt2
-rwxr-xr-xbsdiff/ss_bsdiff.c116
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);