From 26dec498cf1bae39f4842e93b8bfe4d10b0395e9 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 07:13:49 -0700 Subject: small compression speed improvement on 64-bits systems --- NEWS | 4 +++- lib/lz4.c | 17 +++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index b676d86..f98f2c7 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,12 @@ v1.7.2 Changed : moved to versioning; package, cli and library have same version number -Improved: Small decompression speed boost (+4%) +Improved: Small decompression speed boost +Improved: Small compression speed improvement on 64-bits systems Improved: Performance on ARMv6 and ARMv7 Added : Debianization, by Evgeniy Polyakov Makefile: Generates object files (*.o) for faster (re)compilation on low power systems Fix : cli : crash on some invalid inputs +Fix : cli : -t correctly validates lz4-compressed files, by Nick Terrell r131 New : Dos/DJGPP target, thanks to Louis Santillan (#114) diff --git a/lib/lz4.c b/lib/lz4.c index 6a6aaf2..0777d5e 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -415,27 +415,28 @@ int LZ4_sizeofState() { return LZ4_STREAMSIZE; } static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) { if (tableType == byU16) - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } static const U64 prime5bytes = 889523592379ULL; -static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) +static U32 LZ4_hashSequence64(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - const U32 hashMask = (1<> (40 - hashLog)) & hashMask; + return ((sequence << 24) * prime5bytes) >> (64 - hashLog); } static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) { - if (LZ4_64bits()) - return LZ4_hashSequence64(sequence, tableType); + if (LZ4_64bits()) return LZ4_hashSequence64(sequence, tableType); return LZ4_hashSequence((U32)sequence, tableType); } -static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); } +static U32 LZ4_hashPosition(const void* p, tableType_t tableType) +{ + return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); +} static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { -- cgit v0.12 From f878c08b76a58e083c47470284139f3006c8e746 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 07:22:50 -0700 Subject: better correctness on big-endian 64-bits platforms --- NEWS | 1 + lib/lz4.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index f98f2c7..7bfa3c5 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ Added : Debianization, by Evgeniy Polyakov Makefile: Generates object files (*.o) for faster (re)compilation on low power systems Fix : cli : crash on some invalid inputs Fix : cli : -t correctly validates lz4-compressed files, by Nick Terrell +Fix : better ratio on 64-bits big-endian targets r131 New : Dos/DJGPP target, thanks to Louis Santillan (#114) diff --git a/lib/lz4.c b/lib/lz4.c index 0777d5e..b935b76 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -420,11 +420,15 @@ static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -static const U64 prime5bytes = 889523592379ULL; static U32 LZ4_hashSequence64(U64 sequence, tableType_t const tableType) { + static const U64 prime5bytes = 889523592379ULL; + static const U64 prime8bytes = 11400714785074694791ULL; const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - return ((sequence << 24) * prime5bytes) >> (64 - hashLog); + if (LZ4_isLittleEndian()) + return ((sequence << 24) * prime5bytes) >> (64 - hashLog); + else + return ((sequence >> 24) * prime8bytes) >> (64 - hashLog); } static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) -- cgit v0.12 From 374090c7a760a839f2ee1701620d834d1d6ae724 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 4 Nov 2016 11:58:10 -0700 Subject: Return error if input file does not exist. Make `lz4 file-does-not-exist` return non-zero. --- programs/lz4cli.c | 4 ++-- tests/Makefile | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/programs/lz4cli.c b/programs/lz4cli.c index a6f4b4e..f77be3d 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -550,7 +550,7 @@ int main(int argc, const char** argv) if (multiple_inputs) operationResult = LZ4IO_decompressMultipleFilenames(inFileNames, ifnIdx, LZ4_EXTENSION); else - DEFAULT_DECOMPRESSOR(input_filename, output_filename); + operationResult = DEFAULT_DECOMPRESSOR(input_filename, output_filename); } else { /* compression is default action */ if (legacy_format) { @@ -560,7 +560,7 @@ int main(int argc, const char** argv) if (multiple_inputs) operationResult = LZ4IO_compressMultipleFilenames(inFileNames, ifnIdx, LZ4_EXTENSION, cLevel); else - DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel); + operationResult = DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel); } } diff --git a/tests/Makefile b/tests/Makefile index 0c44b21..bfbafd8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -221,6 +221,11 @@ test-lz4: lz4 datagen test-lz4-basic test-lz4-multiple test-lz4-sparse test-lz4- ./datagen | $(PRGDIR)/lz4 -tf && false || true ./datagen | $(PRGDIR)/lz4 -d > $(VOID) && false || true ./datagen | $(PRGDIR)/lz4 -df > $(VOID) + @echo "\n ---- test cli ----" + $(PRGDIR)/lz4 file-does-not-exist && false || true + $(PRGDIR)/lz4 -f file-does-not-exist && false || true + $(PRGDIR)/lz4 -fm file1-dne file2-dne && false || true + $(PRGDIR)/lz4 -fm file1-dne file2-dne && false || true test-lz4c: lz4c datagen @echo "\n ---- test lz4c version ----" -- cgit v0.12 From f30c56c08315250cf4263b13ab4bc83e482f581e Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 4 Nov 2016 12:34:28 -0700 Subject: Quiet gcc-4.6.3 narrowing warning --- lib/lz4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/lz4.c b/lib/lz4.c index b935b76..6db4c0b 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -426,9 +426,9 @@ static U32 LZ4_hashSequence64(U64 sequence, tableType_t const tableType) static const U64 prime8bytes = 11400714785074694791ULL; const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; if (LZ4_isLittleEndian()) - return ((sequence << 24) * prime5bytes) >> (64 - hashLog); + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); else - return ((sequence >> 24) * prime8bytes) >> (64 - hashLog); + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) -- cgit v0.12 From 86a24c80f4689fd88c48849c53eb0f0f4de4e5d7 Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 4 Nov 2016 12:46:39 -0700 Subject: Fix typo in lz4 manpage --- programs/lz4.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/lz4.1 b/programs/lz4.1 index 51a37f1..059b820 100644 --- a/programs/lz4.1 +++ b/programs/lz4.1 @@ -121,7 +121,7 @@ Decompress. .B --decompress is also the default operation when the input filename has an .B .lz4 -extensionq +extension. .TP .BR \-t ", " \-\-test Test the integrity of compressed -- cgit v0.12 From 079d5dd54b763a0f1bf7aae14f7ff4852c358d8e Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 16:29:43 -0700 Subject: removed support for old error code enums from lz4frame_static.h, to free up namespace. note : lz4frame_static.h does not guaranteed API stability. note 2 : the macro to enable old error code enums is still present. Just needs to comment one line to re-enable them. --- lib/lz4frame_static.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lz4frame_static.h b/lib/lz4frame_static.h index fab3def..0c154a3 100644 --- a/lib/lz4frame_static.h +++ b/lib/lz4frame_static.h @@ -64,7 +64,7 @@ extern "C" { ITEM(ERROR_headerChecksum_invalid) ITEM(ERROR_contentChecksum_invalid) \ ITEM(ERROR_maxCode) -//#define LZ4F_DISABLE_OLD_ENUMS /* uncomment to disable deprecated enums */ +#define LZ4F_DISABLE_OLD_ENUMS /* comment to enable deprecated enums */ #ifndef LZ4F_DISABLE_OLD_ENUMS # define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM, ENUM = LZ4F_##ENUM, #else -- cgit v0.12 From eaad740ac7267428b03ae19c7051e615ec507bda Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 16:58:34 -0700 Subject: lz4frame obsolete enum should trigger deprecation warnings (on supported compilers) --- lib/lz4frame.h | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 63abc60..08d1895 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -45,13 +45,11 @@ extern "C" { #endif -/*-************************************ -* Dependency -**************************************/ +/* --- Dependency --- */ #include /* size_t */ /*-*************************************************************** -* Export parameters +* Compiler specifics *****************************************************************/ /*! * LZ4_DLL_EXPORT : @@ -67,6 +65,15 @@ extern "C" { # define LZ4FLIB_API #endif +#if defined(_MSC_VER) +# define LZ4F_DEPRECATE(x) __declspec(deprecated) x +#elif defined(__GNUC__) +# define LZ4F_DEPRECATE(x) x __attribute__((deprecated)) +#else +# define LZ4F_DEPRECATE(x) x /* no deprecation warning for this compiler */ +#endif + + /*-************************************ * Error management **************************************/ @@ -81,7 +88,7 @@ LZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return er **************************************/ /* #define LZ4F_DISABLE_OBSOLETE_ENUMS */ /* uncomment to disable obsolete enums */ #ifndef LZ4F_DISABLE_OBSOLETE_ENUMS -# define LZ4F_OBSOLETE_ENUM(x) ,x +# define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x #else # define LZ4F_OBSOLETE_ENUM(x) #endif @@ -92,30 +99,30 @@ typedef enum { LZ4F_max256KB=5, LZ4F_max1MB=6, LZ4F_max4MB=7 - LZ4F_OBSOLETE_ENUM(max64KB = LZ4F_max64KB) - LZ4F_OBSOLETE_ENUM(max256KB = LZ4F_max256KB) - LZ4F_OBSOLETE_ENUM(max1MB = LZ4F_max1MB) - LZ4F_OBSOLETE_ENUM(max4MB = LZ4F_max4MB) + LZ4F_OBSOLETE_ENUM(max64KB) + LZ4F_OBSOLETE_ENUM(max256KB) + LZ4F_OBSOLETE_ENUM(max1MB) + LZ4F_OBSOLETE_ENUM(max4MB) } LZ4F_blockSizeID_t; typedef enum { LZ4F_blockLinked=0, LZ4F_blockIndependent - LZ4F_OBSOLETE_ENUM(blockLinked = LZ4F_blockLinked) - LZ4F_OBSOLETE_ENUM(blockIndependent = LZ4F_blockIndependent) + LZ4F_OBSOLETE_ENUM(blockLinked) + LZ4F_OBSOLETE_ENUM(blockIndependent) } LZ4F_blockMode_t; typedef enum { LZ4F_noContentChecksum=0, LZ4F_contentChecksumEnabled - LZ4F_OBSOLETE_ENUM(noContentChecksum = LZ4F_noContentChecksum) - LZ4F_OBSOLETE_ENUM(contentChecksumEnabled = LZ4F_contentChecksumEnabled) + LZ4F_OBSOLETE_ENUM(noContentChecksum) + LZ4F_OBSOLETE_ENUM(contentChecksumEnabled) } LZ4F_contentChecksum_t; typedef enum { LZ4F_frame=0, LZ4F_skippableFrame - LZ4F_OBSOLETE_ENUM(skippableFrame = LZ4F_skippableFrame) + LZ4F_OBSOLETE_ENUM(skippableFrame) } LZ4F_frameType_t; #ifndef LZ4F_DISABLE_OBSOLETE_ENUMS -- cgit v0.12 From 96565816bd38632e47bc70b76548b0f3c99c3b27 Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 17:11:06 -0700 Subject: restricted deprecation warning to fairly recent gcc versions (>=6.0) --- lib/lz4frame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 08d1895..63d61ad 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -67,7 +67,7 @@ extern "C" { #if defined(_MSC_VER) # define LZ4F_DEPRECATE(x) __declspec(deprecated) x -#elif defined(__GNUC__) +#elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6)) # define LZ4F_DEPRECATE(x) x __attribute__((deprecated)) #else # define LZ4F_DEPRECATE(x) x /* no deprecation warning for this compiler */ -- cgit v0.12 From 8195ba8f7bbf0153a1dc01d2ada8823a29462afa Mon Sep 17 00:00:00 2001 From: Yann Collet Date: Fri, 4 Nov 2016 18:29:07 -0700 Subject: Updated man page --- programs/README.md | 12 ++++++------ programs/lz4.1 | 33 ++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/programs/README.md b/programs/README.md index 7a5d2e2..b67408f 100644 --- a/programs/README.md +++ b/programs/README.md @@ -2,20 +2,20 @@ Command Line Interface for LZ4 library ============================================ Command Line Interface (CLI) can be created using the `make` command without any additional parameters. -There are however other Makefile targets that create different variations of CLI: -- `lz4` : default CLI supporting gzip-like arguments -- `lz4c` : Same as `lz4` with additional support for decompression of legacy lz4 versions +There are also multiple targets that create different variations of CLI: +- `lz4` : default CLI, with a command line syntax close to gzip +- `lz4c` : Same as `lz4` with additional support legacy lz4 commands (incompatible with gzip) - `lz4c32` : Same as `lz4c`, but forced to compile in 32-bits mode #### Aggregation of parameters -CLI supports aggregation of parameters i.e. `-b1`, `-e18`, and `-i1` can be joined into `-b1e18i1`. +CLI supports aggregation of parameters i.e. `-b1`, `-e18`, and `-i1` can be joined into `-b1e18i1`. #### Benchmark in Command Line Interface CLI includes in-memory compression benchmark module for lz4. -The benchmark is conducted using a given filename. +The benchmark is conducted using a given filename. The file is read into memory. It makes benchmark more precise as it eliminates I/O overhead. @@ -26,7 +26,7 @@ The `-i` parameter selects a number of iterations used for each of tested levels #### Usage of Command Line Interface -The full list of options can be obtained with `-h` or `-H` parameter: +The full list of commands can be obtained with `-h` or `-H` parameter: ``` Usage : lz4 [arg] [input] [output] diff --git a/programs/lz4.1 b/programs/lz4.1 index 059b820..529d36a 100644 --- a/programs/lz4.1 +++ b/programs/lz4.1 @@ -50,12 +50,16 @@ The native file format is the format. .B lz4 -supports a command line syntax similar but not identical to +supports a command line syntax similar \fIbut not identical\fR to .BR gzip (1). Differences are : -\fBlz4\fR preserve original files ; -\fBlz4 file1 file2\fR means : compress file1 \fIinto\fR file2 ; -\fBlz4 file\fR shows real-time statistics during compression . + \fBlz4\fR preserves original files + \fBlz4\fR compresses a single file by default (use \fB-m\fR for multiple files) + \fBlz4 file1 file2\fR means : compress file1 \fIinto\fR file2 + When no destination name is provided, compressed file name receives a \fB.lz4\fR suffix + When no destination name is provided, if \fBstdout\fR is \fInot\fR the console, it becomes the output (like a silent \fB-c\fR) + Therefore \fBlz4 file > /dev/null\fR will not create \fBfile.lz4\fR + \fBlz4 file\fR shows real-time statistics during compression (use \fB-q\fR to silent them) Default behaviors can be modified by opt-in commands, described below. \fBlz4 --quiet --multiple\fR more closely mimics \fBgzip\fR behavior. @@ -129,6 +133,11 @@ Test the integrity of compressed files. The decompressed data is discarded. No files are created nor removed. + +.TP +.BR \-b# +Benchmark mode, using # compression level. + . .SS "Operation modifiers" .TP @@ -215,12 +224,22 @@ hence for a file. It won't work with unknown source size, such as stdin or pipe. .BR \-k ", " \--keep Don't delete source file. This is default behavior anyway, so this option is just for compatibility with gzip/xz. + +. +.SS "Benchmark mode" +.TP +.B \-b# + benchmark file(s), using # compression level .TP -.B \-b - benchmark file(s) +.B \-e# + benchmark multiple compression levels, from b# to e# (included) .TP .B \-i# - iteration loops [1-9](default : 3), benchmark mode only + minimum evaluation in seconds [1-9] (default : 3) +.TP +.B \-r + operate recursively on directories + .SH BUGS Report bugs at: https://github.com/Cyan4973/lz4/issues -- cgit v0.12 From 920bf21714f99cc20d3b8bcc28060136a390354a Mon Sep 17 00:00:00 2001 From: Nick Terrell Date: Fri, 4 Nov 2016 19:59:50 -0700 Subject: Fix LZ4_decompress_fast_continue() bug It specified the external dictionary location incorrectly. Add tests that expose this bug with both normal compilation and ASAN. --- lib/lz4.c | 2 +- tests/Makefile | 8 +++- tests/fasttest.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 tests/fasttest.c diff --git a/lib/lz4.c b/lib/lz4.c index 6db4c0b..740ae64 100644 --- a/lib/lz4.c +++ b/lib/lz4.c @@ -1366,7 +1366,7 @@ int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const ch lz4sd->prefixEnd += originalSize; } else { lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize; + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); diff --git a/tests/Makefile b/tests/Makefile index 0dd8a59..2da6408 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -97,6 +97,9 @@ frametest: $(LZ4DIR)/lz4frame.o $(LZ4DIR)/lz4.o $(LZ4DIR)/lz4hc.o $(LZ4DIR)/xxha frametest32: $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c frametest.c $(CC) -m32 $(FLAGS) $^ -o $@$(EXT) +fasttest: $(LZ4DIR)/lz4.o fasttest.c + $(CC) $(FLAGS) $^ -o $@$(EXT) + datagen : $(PRGDIR)/datagen.c datagencli.c $(CC) $(FLAGS) -I$(PRGDIR) $^ -o $@$(EXT) @@ -119,7 +122,7 @@ versionsTest: #FreeBSD targets ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD)) -test: test-lz4 test-lz4c test-frametest test-fullbench test-fuzzer test-mem +test: test-lz4 test-lz4c test-fasttest test-frametest test-fullbench test-fuzzer test-mem test32: test-lz4c32 test-frametest32 test-fullbench32 test-fuzzer32 test-mem32 @@ -267,6 +270,9 @@ test-frametest: frametest test-frametest32: frametest32 ./frametest32 $(FUZZER_TIME) +test-fasttest: fasttest + ./fasttest + test-mem: lz4 datagen fuzzer frametest fullbench @echo "\n ---- valgrind tests : memory analyzer ----" valgrind --leak-check=yes --error-exitcode=1 ./datagen -g50M > $(VOID) diff --git a/tests/fasttest.c b/tests/fasttest.c new file mode 100644 index 0000000..a405542 --- /dev/null +++ b/tests/fasttest.c @@ -0,0 +1,138 @@ +/************************************** + * Compiler Options + **************************************/ +#ifdef _MSC_VER /* Visual Studio */ +# define _CRT_SECURE_NO_WARNINGS // for MSVC +# define snprintf sprintf_s +#endif +#ifdef __GNUC__ +# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */ +#endif + + +/************************************** + * Includes + **************************************/ +#include +#include +#include +#include +#include "lz4.h" + + +/* Returns non-zero on failure. */ +int test_compress(const char *input, int inSize, char *output, int outSize) +{ + LZ4_stream_t lz4Stream_body = { 0 }; + LZ4_stream_t* lz4Stream = &lz4Stream_body; + + int inOffset = 0; + int outOffset = 0; + + if (inSize & 3) return -1; + + while (inOffset < inSize) { + const int length = inSize >> 2; + if (inSize > 1024) return -2; + if (outSize - (outOffset + 8) < LZ4_compressBound(length)) return -3; + { + const int outBytes = LZ4_compress_continue( + lz4Stream, input + inOffset, output + outOffset + 8, length); + if(outBytes <= 0) return -4; + memcpy(output + outOffset, &length, 4); /* input length */ + memcpy(output + outOffset + 4, &outBytes, 4); /* output length */ + inOffset += length; + outOffset += outBytes + 8; + } + } + if (outOffset + 8 > outSize) return -5; + memset(output + outOffset, 0, 4); + memset(output + outOffset + 4, 0, 4); + return 0; +} + +void swap(void **a, void **b) { + void *tmp = *a; + *a = *b; + *b = tmp; +} + +/* Returns non-zero on failure. Not a safe function. */ +int test_decompress(const char *uncompressed, const char *compressed) +{ + char outBufferA[1024]; + char spacing; /* So prefixEnd != dest */ + char outBufferB[1024]; + char *output = outBufferA; + char *lastOutput = outBufferB; + LZ4_streamDecode_t lz4StreamDecode_body = { 0 }; + LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body; + int offset = 0; + int unOffset = 0; + int lastBytes = 0; + + (void)spacing; + + for(;;) { + int32_t bytes; + int32_t unBytes; + /* Read uncompressed size and compressed size */ + memcpy(&unBytes, compressed + offset, 4); + memcpy(&bytes, compressed + offset + 4, 4); + offset += 8; + /* Check if we reached end of stream or error */ + if(bytes == 0 && unBytes == 0) return 0; + if(bytes <= 0 || unBytes <= 0 || unBytes > 1024) return 1; + + /* Put the last output in the dictionary */ + LZ4_setStreamDecode(lz4StreamDecode, lastOutput, lastBytes); + /* Decompress */ + bytes = LZ4_decompress_fast_continue( + lz4StreamDecode, compressed + offset, output, unBytes); + if(bytes <= 0) return 2; + /* Check result */ + { + int r = memcmp(uncompressed + unOffset, output, unBytes); + if (r) return 3; + } + swap((void**)&output, (void**)&lastOutput); + offset += bytes; + unOffset += unBytes; + lastBytes = unBytes; + } +} + + +int main(int argc, char **argv) +{ + char input[] = + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello!" + "Hello Hello Hello Hello Hello Hello Hello Hello"; + char output[LZ4_COMPRESSBOUND(4096)]; + int r; + + (void)argc; + (void)argv; + + if ((r = test_compress(input, sizeof(input), output, sizeof(output)))) { + return r; + } + if ((r = test_decompress(input, output))) { + return r; + } + return 0; +} -- cgit v0.12