From 4cb8b6f5b6cf26ab2fd3358b44094bdfa98cb1d7 Mon Sep 17 00:00:00 2001 From: Arun Date: Sat, 28 Aug 2021 12:55:11 +0530 Subject: [PATCH 01/15] Update doc --- README.md | 8 ++++---- Unishox_Article_2.pdf | Bin 161088 -> 161483 bytes Unishox_Article_2.tex | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 22cdb1f..80cfdd8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Unishox - Guaranteed Compression for Unicode Short Strings +# Unishox - A hybrid encoder for compressing Short Unicode Strings -This is a C library for compressing short strings. It was developed to individually compress and decompress small strings. In general compression utilities such as `zip`, `gzip` do not compress short strings well and often expand them. They also use lots of memory which makes them unusable in constrained environments like Arduino. +In general compression utilities such as `zip`, `gzip` do not compress short strings well and often expand them. They also use lots of memory which makes them unusable in constrained environments like Arduino. So Unishox algorithm was developed for individually compressing (and decompressing) short strings. -Note: The present byte-code version is 2 and it replaces Unishox 1. Unishox 1 is still available as unishox1.c, but it will have to be compiled manually if it is needed. +Note: The present byte-code version is 2 and it replaces [Unishox 1](Unishox_Article_1.pdf?raw=true). Unishox 1 is still available as unishox1.c, but it will have to be compiled manually if it is needed. # Applications @@ -22,7 +22,7 @@ The model used for arriving at the prefix-free code is shown below: ![Promo video](demo/model.png?raw=true) -The complete specification can be found in this article: [Unishox 2 - Guaranteed Configurable Compression for Short Strings using Entropy, Dictionary and Delta encoding techniques](Unishox_Article_2.pdf?raw=true). +The complete specification can be found in this article: [A hybrid encoder for compressing Short Unicode Strings](Unishox_Article_2.pdf?raw=true). # Compiling diff --git a/Unishox_Article_2.pdf b/Unishox_Article_2.pdf index 79311ebfcc96707956b95e91038466f5d23e50ab..80c4cacb1d2f4fb09fe19baec2869943341e2cba 100644 GIT binary patch delta 30365 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 P=4OW_Cl^ Date: Tue, 24 Aug 2021 09:44:55 +0200 Subject: [PATCH 02/15] Add CMake file to project --- .gitignore | 3 +++ CMakeLists.txt | 11 +++++++++++ 2 files changed, 14 insertions(+) create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index f7e8706..d3bda22 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ unishox++_0_1_0 unishox_0_1_0 .DS_Store *.txt +!CMakeLists.txt !json?.txt !xml?.txt !chinese.txt @@ -61,3 +62,5 @@ delta_only *.csu *.bcu +# Traditional cmake building directories +build* diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..962654e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.5) + +project(Unixshox + LANGUAGES C +) + +add_executable(unishox + unishox2.c + unishox2.h + test_unishox2.c +) From a85db7eeef8592adea4a7403b4c78fbbde363615 Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Tue, 24 Aug 2021 09:46:11 +0200 Subject: [PATCH 03/15] Dynamically allocated array MSVC2019 was complaining about trying to statically allocated the array: ...\test_unishox2.c(377): error C2057: expected constant expression ...\test_unishox2.c(377): error C2466: cannot allocate an array of constant size 0 ...\test_unishox2.c(377): error C2133: 'short_buf': unknown size --- test_unishox2.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test_unishox2.c b/test_unishox2.c index 65350af..c6cc690 100644 --- a/test_unishox2.c +++ b/test_unishox2.c @@ -341,7 +341,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || printf("%.2f %s\n", perc, cbuf); tot_len += len; ctot += clen; - char short_buf[strlen(args[3]) + 100]; + char* short_buf = malloc(strlen(args[3]) + 100); snprintf(short_buf, sizeof(short_buf), "const byte %s_%d[] PROGMEM = {", args[3], line_ctr++); fputs(short_buf, wfp); int len_len = encode_unsigned_varint((byte *) short_buf, clen); @@ -359,6 +359,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || } strcpy(short_buf, "};\n"); fputs(short_buf, wfp); + free(short_buf); } if (len > max_len) max_len = len; @@ -372,7 +373,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, tot_len); printf("%.2f%%\n", perc); - char short_buf[strlen(args[3]) + 100]; + char* short_buf = malloc(strlen(args[3]) + 100); snprintf(short_buf, sizeof(short_buf), "const byte * const %s[] PROGMEM = {", args[3]); fputs(short_buf, wfp); for (int i = 0; i < line_ctr; i++) { @@ -390,6 +391,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || snprintf(short_buf, sizeof(short_buf), "#define %s_max_len %d\n", args[3], max_len); fputs(short_buf, wfp); fputs("#endif\n", wfp); + free(short_buf); } else if (argv >= 2 && strcmp(args[1], "-t") == 0) { From 267301df28c2c206d09a41b4ae11944f0d984ee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 11:34:23 +0200 Subject: [PATCH 04/15] Add support for C11 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 962654e..36263b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,9 @@ project(Unixshox LANGUAGES C ) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_STANDARD 11) + add_executable(unishox unishox2.c unishox2.h From 18a8d191ee7e26c6bc6ad42784530b71cc012f01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 11:35:14 +0200 Subject: [PATCH 05/15] Fix wrong size of buffer The size returned by sizeof(buf) was 8 when its length was actually more than 100 bytes. --- test_unishox2.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test_unishox2.c b/test_unishox2.c index c6cc690..6eaa394 100644 --- a/test_unishox2.c +++ b/test_unishox2.c @@ -314,6 +314,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || fputs("_UNISHOX2_COMPRESSED__\n", wfp); int line_ctr = 0; int max_len = 0; + const size_t short_buf_len = strlen(args[3]) + 100; while (fgets(cbuf, sizeof(cbuf), fp) != NULL) { // compress the line and look in previous lines // add to linked list @@ -341,8 +342,8 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || printf("%.2f %s\n", perc, cbuf); tot_len += len; ctot += clen; - char* short_buf = malloc(strlen(args[3]) + 100); - snprintf(short_buf, sizeof(short_buf), "const byte %s_%d[] PROGMEM = {", args[3], line_ctr++); + char* short_buf = malloc(short_buf_len); + snprintf(short_buf, short_buf_len, "const byte %s_%d[] PROGMEM = {", args[3], line_ctr++); fputs(short_buf, wfp); int len_len = encode_unsigned_varint((byte *) short_buf, clen); for (int i = 0; i < len_len; i++) { @@ -373,8 +374,8 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, tot_len); printf("%.2f%%\n", perc); - char* short_buf = malloc(strlen(args[3]) + 100); - snprintf(short_buf, sizeof(short_buf), "const byte * const %s[] PROGMEM = {", args[3]); + char* short_buf = malloc(short_buf_len); + snprintf(short_buf, short_buf_len, "const byte * const %s[] PROGMEM = {", args[3]); fputs(short_buf, wfp); for (int i = 0; i < line_ctr; i++) { if (i) { @@ -386,9 +387,9 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || } strcpy(short_buf, "};\n"); fputs(short_buf, wfp); - snprintf(short_buf, sizeof(short_buf), "#define %s_line_count %d\n", args[3], line_ctr); + snprintf(short_buf, short_buf_len, "#define %s_line_count %d\n", args[3], line_ctr); fputs(short_buf, wfp); - snprintf(short_buf, sizeof(short_buf), "#define %s_max_len %d\n", args[3], max_len); + snprintf(short_buf, short_buf_len, "#define %s_max_len %d\n", args[3], max_len); fputs(short_buf, wfp); fputs("#endif\n", wfp); free(short_buf); From 878aab5e2b0ed41d7aca199ab15333765ece1a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 11:37:52 +0200 Subject: [PATCH 06/15] Reserve and free only in one place --- test_unishox2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test_unishox2.c b/test_unishox2.c index 6eaa394..7c4f810 100644 --- a/test_unishox2.c +++ b/test_unishox2.c @@ -315,6 +315,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || int line_ctr = 0; int max_len = 0; const size_t short_buf_len = strlen(args[3]) + 100; + char* short_buf = malloc(short_buf_len); while (fgets(cbuf, sizeof(cbuf), fp) != NULL) { // compress the line and look in previous lines // add to linked list @@ -342,7 +343,6 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || printf("%.2f %s\n", perc, cbuf); tot_len += len; ctot += clen; - char* short_buf = malloc(short_buf_len); snprintf(short_buf, short_buf_len, "const byte %s_%d[] PROGMEM = {", args[3], line_ctr++); fputs(short_buf, wfp); int len_len = encode_unsigned_varint((byte *) short_buf, clen); @@ -360,7 +360,6 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || } strcpy(short_buf, "};\n"); fputs(short_buf, wfp); - free(short_buf); } if (len > max_len) max_len = len; @@ -374,7 +373,6 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, tot_len); printf("%.2f%%\n", perc); - char* short_buf = malloc(short_buf_len); snprintf(short_buf, short_buf_len, "const byte * const %s[] PROGMEM = {", args[3]); fputs(short_buf, wfp); for (int i = 0; i < line_ctr; i++) { From c8074bc0812ebca889e7aa4733027b7393b8275b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 11:42:30 +0200 Subject: [PATCH 07/15] Remove unused variables and fix warnings about signess --- test_unishox2.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test_unishox2.c b/test_unishox2.c index 7c4f810..809608f 100644 --- a/test_unishox2.c +++ b/test_unishox2.c @@ -160,13 +160,11 @@ uint64_t decode_unsigned_varint(const uint8_t *data, int *decoded_bytes) { void print_string_as_hex(char *in, int len) { int l; - byte bit; printf("String in hex:\n"); for (l=0; l= 4 && (strcmp(args[1], "-g") == 0 || snprintf(short_buf, 10, "%u, ", (byte) short_buf[i]); fputs(short_buf, wfp); } - for (int i = 0; i < clen; i++) { + for (size_t i = 0; i < clen; i++) { if (i) { strcpy(short_buf, ", "); fputs(short_buf, wfp); From 8b7d646367c394b3c06d843fecc5d1419ba28202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 12:03:23 +0200 Subject: [PATCH 08/15] Add stricter compiler flags and fix some warnings --- CMakeLists.txt | 3 +-- cmake/compilerFlags.cmake | 22 ++++++++++++++++++++++ unishox2.c | 5 +---- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 cmake/compilerFlags.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 36263b9..c62f9b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,7 @@ project(Unixshox LANGUAGES C ) -set(CMAKE_C_STANDARD_REQUIRED ON) -set(CMAKE_C_STANDARD 11) +include(cmake/compilerFlags.cmake) add_executable(unishox unishox2.c diff --git a/cmake/compilerFlags.cmake b/cmake/compilerFlags.cmake new file mode 100644 index 0000000..ced8a21 --- /dev/null +++ b/cmake/compilerFlags.cmake @@ -0,0 +1,22 @@ +include(CheckCCompilerFlag) + +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_STANDARD 11) + +if (${CMAKE_C_COMPILER_ID} STREQUAL GNU) + set(COMPILER_IS_GCC ON) +elseif (${CMAKE_C_COMPILER_ID} MATCHES "Clang") + set(COMPILER_IS_CLANG ON) +endif() + +if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) + add_compile_options(-Werror) + add_compile_options(-Wall -Wcast-align -Wpointer-arith -Wformat-security -Wmissing-format-attribute -W) + add_compile_options(-Wno-error=format-nonliteral) + + check_c_compiler_flag(-Wdeprecated-copy DEPRECATED_COPY) + if ( DEPRECATED_COPY) + add_compile_options(-Wdeprecated-copy) + endif () + +endif() diff --git a/unishox2.c b/unishox2.c index 9c4d3fd..2cb9baf 100644 --- a/unishox2.c +++ b/unishox2.c @@ -186,7 +186,6 @@ int encodeUnicode(char *out, int ol, int32_t code, int32_t prev_code) { //const byte codes[8] = {0x00, 0x42, 0x83, 0xA3, 0xC3, 0xE4, 0xF5, 0xFD}; const byte codes[6] = {0x01, 0x82, 0xC3, 0xE4, 0xF5, 0xFD}; int32_t till = 0; - int orig_ol = ol; int32_t diff = code - prev_code; if (diff < 0) diff = -diff; @@ -214,8 +213,6 @@ int encodeUnicode(char *out, int ol, int32_t code, int32_t prev_code) { val <<= (8 - uni_bit_len[i]); ol = append_bits(out, ol, val & 0xFF, uni_bit_len[i]); } - //} - //printf("bits:%d\n", ol-orig_ol); return ol; } } @@ -630,7 +627,7 @@ int unishox2_compress_lines(const char *in, int len, char *out, const byte usx_h ol = append_bits(out, ol, usx_vcodes[1], usx_vcode_lens[1]); } else { c_in--; - ol = append_code(out, ol, usx_code_94[c_in], &state, usx_hcodes, usx_hcode_lens); + ol = append_code(out, ol, usx_code_94[(int)c_in], &state, usx_hcodes, usx_hcode_lens); } } else if (c_in == 13 && c_next == 10) { From db416c33115dde1ae2b757f0c76cd639d727c292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Sun, 5 Sep 2021 16:51:41 +0200 Subject: [PATCH 09/15] fix more warnings reported by msvc --- CMakeLists.txt | 7 +++++-- cmake/compilerFlags.cmake | 9 +++++++++ cmake/summary.cmake | 23 +++++++++++++++++++++++ test_unishox2.c | 37 ++++++++++++++++++------------------- unishox2.c | 12 ++++++------ 5 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 cmake/summary.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c62f9b6..9d33f4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,16 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.20) +cmake_policy(SET CMP0092 NEW) project(Unixshox LANGUAGES C ) -include(cmake/compilerFlags.cmake) +include(cmake/compilerFlags.cmake REQUIRED) add_executable(unishox unishox2.c unishox2.h test_unishox2.c ) + +include(cmake/summary.cmake REQUIRED) diff --git a/cmake/compilerFlags.cmake b/cmake/compilerFlags.cmake index ced8a21..99cc5de 100644 --- a/cmake/compilerFlags.cmake +++ b/cmake/compilerFlags.cmake @@ -1,5 +1,7 @@ include(CheckCCompilerFlag) + + set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD 11) @@ -20,3 +22,10 @@ if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) endif () endif() + +if (MSVC) + add_compile_options(/MP) + add_compile_options(/W3 /WX) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + add_definitions(-wd5105) +endif() diff --git a/cmake/summary.cmake b/cmake/summary.cmake new file mode 100644 index 0000000..8adafb5 --- /dev/null +++ b/cmake/summary.cmake @@ -0,0 +1,23 @@ +message( STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") +message( STATUS "------------------------------------------------------------------" ) +message( STATUS "CMake Generator: ${CMAKE_GENERATOR}" ) +message( STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}" ) +message( STATUS "Compiler info: ${CMAKE_C_COMPILER_ID} (${CMAKE_C_COMPILER}) ; version: ${CMAKE_C_COMPILER_VERSION}") +message( STATUS "CMAKE_C_STANDARD:${CMAKE_C_STANDARD}" ) +message( STATUS " --- Compiler flags --- ") +message( STATUS "General: ${CMAKE_C_FLAGS}" ) +message( STATUS "Extra: ${EXTRA_COMPILE_FLAGS}" ) +message( STATUS "Debug: ${CMAKE_C_FLAGS_DEBUG}" ) +message( STATUS "Release: ${CMAKE_C_FLAGS_RELEASE}" ) +message( STATUS "RelWithDebInfo: ${CMAKE_C_FLAGS_RELWITHDEBINFO}" ) +message( STATUS "MinSizeRel: ${CMAKE_C_FLAGS_MINSIZEREL}" ) +message( STATUS " --- Linker flags --- ") +message( STATUS "General: ${CMAKE_EXE_LINKER_FLAGS}" ) +message( STATUS "Debug: ${CMAKE_EXE_LINKER_FLAGS_DEBUG}" ) +message( STATUS "Release: ${CMAKE_EXE_LINKER_FLAGS_RELEASE}" ) +message( STATUS "RelWithDebInfo: ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" ) +message( STATUS "MinSizeRel: ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}" ) +message( STATUS "" ) +message( STATUS "Compiler Options") +message( STATUS "" ) +message( STATUS "------------------------------------------------------------------" ) diff --git a/test_unishox2.c b/test_unishox2.c index 809608f..b9690a3 100644 --- a/test_unishox2.c +++ b/test_unishox2.c @@ -1,8 +1,11 @@ +#include "unishox2.h" + #ifdef _MSC_VER #include #else #include #endif + #include #include #include @@ -10,8 +13,6 @@ #include #include -#include "unishox2.h" - typedef unsigned char byte; int unishox2_compress_preset_lines(const char *in, int len, char *out, int preset, struct us_lnk_lst *prev_lines) { @@ -98,12 +99,11 @@ int test_ushx_cd(char *input, int preset) { char cbuf[200]; char dbuf[250]; - int len = strlen(input); + int len = (int)strlen(input); int clen = unishox2_compress_preset_lines(input, len, cbuf, preset, NULL); printf("\n\n"); int dlen = unishox2_decompress_preset_lines(cbuf, clen, dbuf, preset, NULL); dbuf[dlen] = '\0'; - float perc; if (dlen != len) { printf("Fail len: %d, %d:\n%s\n%s\n", len, dlen, input, dbuf); return 0; @@ -112,7 +112,7 @@ int test_ushx_cd(char *input, int preset) { printf("Fail cmp:\n%s\n%s\n", input, dbuf); return 0; } - perc = (len - clen); + float perc = (float)(len - clen); perc /= len; perc *= 100; printf("%s: %d/%d=", input, clen, len); @@ -206,9 +206,9 @@ int main(int argv, char *args[]) { char cbuf[4096]; char dbuf[8192]; -long len, tot_len, ctot; -size_t clen, dlen; -float perc; +long len, tot_len, clen, ctot=0; +size_t dlen; +float perc=0.F; FILE *fp, *wfp; int bytes_read; uint32_t tStart; @@ -220,7 +220,6 @@ if (argv >= 4 && strcmp(args[1], "-c") == 0) { if (argv > 4) preset = atoi(args[4]); tot_len = 0; - ctot = 0; fp = fopen(args[2], "rb"); if (fp == NULL) { perror(args[2]); @@ -232,7 +231,7 @@ if (argv >= 4 && strcmp(args[1], "-c") == 0) { return 1; } do { - bytes_read = fread(cbuf, 1, sizeof(cbuf), fp); + bytes_read = (int)fread(cbuf, 1, sizeof(cbuf), fp); if (bytes_read > 0) { clen = unishox2_compress_preset_lines(cbuf, bytes_read, dbuf, preset, NULL); ctot += clen; @@ -240,14 +239,14 @@ if (argv >= 4 && strcmp(args[1], "-c") == 0) { if (clen > 0) { fputc(clen >> 8, wfp); fputc(clen & 0xFF, wfp); - if (clen != fwrite(dbuf, 1, clen, wfp)) { + if (clen != (long)fwrite(dbuf, 1, clen, wfp)) { perror("fwrite"); return 1; } } } } while (bytes_read > 0); - perc = (tot_len-ctot); + perc = (float)(tot_len-ctot); perc /= tot_len; perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, tot_len); @@ -271,7 +270,7 @@ if (argv >= 4 && strcmp(args[1], "-d") == 0) { //memset(dbuf, 0, sizeof(dbuf)); int len_to_read = fgetc(fp) << 8; len_to_read += fgetc(fp); - bytes_read = fread(dbuf, 1, len_to_read, fp); + bytes_read = (int)fread(dbuf, 1, len_to_read, fp); if (bytes_read > 0) { dlen = unishox2_decompress_preset_lines(dbuf, bytes_read, cbuf, preset, NULL); if (dlen > 0) { @@ -317,7 +316,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || while (fgets(cbuf, sizeof(cbuf), fp) != NULL) { // compress the line and look in previous lines // add to linked list - len = strlen(cbuf); + len = (long)strlen(cbuf); if (cbuf[len - 1] == '\n' || cbuf[len - 1] == '\r') { len--; cbuf[len] = 0; @@ -333,7 +332,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || cur_line->previous = ll; clen = unishox2_compress_preset_lines(cbuf, len, dbuf, preset, cur_line); if (clen > 0) { - perc = (len-clen); + perc = (float)(len-clen); perc /= len; perc *= 100; //print_compressed(dbuf, clen); @@ -348,7 +347,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || snprintf(short_buf, 10, "%u, ", (byte) short_buf[i]); fputs(short_buf, wfp); } - for (size_t i = 0; i < clen; i++) { + for (int i = 0; i < clen; i++) { if (i) { strcpy(short_buf, ", "); fputs(short_buf, wfp); @@ -366,7 +365,7 @@ if (argv >= 4 && (strcmp(args[1], "-g") == 0 || printf("\n%s\n", cbuf); } } - perc = (tot_len-ctot); + perc = (float)(tot_len-ctot); perc /= tot_len; perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, tot_len); @@ -632,7 +631,7 @@ if (argv == 2 || (argv == 3 && atoi(args[2]) > 0)) { int preset = 0; if (argv >= 3) preset = atoi(args[2]); - len = strlen(args[1]); + len = (long)strlen(args[1]); printf("String: %s, Len:%ld\n", args[1], len); //print_string_as_hex(args[1], len); memset(cbuf, 0, sizeof(cbuf)); @@ -643,7 +642,7 @@ if (argv == 2 || (argv == 3 && atoi(args[2]) > 0)) { dbuf[dlen] = 0; printf("\nDecompressed: %s\n", dbuf); //print_compressed(dbuf, dlen); - perc = (len-ctot); + perc = (float)(len-ctot); perc /= len; perc *= 100; printf("\nBytes (Compressed/Original=Savings%%): %ld/%ld=", ctot, len); diff --git a/unishox2.c b/unishox2.c index 2cb9baf..5d317db 100644 --- a/unishox2.c +++ b/unishox2.c @@ -300,7 +300,7 @@ int matchLine(const char *in, int len, int l, char *out, int *ol, struct us_lnk_ int j = 0; do { int i, k; - int line_len = strlen(prev_lines->data); + int line_len = (int)strlen(prev_lines->data); int limit = (line_ctr == 0 ? l : line_len); for (; j < limit; j++) { for (i = l, k = j; k < line_len && i < len; k++, i++) { @@ -503,7 +503,7 @@ int unishox2_compress_lines(const char *in, int len, char *out, const byte usx_h int i; for (i = 0; i < 5; i++) { if (usx_templates[i]) { - int rem = strlen(usx_templates[i]); + int rem = (int)strlen(usx_templates[i]); int j = 0; for (; j < rem && l + j < len; j++) { char c_t = usx_templates[i][j]; @@ -550,7 +550,7 @@ int unishox2_compress_lines(const char *in, int len, char *out, const byte usx_h if (usx_freq_seq != NULL) { int i; for (i = 0; i < 6; i++) { - int seq_len = strlen(usx_freq_seq[i]); + int seq_len = (int)strlen(usx_freq_seq[i]); if (len - seq_len >= 0 && l <= len - seq_len) { if (memcmp(usx_freq_seq[i], in + l, seq_len) == 0 && usx_hcode_lens[usx_freq_codes[i] >> 5]) { ol = append_code(out, ol, usx_freq_codes[i], &state, usx_hcodes, usx_hcode_lens); @@ -1030,7 +1030,7 @@ int unishox2_decompress_lines(const char *in, int len, char *out, const byte usx int rem = readCount(in, &bit_no, len); if (rem < 0) break; - rem = strlen(usx_templates[idx]) - rem; + rem = (int)strlen(usx_templates[idx]) - rem; for (int j = 0; j < rem; j++) { char c_t = usx_templates[idx][j]; if (c_t == 'f' || c_t == 'r' || c_t == 't' || c_t == 'o' || c_t == 'F') { @@ -1101,11 +1101,11 @@ int unishox2_decompress_lines(const char *in, int len, char *out, const byte usx } else if (h == USX_SYM && v > 24) { v -= 25; memcpy(out + ol, usx_freq_seq[v], strlen(usx_freq_seq[v])); - ol += strlen(usx_freq_seq[v]); + ol += (int)strlen(usx_freq_seq[v]); } else if (h == USX_NUM && v > 22 && v < 26) { v -= (23 - 3); memcpy(out + ol, usx_freq_seq[v], strlen(usx_freq_seq[v])); - ol += strlen(usx_freq_seq[v]); + ol += (int)strlen(usx_freq_seq[v]); } else break; // Terminator if (dstate == USX_DELTA) From cd888a7609bebfb811d7bed1cc78938e66963bbf Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Thu, 9 Sep 2021 13:21:19 +0200 Subject: [PATCH 10/15] Add library target in CMake + generate export file --- CMakeLists.txt | 16 ++++++++++++++-- unishox2.h | 18 ++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d33f4c..39044a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,12 +5,24 @@ project(Unixshox LANGUAGES C ) +include(GenerateExportHeader) include(cmake/compilerFlags.cmake REQUIRED) -add_executable(unishox - unishox2.c +set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) + +include_directories(${CMAKE_BINARY_DIR}) + +add_library(unishox unishox2.h + unishox2.c +) + +generate_export_header(unishox) + +add_executable(unishox_cli test_unishox2.c ) +target_link_libraries(unishox_cli PRIVATE unishox) include(cmake/summary.cmake REQUIRED) diff --git a/unishox2.h b/unishox2.h index 604b2d1..4385bc5 100644 --- a/unishox2.h +++ b/unishox2.h @@ -19,6 +19,8 @@ #ifndef unishox2 #define unishox2 +#include "unishox_export.h" + #define UNISHOX_VERSION "2.0" //enum {USX_ALPHA = 0, USX_SYM, USX_NUM, USX_DICT, USX_DELTA}; @@ -88,19 +90,19 @@ struct us_lnk_lst { struct us_lnk_lst *previous; }; -extern int unishox2_compress_simple(const char *in, int len, char *out); -extern int unishox2_decompress_simple(const char *in, int len, char *out); -extern int unishox2_compress(const char *in, int len, char *out, - const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], +UNISHOX_EXPORT int unishox2_compress_simple(const char *in, int len, char *out); +UNISHOX_EXPORT int unishox2_decompress_simple(const char *in, int len, char *out); +UNISHOX_EXPORT int unishox2_compress(const char *in, int len, char *out, + const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]); -extern int unishox2_decompress(const char *in, int len, char *out, +UNISHOX_EXPORT int unishox2_decompress(const char *in, int len, char *out, const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[]); -extern int unishox2_compress_lines(const char *in, int len, char *out, - const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], +UNISHOX_EXPORT int unishox2_compress_lines(const char *in, int len, char *out, + const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines); -extern int unishox2_decompress_lines(const char *in, int len, char *out, +UNISHOX_EXPORT int unishox2_decompress_lines(const char *in, int len, char *out, const unsigned char usx_hcodes[], const unsigned char usx_hcode_lens[], const char *usx_freq_seq[], const char *usx_templates[], struct us_lnk_lst *prev_lines); From a5da71c359de42ba8b888b746bb0bcae7485b448 Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Thu, 9 Sep 2021 13:41:35 +0200 Subject: [PATCH 11/15] Installation of library with cmake --- CMakeLists.txt | 29 +++++++++++++++++++++++++++++ cmake/summary.cmake | 5 ++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39044a2..6af398d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,9 +3,14 @@ cmake_policy(SET CMP0092 NEW) project(Unixshox LANGUAGES C + VERSION 2.0.0 ) +include(GNUInstallDirs) +include(WriteBasicConfigVersionFile) +include(CMakePackageConfigHelpers) include(GenerateExportHeader) + include(cmake/compilerFlags.cmake REQUIRED) set(CMAKE_CXX_VISIBILITY_PRESET hidden) @@ -20,6 +25,30 @@ add_library(unishox generate_export_header(unishox) +# -------------------------------------------------------------------- +# Install rules for C library +# -------------------------------------------------------------------- + +write_basic_package_version_file(unishoxConfigVersion.cmake COMPATIBILITY ExactVersion) + +install(TARGETS unishox EXPORT unishoxConfig + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/unishox/ +) + +install(FILES ${PROJECT_BINARY_DIR}/unishox_export.h unishox2.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/unishox) + +install(EXPORT unishoxConfig DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/unishox") + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/unishoxConfigVersion.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/unishox") + +# -------------------------------------------------------------------- +# Test CLI application +# -------------------------------------------------------------------- + add_executable(unishox_cli test_unishox2.c ) diff --git a/cmake/summary.cmake b/cmake/summary.cmake index 8adafb5..bfaf120 100644 --- a/cmake/summary.cmake +++ b/cmake/summary.cmake @@ -3,7 +3,7 @@ message( STATUS "--------------------------------------------------------------- message( STATUS "CMake Generator: ${CMAKE_GENERATOR}" ) message( STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}" ) message( STATUS "Compiler info: ${CMAKE_C_COMPILER_ID} (${CMAKE_C_COMPILER}) ; version: ${CMAKE_C_COMPILER_VERSION}") -message( STATUS "CMAKE_C_STANDARD:${CMAKE_C_STANDARD}" ) +message( STATUS "CMAKE_C_STANDARD: ${CMAKE_C_STANDARD}" ) message( STATUS " --- Compiler flags --- ") message( STATUS "General: ${CMAKE_C_FLAGS}" ) message( STATUS "Extra: ${EXTRA_COMPILE_FLAGS}" ) @@ -18,6 +18,5 @@ message( STATUS "Release: ${CMAKE_EXE_LINKER_FLAGS_RELEASE}" ) message( STATUS "RelWithDebInfo: ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" ) message( STATUS "MinSizeRel: ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}" ) message( STATUS "" ) -message( STATUS "Compiler Options") -message( STATUS "" ) +message( STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}" ) message( STATUS "------------------------------------------------------------------" ) From 2e4fc991b40344fd77235dcaed04a9c33dd031df Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Mon, 13 Sep 2021 10:07:17 +0200 Subject: [PATCH 12/15] CMake Config file now exports inclusion directories --- .gitignore | 3 +++ CMakeLists.txt | 4 ++++ cmake/summary.cmake | 1 + 3 files changed, 8 insertions(+) diff --git a/.gitignore b/.gitignore index 02f0ca8..2f2737c 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ delta_only # Traditional cmake building directories build* + +# QtCreator temporary files +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 6af398d..20f9f63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,10 @@ generate_export_header(unishox) # -------------------------------------------------------------------- # Install rules for C library # -------------------------------------------------------------------- +# Use include/unishox to build libary code +target_include_directories(unishox PUBLIC + $ +) write_basic_package_version_file(unishoxConfigVersion.cmake COMPATIBILITY ExactVersion) diff --git a/cmake/summary.cmake b/cmake/summary.cmake index bfaf120..a028f6a 100644 --- a/cmake/summary.cmake +++ b/cmake/summary.cmake @@ -19,4 +19,5 @@ message( STATUS "RelWithDebInfo: ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}" ) message( STATUS "MinSizeRel: ${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL}" ) message( STATUS "" ) message( STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}" ) +message( STATUS "BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}" ) message( STATUS "------------------------------------------------------------------" ) From a78accc0768c6d1c0b81e06c99037f5fa2860873 Mon Sep 17 00:00:00 2001 From: Luis Diaz Date: Mon, 13 Sep 2021 11:13:02 +0200 Subject: [PATCH 13/15] CI: update workflow to use cmake --- .github/workflows/c-cpp.yml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 7f75963..e8e5f17 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -13,7 +13,24 @@ jobs: steps: - uses: actions/checkout@v2 - - name: make - run: make - - name: test - run: ./test_unishox2 -t + + - name: Configure Project + run: | + mkdir buildRelease && cd buildRelease + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install .. + + - name: Compile project + run: | + cd buildRelease + cmake --build . + + - name: Install library + run: | + cd buildRelease + cmake --build . --target install + tree install + + - name: Test with CLI app + run: | + cd buildRelease + ./unishox_cli -t From f36347484f505a108b11a9e972b5660495ad9173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Mon, 13 Sep 2021 11:22:24 +0200 Subject: [PATCH 14/15] CI: require cmake version available in ubuntu 20.04 --- .github/workflows/c-cpp.yml | 1 + CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index e8e5f17..3848f25 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -16,6 +16,7 @@ jobs: - name: Configure Project run: | + cmake --version mkdir buildRelease && cd buildRelease cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 20f9f63..8aec263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0092 NEW) project(Unixshox From f85725721523827fa3309ceca8eb91253aef9423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20D=C3=ADaz=20M=C3=A1s?= Date: Mon, 13 Sep 2021 11:31:26 +0200 Subject: [PATCH 15/15] Do not treat as error stringop-truncation --- .gitignore | 3 +++ cmake/compilerFlags.cmake | 1 + 2 files changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 2f2737c..35d756c 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,6 @@ build* # QtCreator temporary files CMakeLists.txt.user + +# Vim temporary files +*.swp diff --git a/cmake/compilerFlags.cmake b/cmake/compilerFlags.cmake index 99cc5de..21f47d4 100644 --- a/cmake/compilerFlags.cmake +++ b/cmake/compilerFlags.cmake @@ -15,6 +15,7 @@ if (COMPILER_IS_GCC OR COMPILER_IS_CLANG) add_compile_options(-Werror) add_compile_options(-Wall -Wcast-align -Wpointer-arith -Wformat-security -Wmissing-format-attribute -W) add_compile_options(-Wno-error=format-nonliteral) + add_compile_options(-Wno-error=stringop-truncation) check_c_compiler_flag(-Wdeprecated-copy DEPRECATED_COPY) if ( DEPRECATED_COPY)