summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYann Collet <Cyan4973@users.noreply.github.com>2017-05-11 21:54:00 (GMT)
committerGitHub <noreply@github.com>2017-05-11 21:54:00 (GMT)
commit5c97cdfa0db69aa2b22a0abc8fd7cf0d18698fef (patch)
treea0c31a6b1334168c685168de35116ee7e5d0d9cd
parenta8dd86d93e963edd6761936377dff21b45016156 (diff)
parent2600a154bebdf79637e289ed19e53e2c72a168d7 (diff)
downloadlz4-5c97cdfa0db69aa2b22a0abc8fd7cf0d18698fef.zip
lz4-5c97cdfa0db69aa2b22a0abc8fd7cf0d18698fef.tar.gz
lz4-5c97cdfa0db69aa2b22a0abc8fd7cf0d18698fef.tar.bz2
Merge pull request #352 from lz4/resetDCtx
Reset decompression context
-rw-r--r--Makefile99
-rw-r--r--contrib/gen_manual/.gitignore2
-rw-r--r--contrib/gen_manual/Makefile26
-rw-r--r--doc/lz4_manual.html18
-rw-r--r--doc/lz4frame_manual.html72
-rw-r--r--lib/Makefile13
-rw-r--r--lib/lz4.h4
-rw-r--r--lib/lz4frame.c200
-rw-r--r--lib/lz4frame.h8
-rw-r--r--lib/lz4frame_static.h9
-rw-r--r--lib/lz4hc.c42
-rw-r--r--programs/Makefile26
-rw-r--r--tests/frametest.c48
13 files changed, 321 insertions, 246 deletions
diff --git a/Makefile b/Makefile
index 1f5165d..b31ebd0 100644
--- a/Makefile
+++ b/Makefile
@@ -52,36 +52,39 @@ EXT =
endif
-.PHONY: default all lib lz4 clean test versionsTest examples
+.PHONY: default
+default: lib lz4-release
-default:
- @$(MAKE) -C $(LZ4DIR)
- @$(MAKE) -C $(PRGDIR)
- @cp $(PRGDIR)/lz4$(EXT) .
+.PHONY: all
+all: allmost manuals
-all:
- @$(MAKE) -C $(LZ4DIR) $@
- @$(MAKE) -C $(PRGDIR) $@
- @$(MAKE) -C $(TESTDIR) $@
- @$(MAKE) -C $(EXDIR) $@
+.PHONY: allmost
+allmost: lib lz4 examples
+.PHONY: lib
lib:
@$(MAKE) -C $(LZ4DIR)
-lz4:
+.PHONY: lz4 lz4-release
+lz4 lz4-release: lib
@$(MAKE) -C $(PRGDIR) $@
@cp $(PRGDIR)/lz4$(EXT) .
-lz4-release:
- @$(MAKE) -C $(PRGDIR)
- @cp $(PRGDIR)/lz4$(EXT) .
+.PHONY: examples
+examples: lib lz4
+ $(MAKE) -C $(EXDIR) test
+
+.PHONY: manuals
+manuals:
+ @$(MAKE) -C contrib/gen_manual $@
+.PHONY: clean
clean:
+ @$(MAKE) -C $(LZ4DIR) $@ > $(VOID)
@$(MAKE) -C $(PRGDIR) $@ > $(VOID)
@$(MAKE) -C $(TESTDIR) $@ > $(VOID)
- @$(MAKE) -C $(LZ4DIR) $@ > $(VOID)
@$(MAKE) -C $(EXDIR) $@ > $(VOID)
- @$(MAKE) -C examples $@ > $(VOID)
+ @$(MAKE) -C contrib/gen_manual $@
@$(RM) lz4$(EXT)
@echo Cleaning completed
@@ -92,17 +95,35 @@ clean:
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU OpenBSD FreeBSD NetBSD DragonFly SunOS))
HOST_OS = POSIX
-install:
- @$(MAKE) -C $(LZ4DIR) $@
- @$(MAKE) -C $(PRGDIR) $@
-
-uninstall:
+install uninstall:
@$(MAKE) -C $(LZ4DIR) $@
@$(MAKE) -C $(PRGDIR) $@
travis-install:
$(MAKE) -j1 install PREFIX=~/install_test_dir
+cmake:
+ @cd contrib/cmake_unofficial; cmake $(CMAKE_PARAMS) CMakeLists.txt; $(MAKE)
+
+endif
+
+
+ifneq (,$(filter MSYS%,$(shell uname)))
+HOST_OS = MSYS
+CMAKE_PARAMS = -G"MSYS Makefiles"
+endif
+
+
+#------------------------------------------------------------------------
+#make tests validated only for MSYS, Linux, OSX, kFreeBSD and Hurd targets
+#------------------------------------------------------------------------
+ifneq (,$(filter $(HOST_OS),MSYS POSIX))
+
+.PHONY: list
+list:
+ @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
+
+.PHONY: test
test:
$(MAKE) -C $(TESTDIR) $@
@@ -135,31 +156,10 @@ platformTest: clean
CFLAGS="-O3 -Werror -static" $(MAKE) -C $(TESTDIR) all
$(MAKE) -C $(TESTDIR) test-platform
+.PHONY: versionsTest
versionsTest: clean
$(MAKE) -C $(TESTDIR) $@
-examples:
- $(MAKE) -C $(LZ4DIR)
- $(MAKE) -C $(PRGDIR) lz4
- $(MAKE) -C examples test
-
-endif
-
-
-ifneq (,$(filter MSYS%,$(shell uname)))
-HOST_OS = MSYS
-CMAKE_PARAMS = -G"MSYS Makefiles"
-endif
-
-
-#------------------------------------------------------------------------
-#make tests validated only for MSYS, Linux, OSX, kFreeBSD and Hurd targets
-#------------------------------------------------------------------------
-ifneq (,$(filter $(HOST_OS),MSYS POSIX))
-
-cmake:
- @cd contrib/cmake_unofficial; cmake $(CMAKE_PARAMS) CMakeLists.txt; $(MAKE)
-
gpptest: clean
g++ -v
CC=g++ $(MAKE) -C $(LZ4DIR) all CFLAGS="-O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror"
@@ -173,13 +173,10 @@ gpptest32: clean
CC=g++ $(MAKE) -C $(TESTDIR) native CFLAGS="-m32 -O3 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Werror"
c_standards: clean
- $(MAKE) all MOREFLAGS="-std=gnu90 -Werror"
- $(MAKE) clean
- $(MAKE) all MOREFLAGS="-std=c99 -Werror"
- $(MAKE) clean
- $(MAKE) all MOREFLAGS="-std=gnu99 -Werror"
- $(MAKE) clean
- $(MAKE) all MOREFLAGS="-std=c11 -Werror"
- $(MAKE) clean
+ # note : lz4 is not C90 compatible, because it requires long long support
+ CFLAGS="-std=gnu90 -Werror" $(MAKE) clean allmost
+ CFLAGS="-std=c99 -Werror" $(MAKE) clean allmost
+ CFLAGS="-std=gnu99 -Werror" $(MAKE) clean allmost
+ CFLAGS="-std=c11 -Werror" $(MAKE) clean allmost
endif
diff --git a/contrib/gen_manual/.gitignore b/contrib/gen_manual/.gitignore
new file mode 100644
index 0000000..6ea967f
--- /dev/null
+++ b/contrib/gen_manual/.gitignore
@@ -0,0 +1,2 @@
+# build artefact
+gen_manual
diff --git a/contrib/gen_manual/Makefile b/contrib/gen_manual/Makefile
index adbcca2..9fbe858 100644
--- a/contrib/gen_manual/Makefile
+++ b/contrib/gen_manual/Makefile
@@ -35,7 +35,15 @@ CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -W
CFLAGS += $(MOREFLAGS)
FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
-
+LZ4API = ../../lib/lz4.h
+LZ4MANUAL = ../../doc/lz4_manual.html
+LZ4FAPI = ../../lib/lz4frame.h
+LZ4FMANUAL = ../../doc/lz4frame_manual.html
+LIBVER_MAJOR_SCRIPT:=`sed -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LZ4API)`
+LIBVER_MINOR_SCRIPT:=`sed -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LZ4API)`
+LIBVER_PATCH_SCRIPT:=`sed -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < $(LZ4API)`
+LIBVER_SCRIPT:= $(LIBVER_MAJOR_SCRIPT).$(LIBVER_MINOR_SCRIPT).$(LIBVER_PATCH_SCRIPT)
+LZ4VER := $(shell echo $(LIBVER_SCRIPT))
# Define *.exe as extension for Windows systems
ifneq (,$(filter Windows%,$(OS)))
@@ -45,14 +53,24 @@ EXT =
endif
-.PHONY: default gen_manual
-
+.PHONY: default
default: gen_manual
gen_manual: gen_manual.cpp
- $(CXX) $(FLAGS) $^ -o $@$(EXT)
+ $(CXX) $(FLAGS) $^ -o $@$(EXT)
+
+$(LZ4MANUAL) : gen_manual $(LZ4API)
+ echo "Update lz4 manual in /doc"
+ ./gen_manual $(LZ4VER) $(LZ4API) $@
+
+$(LZ4FMANUAL) : gen_manual $(LZ4FAPI)
+ echo "Update lz4frame manual in /doc"
+ ./gen_manual $(LZ4VER) $(LZ4FAPI) $@
+.PHONY: manuals
+manuals: gen_manual $(LZ4MANUAL) $(LZ4FMANUAL)
+.PHONY: clean
clean:
@$(RM) gen_manual$(EXT)
@echo Cleaning completed
diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html
index ff6e149..fecd8cd 100644
--- a/doc/lz4_manual.html
+++ b/doc/lz4_manual.html
@@ -1,10 +1,10 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-<title>lz4 1.7.5 Manual</title>
+<title>1.8.0 Manual</title>
</head>
<body>
-<h1>lz4 1.7.5 Manual</h1>
+<h1>1.8.0 Manual</h1>
<hr>
<a name="Contents"></a><h2>Contents</h2>
<ol>
@@ -170,21 +170,21 @@ int LZ4_freeStream (LZ4_stream_t* streamPtr);
</p></pre><BR>
-<pre><b>int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration);
+<pre><b>int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);
</b><p> Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio.
- Important : Previous data blocks are assumed to still be present and unmodified !
+ Important : Previous data blocks are assumed to remain present and unmodified !
'dst' buffer must be already allocated.
- If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
+ If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.
If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero.
+ After an error, the stream status is invalid, and it can only be reset or freed.
</p></pre><BR>
<pre><b>int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize);
-</b><p> If previously compressed data block is not guaranteed to remain available at its memory location,
+</b><p> If previously compressed data block is not guaranteed to remain available at its current memory location,
save it into a safer place (char* safeBuffer).
- Note : you don't need to call LZ4_loadDict() afterwards,
- dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue().
- Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.
+ Note : it's not necessary to call LZ4_loadDict() after LZ4_saveDict(), dictionary is immediately usable.
+ @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.
</p></pre><BR>
diff --git a/doc/lz4frame_manual.html b/doc/lz4frame_manual.html
index f76ec3d..87750a1 100644
--- a/doc/lz4frame_manual.html
+++ b/doc/lz4frame_manual.html
@@ -1,19 +1,23 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
-<title>lz4frame 1.7.5 Manual</title>
+<title>1.8.0 Manual</title>
</head>
<body>
-<h1>lz4frame 1.7.5 Manual</h1>
+<h1>1.8.0 Manual</h1>
<hr>
<a name="Contents"></a><h2>Contents</h2>
<ol>
<li><a href="#Chapter1">Introduction</a></li>
-<li><a href="#Chapter2">Error management</a></li>
-<li><a href="#Chapter3">Frame compression types</a></li>
-<li><a href="#Chapter4">Simple compression function</a></li>
-<li><a href="#Chapter5">Advanced compression functions</a></li>
-<li><a href="#Chapter6">Decompression functions</a></li>
+<li><a href="#Chapter2">Compiler specifics</a></li>
+<li><a href="#Chapter3">Error management</a></li>
+<li><a href="#Chapter4">Frame compression types</a></li>
+<li><a href="#Chapter5">Simple compression function</a></li>
+<li><a href="#Chapter6">Advanced compression functions</a></li>
+<li><a href="#Chapter7">Resource Management</a></li>
+<li><a href="#Chapter8">Compression</a></li>
+<li><a href="#Chapter9">Decompression functions</a></li>
+<li><a href="#Chapter10">Streaming decompression functions</a></li>
</ol>
<hr>
<a name="Chapter1"></a><h2>Introduction</h2><pre>
@@ -22,13 +26,15 @@
of encoding standard metadata alongside LZ4-compressed blocks.
<BR></pre>
-<a name="Chapter2"></a><h2>Error management</h2><pre></pre>
+<a name="Chapter2"></a><h2>Compiler specifics</h2><pre></pre>
+
+<a name="Chapter3"></a><h2>Error management</h2><pre></pre>
<pre><b>unsigned LZ4F_isError(LZ4F_errorCode_t code); </b>/**< tells if a `LZ4F_errorCode_t` function result is an error code */<b>
</b></pre><BR>
<pre><b>const char* LZ4F_getErrorName(LZ4F_errorCode_t code); </b>/**< return error code string; useful for debugging */<b>
</b></pre><BR>
-<a name="Chapter3"></a><h2>Frame compression types</h2><pre></pre>
+<a name="Chapter4"></a><h2>Frame compression types</h2><pre></pre>
<pre><b>typedef enum {
LZ4F_default=0,
@@ -77,7 +83,7 @@
<pre><b>typedef struct {
LZ4F_frameInfo_t frameInfo;
- int compressionLevel; </b>/* 0 == default (fast mode); values above 16 count as 16; values below 0 count as 0 */<b>
+ int compressionLevel; </b>/* 0 == default (fast mode); values above LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values below 0 trigger "fast acceleration", proportional to value */<b>
unsigned autoFlush; </b>/* 1 == always flush (reduce usage of tmp buffer) */<b>
unsigned reserved[4]; </b>/* must be zero for forward compatibility */<b>
} LZ4F_preferences_t;
@@ -86,7 +92,7 @@
All reserved fields must be set to zero.
</p></pre><BR>
-<a name="Chapter4"></a><h2>Simple compression function</h2><pre></pre>
+<a name="Chapter5"></a><h2>Simple compression function</h2><pre></pre>
<pre><b>size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
</b><p> Returns the maximum possible size of a frame compressed with LZ4F_compressFrame() given srcSize content and preferences.
@@ -105,17 +111,19 @@
</p></pre><BR>
-<a name="Chapter5"></a><h2>Advanced compression functions</h2><pre></pre>
+<a name="Chapter6"></a><h2>Advanced compression functions</h2><pre></pre>
<pre><b>typedef struct {
unsigned stableSrc; </b>/* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */<b>
unsigned reserved[3];
} LZ4F_compressOptions_t;
</b></pre><BR>
+<a name="Chapter7"></a><h2>Resource Management</h2><pre></pre>
+
<pre><b>LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version);
LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
</b><p> The first thing to do is to create a compressionContext object, which will be used in all compression operations.
- This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
+ This is achieved using LZ4F_createCompressionContext(), which takes as argument a version.
The version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.
The function will provide a pointer to a fully allocated LZ4F_cctx object.
If @return != zero, there was an error during context creation.
@@ -123,6 +131,8 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
</p></pre><BR>
+<a name="Chapter8"></a><h2>Compression</h2><pre></pre>
+
<pre><b>size_t LZ4F_compressBegin(LZ4F_cctx* cctx, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* prefsPtr);
</b><p> will write the frame header into dstBuffer.
dstCapacity must be large enough to store the header. Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
@@ -173,7 +183,7 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
</p></pre><BR>
-<a name="Chapter6"></a><h2>Decompression functions</h2><pre></pre>
+<a name="Chapter9"></a><h2>Decompression functions</h2><pre></pre>
<pre><b>typedef struct {
unsigned stableDst; </b>/* guarantee that decompressed data will still be there on next function calls (avoid storage into tmp buffers) */<b>
@@ -181,7 +191,7 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);
} LZ4F_decompressOptions_t;
</b></pre><BR>
<pre><b>LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version);
-LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctx);
+LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);
</b><p> Create an LZ4F_decompressionContext_t object, which will be used to track all decompression operations.
The version provided MUST be LZ4F_VERSION. It is intended to track potential breaking differences between different versions.
The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext_t object.
@@ -192,19 +202,27 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctx);
</p></pre><BR>
+<a name="Chapter10"></a><h2>Streaming decompression functions</h2><pre></pre>
+
<pre><b>size_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,
LZ4F_frameInfo_t* frameInfoPtr,
const void* srcBuffer, size_t* srcSizePtr);
-</b><p> This function decodes frame header information (such as max blockSize, frame checksum, etc.).
- Its usage is optional. The objective is to extract frame header information, typically for allocation purposes.
- A header size is variable and can length from 7 to 15 bytes. It's possible to provide more input bytes than that.
+</b><p> This function extracts frame parameters (such as max blockSize, frame checksum, etc.).
+ Its usage is optional. Extracted information can be useful for allocation purposes, typically.
+ This function works in 2 situations :
+ - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process.
+ Input size must be large enough to successfully decode the entire frame header.
+ Frame header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes.
+ It's allowed to provide more input data than this minimum.
+ - After decoding has been started.
+ In which case, no input is read, frame parameters are extracted from dctx.
+ If decoding has just started, but not yet extracted information from header, LZ4F_getFrameInfo() will fail.
The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value).
- Decompression must resume from this point (srcBuffer + *srcSizePtr).
- Note that LZ4F_getFrameInfo() can also be used anytime *after* decompression is started, in which case 0 input byte can be enough.
- Frame header info is *copied into* an already allocated LZ4F_frameInfo_t structure.
+ Decompression must resume from (srcBuffer + *srcSizePtr).
@return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call,
or an error code which can be tested using LZ4F_isError()
- (typically, when there is not enough src bytes to fully decode the frame header)
+ note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped.
+ note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.
</p></pre><BR>
@@ -227,14 +245,22 @@ LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* const dctx);
@return is an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call.
Schematically, it's the size of the current (or remaining) compressed block + header of next block.
- Respecting the hint provides some boost to performance, since it does skip intermediate buffers.
+ Respecting the hint provides some small speed benefit, because it skips intermediate buffers.
This is just a hint though, it's always possible to provide any srcSize.
When a frame is fully decoded, @return will be 0 (no more data expected).
If decompression failed, @return is an error code, which can be tested using LZ4F_isError().
After a frame is fully decoded, dctx can be used again to decompress another frame.
+ After a decompression error, use LZ4F_resetDecompressionContext() before re-using dctx, to return to clean state.
</p></pre><BR>
+<pre><b>void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); </b>/* always successful */<b>
+</b><p> In case of an error, the context is left in "undefined" state.
+ In which case, it's necessary to reset it, before re-using it.
+ This method can also be used to abruptly stop an unfinished decompression,
+ and start a new with the same context.
+</p></pre><BR>
+
</html>
</body>
diff --git a/lib/Makefile b/lib/Makefile
index 9a794b8..c6fd7b8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -46,10 +46,10 @@ BUILD_STATIC:= yes
CPPFLAGS+= -DXXH_NAMESPACE=LZ4_
CFLAGS ?= -O3
-DEBUGFLAGS:=-g -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
+DEBUGFLAGS:= -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow \
-Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes -Wundef \
-Wpointer-arith -Wstrict-aliasing=1
-CFLAGS += $(MOREFLAGS)
+CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
@@ -70,12 +70,13 @@ endif
LIBLZ4 = liblz4.$(SHARED_EXT_VER)
+.PHONY: default
default: lib-release
-lib-release: liblz4.a liblz4
+lib-release: DEBUGFLAGS :=
+lib-release: lib
-lib: CFLAGS += $(DEBUGFLAGS)
-lib: lib-release
+lib: liblz4.a liblz4
all: lib
@@ -83,7 +84,7 @@ all32: CFLAGS+=-m32
all32: all
liblz4.a: *.c
-ifeq ($(BUILD_STATIC),yes)
+ifeq ($(BUILD_STATIC),yes) # can be disabled on command line
@echo compiling static library
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $^
@$(AR) rcs $@ *.o
diff --git a/lib/lz4.h b/lib/lz4.h
index d5a3016..5b6bc92 100644
--- a/lib/lz4.h
+++ b/lib/lz4.h
@@ -88,8 +88,8 @@ extern "C" {
/*------ Version ------*/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
-#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
-#define LZ4_VERSION_RELEASE 6 /* for tweaks, bug-fixes, or development */
+#define LZ4_VERSION_MINOR 8 /* for new (non-breaking) interface capabilities */
+#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
diff --git a/lib/lz4frame.c b/lib/lz4frame.c
index 356be8a..fb37789 100644
--- a/lib/lz4frame.c
+++ b/lib/lz4frame.c
@@ -209,7 +209,8 @@ LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult)
static LZ4F_errorCode_t err0r(LZ4F_errorCodes code)
{
- LZ4_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)); /* A compilation error here means sizeof(ptrdiff_t) is not large enough */
+ /* A compilation error here means sizeof(ptrdiff_t) is not large enough */
+ LZ4_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));
return (LZ4F_errorCode_t)-(ptrdiff_t)code;
}
@@ -241,7 +242,8 @@ static BYTE LZ4F_headerChecksum (const void* header, size_t length)
/*-************************************
* Simple-pass compression functions
**************************************/
-static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID, const size_t srcSize)
+static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID,
+ const size_t srcSize)
{
LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB;
size_t maxBlockSize = 64 KB;
@@ -256,11 +258,13 @@ static LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSI
/* LZ4F_compressBound() :
* Provides dstCapacity given a srcSize to guarantee operation success in worst case situations.
- * prefsPtr is optional : you can provide NULL as argument, preferences will be set to cover worst case scenario.
- * Result is always the same for a srcSize and prefsPtr, so it can be trusted to size reusable buffers.
+ * prefsPtr is optional : if NULL is provided, preferences will be set to cover worst case scenario.
+ * Result is always the same for a srcSize and prefsPtr, so it can be relied upon to size reusable buffers.
* When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations.
*/
-static size_t LZ4F_compressBound_internal(size_t srcSize, const LZ4F_preferences_t* preferencesPtr, size_t alreadyBuffered)
+static size_t LZ4F_compressBound_internal(size_t srcSize,
+ const LZ4F_preferences_t* preferencesPtr,
+ size_t alreadyBuffered)
{
LZ4F_preferences_t prefsNull;
memset(&prefsNull, 0, sizeof(prefsNull));
@@ -298,14 +302,14 @@ size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* prefere
/*! LZ4F_compressFrame() :
-* Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.5.0, in a single step.
-* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
-* You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
-* If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
-* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will then be set to default.
-* The result of the function is the number of bytes written into dstBuffer.
-* The function outputs an error code if it fails (can be tested using LZ4F_isError())
-*/
+ * Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.5.0, in a single step.
+ * The most important rule is that dstBuffer MUST be large enough (dstCapacity) to ensure compression completion even in worst case.
+ * If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
+ * Get the minimum value of dstCapacity by using LZ4F_compressFrameBound().
+ * The LZ4F_preferences_t structure is optional : if NULL is provided as argument, preferences will be set to default.
+ * The result of the function is the number of bytes written into dstBuffer.
+ * The function outputs an error code if it fails (can be tested using LZ4F_isError())
+ */
size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr)
{
LZ4F_cctx_t cctxI;
@@ -404,10 +408,10 @@ LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_comp
/*! LZ4F_compressBegin() :
- * will write the frame header into dstBuffer.
- * dstBuffer must be large enough to accommodate a header (dstCapacity). Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
- * @return : number of bytes written into dstBuffer for the header
- * or an error code (can be tested using LZ4F_isError())
+ * will write the frame header into dstBuffer.
+ * dstBuffer must be large enough to accommodate a header (dstCapacity). Maximum header size is LZ4F_HEADER_SIZE_MAX bytes.
+ * @return : number of bytes written into dstBuffer for the header
+ * or an error code (can be tested using LZ4F_isError())
*/
size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_preferences_t* preferencesPtr)
{
@@ -650,13 +654,13 @@ size_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapaci
/*! LZ4F_flush() :
-* Should you need to create compressed data immediately, without waiting for a block to be filled,
-* you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
-* The result of the function is the number of bytes written into dstBuffer
-* (it can be zero, this means there was no data left within compressionContext)
-* The function outputs an error code if it fails (can be tested using LZ4F_isError())
-* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
-*/
+ * Should you need to create compressed data immediately, without waiting for a block to be filled,
+ * you can call LZ4_flush(), which will immediately compress any remaining data stored within compressionContext.
+ * The result of the function is the number of bytes written into dstBuffer
+ * (it can be zero, this means there was no data left within compressionContext)
+ * The function outputs an error code if it fails (can be tested using LZ4F_isError())
+ * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
+ */
size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const LZ4F_compressOptions_t* compressOptionsPtr)
{
BYTE* const dstStart = (BYTE*)dstBuffer;
@@ -687,14 +691,14 @@ size_t LZ4F_flush(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstCapacity, const
/*! LZ4F_compressEnd() :
-* When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
-* It will flush whatever data remained within compressionContext (like LZ4_flush())
-* but also properly finalize the frame, with an endMark and a checksum.
-* The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
-* The function outputs an error code if it fails (can be tested using LZ4F_isError())
-* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
-* compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
-*/
+ * When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
+ * It will flush whatever data remained within compressionContext (like LZ4_flush())
+ * but also properly finalize the frame, with an endMark and a checksum.
+ * The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
+ * The function outputs an error code if it fails (can be tested using LZ4F_isError())
+ * The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
+ * compressionContext can then be used again, starting with LZ4F_compressBegin(). The preferences will remain the same.
+ */
size_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr)
{
BYTE* const dstStart = (BYTE*)dstBuffer;
@@ -751,11 +755,11 @@ struct LZ4F_dctx_s {
/*! LZ4F_createDecompressionContext() :
-* Create a decompressionContext object, which will track all decompression operations.
-* Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object.
-* Object can later be released using LZ4F_freeDecompressionContext().
-* @return : if != 0, there was an error during context creation.
-*/
+ * Create a decompressionContext object, which will track all decompression operations.
+ * Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object.
+ * Object can later be released using LZ4F_freeDecompressionContext().
+ * @return : if != 0, there was an error during context creation.
+ */
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)
{
LZ4F_dctx* const dctxPtr = (LZ4F_dctx*)ALLOCATOR(sizeof(LZ4F_dctx));
@@ -794,17 +798,16 @@ typedef enum {
dstage_skipSkippable
} dStage_t;
-LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
+void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)
{
dctx->dStage = dstage_getHeader;
- return 0;
}
/*! LZ4F_headerSize() :
-* @return : size of frame header
-* or an error code, which can be tested using LZ4F_isError()
-*/
+ * @return : size of frame header
+ * or an error code, which can be tested using LZ4F_isError()
+ */
static size_t LZ4F_headerSize(const void* src, size_t srcSize)
{
/* minimal srcSize to determine header size */
@@ -825,13 +828,13 @@ static size_t LZ4F_headerSize(const void* src, size_t srcSize)
/*! LZ4F_decodeHeader() :
- input : `src` points at the **beginning of the frame**
- output : set internal values of dctx, such as
- dctxPtr->frameInfo and dctxPtr->dStage.
- Also allocates internal buffers.
- @return : nb Bytes read from src (necessarily <= srcSize)
- or an error code (testable with LZ4F_isError())
-*/
+ * input : `src` points at the **beginning of the frame**
+ * output : set internal values of dctx, such as
+ * dctxPtr->frameInfo and dctxPtr->dStage.
+ * Also allocates internal buffers.
+ * @return : nb Bytes read from src (necessarily <= srcSize)
+ * or an error code (testable with LZ4F_isError())
+ */
static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcSize)
{
unsigned blockMode, contentSizeFlag, contentChecksumFlag, blockSizeID;
@@ -913,8 +916,8 @@ static size_t LZ4F_decodeHeader(LZ4F_dctx* dctxPtr, const void* src, size_t srcS
/*! LZ4F_getFrameInfo() :
- * This function extracts frame parameters (such as max blockSize, frame checksum, etc.).
- * Its usage is optional. The objective is to provide relevant information for allocation purposes.
+ * This function extracts frame parameters (max blockSize, frame checksum, etc.).
+ * Usage is optional. Objective is to provide relevant information for allocation purposes.
* This function works in 2 situations :
* - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process.
* Amount of input data provided must be large enough to successfully decode the frame header.
@@ -935,7 +938,8 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
size_t o=0, i=0;
*srcSizePtr = 0;
*frameInfoPtr = dctxPtr->frameInfo;
- return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL); /* returns : recommended nb of bytes for LZ4F_decompress() */
+ /* returns : recommended nb of bytes for LZ4F_decompress() */
+ return LZ4F_decompress(dctxPtr, NULL, &o, NULL, &i, NULL);
} else {
if (dctxPtr->dStage == dstage_storeHeader) {
/* frame decoding already started, in the middle of header => automatic fail */
@@ -945,7 +949,10 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
size_t decodeResult;
size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);
if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }
- if (*srcSizePtr < hSize) { *srcSizePtr=0; return err0r(LZ4F_ERROR_frameHeader_incomplete); }
+ if (*srcSizePtr < hSize) {
+ *srcSizePtr=0;
+ return err0r(LZ4F_ERROR_frameHeader_incomplete);
+ }
decodeResult = LZ4F_decodeHeader(dctxPtr, srcBuffer, hSize);
if (LZ4F_isError(decodeResult)) {
@@ -961,10 +968,15 @@ LZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctxPtr, LZ4F_frameInfo_t* frameIn
/* trivial redirector, for common prototype */
-static int LZ4F_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize)
+static int LZ4F_decompress_safe (const char* src,
+ char* dst,
+ int compressedSize,
+ int dstCapacity,
+ const char* dictStart,
+ int dictSize)
{
(void)dictStart; (void)dictSize;
- return LZ4_decompress_safe (source, dest, compressedSize, maxDecompressedSize);
+ return LZ4_decompress_safe (src, dst, compressedSize, dstCapacity);
}
@@ -1028,22 +1040,22 @@ static void LZ4F_updateDict(LZ4F_dctx* dctxPtr, const BYTE* dstPtr, size_t dstSi
/*! LZ4F_decompress() :
-* Call this function repetitively to regenerate data compressed within srcBuffer.
-* The function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *dstSizePtr.
-*
-* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
-*
-* The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
-* If the number of bytes read is < number of bytes provided, then the decompression operation is not complete.
-* Remaining data will have to be presented again in a subsequent invocation.
-*
-* The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.
-* Basically, it's the size of the current (or remaining) compressed block + header of next block.
-* Respecting the hint provides some boost to performance, since it allows less buffer shuffling.
-* Note that this is just a hint, it's always possible to any srcSize value.
-* When a frame is fully decoded, @return will be 0.
-* If decompression failed, @return is an error code which can be tested using LZ4F_isError().
-*/
+ * Call this function repetitively to regenerate data compressed within srcBuffer.
+ * The function will attempt to decode up to *srcSizePtr bytes from srcBuffer, into dstBuffer of capacity *dstSizePtr.
+ *
+ * The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
+ *
+ * The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
+ * If the number of bytes read is < number of bytes provided, then the decompression operation is not complete.
+ * Remaining data will have to be presented again in a subsequent invocation.
+ *
+ * The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.
+ * Basically, it's the size of the current (or remaining) compressed block + header of next block.
+ * Respecting the hint provides some boost to performance, since it allows less buffer shuffling.
+ * Note that this is just a hint, it's always possible to any srcSize value.
+ * When a frame is fully decoded, @return will be 0.
+ * If decompression failed, @return is an error code which can be tested using LZ4F_isError().
+ */
size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
void* dstBuffer, size_t* dstSizePtr,
const void* srcBuffer, size_t* srcSizePtr,
@@ -1097,7 +1109,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
doAnotherStage = 0; /* not enough src data, ask for some more */
break;
}
- { LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget);
+ { LZ4F_errorCode_t const hSize = LZ4F_decodeHeader(dctxPtr, dctxPtr->header, dctxPtr->tmpInTarget); /* will change dStage appropriately */
if (LZ4F_isError(hSize)) return hSize;
}
break;
@@ -1145,7 +1157,7 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
memcpy(dctxPtr->tmpIn + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
srcPtr += sizeToCopy;
dctxPtr->tmpInSize += sizeToCopy;
- if (dctxPtr->tmpInSize < BHSize) { /* not enough input to get full cBlockSize; wait for more */
+ if (dctxPtr->tmpInSize < BHSize) { /* not enough input for cBlockSize */
nextSrcSizeHint = BHSize - dctxPtr->tmpInSize;
doAnotherStage = 0;
break;
@@ -1153,13 +1165,14 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
selectedIn = dctxPtr->tmpIn;
}
- /* case dstage_decodeCBlockSize: */ /* no more direct access, to prevent scan-build warning */
+ /* case dstage_decodeCBlockSize: */ /* no more direct access, to remove scan-build warning */
{ size_t const nextCBlockSize = LZ4F_readLE32(selectedIn) & 0x7FFFFFFFU;
if (nextCBlockSize==0) { /* frameEnd signal, no more CBlock */
dctxPtr->dStage = dstage_getSuffix;
break;
}
- if (nextCBlockSize > dctxPtr->maxBlockSize) return err0r(LZ4F_ERROR_GENERIC); /* invalid cBlockSize */
+ if (nextCBlockSize > dctxPtr->maxBlockSize)
+ return err0r(LZ4F_ERROR_maxBlockSize_invalid);
dctxPtr->tmpInTarget = nextCBlockSize;
if (LZ4F_readLE32(selectedIn) & LZ4F_BLOCKUNCOMPRESSED_FLAG) {
dctxPtr->dStage = dstage_copyDirect;
@@ -1175,11 +1188,13 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
case dstage_copyDirect: /* uncompressed block */
{ size_t sizeToCopy = dctxPtr->tmpInTarget;
- if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr; /* not enough input to read full block */
+ if ((size_t)(srcEnd-srcPtr) < sizeToCopy) sizeToCopy = srcEnd - srcPtr;
if ((size_t)(dstEnd-dstPtr) < sizeToCopy) sizeToCopy = dstEnd - dstPtr;
memcpy(dstPtr, srcPtr, sizeToCopy);
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), srcPtr, sizeToCopy);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= sizeToCopy;
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), srcPtr, sizeToCopy);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= sizeToCopy;
/* dictionary management */
if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
@@ -1240,10 +1255,14 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
else
decoder = LZ4F_decompress_safe;
- decodedSize = decoder((const char*)selectedIn, (char*)dstPtr, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
+ decodedSize = decoder((const char*)selectedIn, (char*)dstPtr,
+ (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize,
+ (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
if (decodedSize < 0) return err0r(LZ4F_ERROR_GENERIC); /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), dstPtr, decodedSize);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= decodedSize;
/* dictionary management */
if (dctxPtr->frameInfo.blockMode==LZ4F_blockLinked)
@@ -1280,10 +1299,15 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
}
/* Decode */
- decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut, (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize, (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
- if (decodedSize < 0) return err0r(LZ4F_ERROR_decompressionFailed); /* decompression failed */
- if (dctxPtr->frameInfo.contentChecksumFlag) XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
- if (dctxPtr->frameInfo.contentSize) dctxPtr->frameRemainingSize -= decodedSize;
+ decodedSize = decoder((const char*)selectedIn, (char*)dctxPtr->tmpOut,
+ (int)dctxPtr->tmpInTarget, (int)dctxPtr->maxBlockSize,
+ (const char*)dctxPtr->dict, (int)dctxPtr->dictSize);
+ if (decodedSize < 0)
+ return err0r(LZ4F_ERROR_decompressionFailed); /* decompression failed */
+ if (dctxPtr->frameInfo.contentChecksumFlag)
+ XXH32_update(&(dctxPtr->xxh), dctxPtr->tmpOut, decodedSize);
+ if (dctxPtr->frameInfo.contentSize)
+ dctxPtr->frameRemainingSize -= decodedSize;
dctxPtr->tmpOutSize = decodedSize;
dctxPtr->tmpOutStart = 0;
dctxPtr->dStage = dstage_flushOut;
@@ -1314,7 +1338,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
case dstage_getSuffix:
{ size_t const suffixSize = dctxPtr->frameInfo.contentChecksumFlag * 4;
- if (dctxPtr->frameRemainingSize) return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
+ if (dctxPtr->frameRemainingSize)
+ return err0r(LZ4F_ERROR_frameSize_wrong); /* incorrect frame size decoded */
if (suffixSize == 0) { /* frame completed */
nextSrcSizeHint = 0;
dctxPtr->dStage = dstage_getHeader;
@@ -1375,7 +1400,8 @@ size_t LZ4F_decompress(LZ4F_dctx* dctxPtr,
memcpy(dctxPtr->header + dctxPtr->tmpInSize, srcPtr, sizeToCopy);
srcPtr += sizeToCopy;
dctxPtr->tmpInSize += sizeToCopy;
- if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) { /* not enough input to get full sBlockSize; wait for more */
+ if (dctxPtr->tmpInSize < dctxPtr->tmpInTarget) {
+ /* not enough input to get full sBlockSize; wait for more */
nextSrcSizeHint = dctxPtr->tmpInTarget - dctxPtr->tmpInSize;
doAnotherStage = 0;
break;
diff --git a/lib/lz4frame.h b/lib/lz4frame.h
index 2e79a17..b1719e2 100644
--- a/lib/lz4frame.h
+++ b/lib/lz4frame.h
@@ -363,6 +363,14 @@ LZ4FLIB_API size_t LZ4F_decompress(LZ4F_dctx* dctx,
const LZ4F_decompressOptions_t* dOptPtr);
+/*! LZ4F_resetDecompressionContext() : v1.8.0
+ * In case of an error, the context is left in "undefined" state.
+ * In which case, it's necessary to reset it, before re-using it.
+ * This method can also be used to abruptly stop an unfinished decompression,
+ * and start a new with the same context. */
+LZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx); /* always successful */
+
+
#if defined (__cplusplus)
}
diff --git a/lib/lz4frame_static.h b/lib/lz4frame_static.h
index 8ea496d..d3bae82 100644
--- a/lib/lz4frame_static.h
+++ b/lib/lz4frame_static.h
@@ -50,15 +50,6 @@ extern "C" {
#include "lz4frame.h"
-/* --- Experimental functions --- */
-/* LZ4F_resetDecompressionContext() :
- * LZ4F_decompress() does not guarantee to leave dctx in clean state in case of errors.
- * In order to re-use a dctx after a decompression error,
- * use LZ4F_resetDecompressionContext() first.
- * dctx will be able to start decompression on a new frame */
-LZ4FLIB_API LZ4F_errorCode_t LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);
-
-
/* --- Error List --- */
#define LZ4F_LIST_ERRORS(ITEM) \
ITEM(OK_NoError) \
diff --git a/lib/lz4hc.c b/lib/lz4hc.c
index 16fe029..b987d39 100644
--- a/lib/lz4hc.c
+++ b/lib/lz4hc.c
@@ -69,9 +69,9 @@
/*=== Macros ===*/
-#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
-#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
-#define DELTANEXTU16(p) chainTable[(U16)(p)] /* faster */
+#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))
+#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */
+#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
@@ -106,7 +106,7 @@ FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
U32 const h = LZ4HC_hashPtr(base+idx);
size_t delta = idx - hashTable[h];
if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
- DELTANEXTU16(idx) = (U16)delta;
+ DELTANEXTU16(chainTable, idx) = (U16)delta;
hashTable[h] = idx;
idx++;
}
@@ -115,8 +115,8 @@ FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)
}
-FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* Index table will be updated */
- const BYTE* ip, const BYTE* const iLimit,
+FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */
+ const BYTE* const ip, const BYTE* const iLimit,
const BYTE** matchpos,
const int maxNbAttempts)
{
@@ -138,8 +138,8 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* In
nbAttempts--;
if (matchIndex >= dictLimit) {
const BYTE* const match = base + matchIndex;
- if (*(match+ml) == *(ip+ml)
- && (LZ4_read32(match) == LZ4_read32(ip)))
+ if ( (*(match+ml) == *(ip+ml)) /* can be longer */
+ && (LZ4_read32(match) == LZ4_read32(ip)) )
{
size_t const mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
if (mlt > ml) { ml = mlt; *matchpos = match; }
@@ -156,7 +156,7 @@ FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_CCtx_internal* hc4, /* In
if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
}
}
- matchIndex -= DELTANEXTU16(matchIndex);
+ matchIndex -= DELTANEXTU16(chainTable, matchIndex);
}
return (int)ml;
@@ -180,9 +180,9 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
const BYTE* const lowPrefixPtr = base + dictLimit;
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
const BYTE* const dictBase = hc4->dictBase;
- U32 matchIndex;
+ int const delta = (int)(ip-iLowLimit);
int nbAttempts = maxNbAttempts;
- int delta = (int)(ip-iLowLimit);
+ U32 matchIndex;
/* First Match */
@@ -206,14 +206,14 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
mlt -= back;
if (mlt > longest) {
- longest = (int)mlt;
+ longest = mlt;
*matchpos = matchPtr+back;
*startpos = ip+back;
} } }
} else {
const BYTE* const matchPtr = dictBase + matchIndex;
if (LZ4_read32(matchPtr) == LZ4_read32(ip)) {
- size_t mlt;
+ int mlt;
int back=0;
const BYTE* vLimit = ip + (dictLimit - matchIndex);
if (vLimit > iHighLimit) vLimit = iHighLimit;
@@ -222,10 +222,10 @@ FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == matchPtr[back-1])) back--;
mlt -= back;
- if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
+ if (mlt > longest) { longest = mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
}
}
- matchIndex -= DELTANEXTU16(matchIndex);
+ matchIndex -= DELTANEXTU16(chainTable, matchIndex);
}
return longest;
@@ -238,12 +238,10 @@ typedef enum {
limitedDestSize = 2,
} limitedOutput_directive;
-#define LZ4HC_DEBUG 0
-#if LZ4HC_DEBUG
-static unsigned debug = 0;
+#ifndef LZ4HC_DEBUG
+# define LZ4HC_DEBUG 0
#endif
-
/* LZ4HC_encodeSequence() :
* @return : 0 if ok,
* 1 if buffer issue detected */
@@ -257,15 +255,15 @@ FORCE_INLINE int LZ4HC_encodeSequence (
BYTE* oend)
{
size_t length;
- BYTE* token;
+ BYTE* const token = (*op)++;
#if LZ4HC_DEBUG
- if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
+ printf("literal : %u -- match : %u -- offset : %u\n",
+ (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
#endif
/* Encode Literal length */
length = (size_t)(*ip - *anchor);
- token = (*op)++;
if ((limit) && ((*op + (length >> 8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
if (length >= RUN_MASK) {
size_t len = length - RUN_MASK;
diff --git a/programs/Makefile b/programs/Makefile
index 4a8103c..2e73780 100644
--- a/programs/Makefile
+++ b/programs/Makefile
@@ -51,7 +51,7 @@ CFLAGS ?= -O3
DEBUGFLAGS:=-g -Wall -Wextra -Wundef -Wcast-qual -Wcast-align -Wshadow \
-Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes \
-Wpointer-arith -Wstrict-aliasing=1
-CFLAGS += $(MOREFLAGS)
+CFLAGS += $(DEBUGFLAGS) $(MOREFLAGS)
FLAGS = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
LZ4_VERSION=$(LIBVER)
@@ -75,28 +75,17 @@ all: lz4 lz4c
all32: CFLAGS+=-m32
all32: all
-lz4: CFLAGS += $(DEBUGFLAGS)
lz4: $(OBJFILES)
$(CC) $(FLAGS) $^ -o $@$(EXT)
lz4-release: DEBUGFLAGS=
lz4-release: lz4
-lz4c : CFLAGS += $(DEBUGFLAGS)
-lz4c : $(SRCFILES)
- $(CC) $(FLAGS) -DENABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
-
-lz4c32: CFLAGS += -m32 $(DEBUGFLAGS)
-lz4c32: $(SRCFILES)
+lz4c32: CFLAGS += -m32
+lz4c: CPPFLAGS += -DENABLE_LZ4C_LEGACY_OPTIONS
+lz4c lz4c32 : $(SRCFILES)
$(CC) $(FLAGS) $^ -o $@$(EXT)
-clean:
- @$(MAKE) -C $(LZ4DIR) $@ > $(VOID)
- @$(RM) core *.o *.test tmp* \
- lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) unlz4 lz4cat
- @echo Cleaning completed
-
-
lz4.1: lz4.1.md
cat $^ | $(MD2ROFF) $(MD2ROFF_FLAGS) | sed -n '/^\.\\\".*/!p' > $@
@@ -108,6 +97,12 @@ clean-man:
preview-man: clean-man man
man ./lz4.1
+clean:
+ @$(MAKE) -C $(LZ4DIR) $@ > $(VOID)
+ @$(RM) core *.o *.test tmp* \
+ lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) unlz4 lz4cat
+ @echo Cleaning completed
+
#-----------------------------------------------------------------------------
# make install is validated only for Linux, OSX, BSD, Hurd and Solaris targets
@@ -120,7 +115,6 @@ unlz4: lz4
lz4cat: lz4
ln -s lz4 lz4cat
-
ifneq (,$(filter $(shell uname),SunOS))
INSTALL ?= ginstall
else
diff --git a/tests/frametest.c b/tests/frametest.c
index a4c548e..0dadf9f 100644
--- a/tests/frametest.c
+++ b/tests/frametest.c
@@ -40,6 +40,7 @@
#include <stdio.h> /* fprintf */
#include <string.h> /* strcmp */
#include <time.h> /* clock_t, clock(), CLOCKS_PER_SEC */
+#include <assert.h>
#include "lz4frame_static.h"
#include "lz4.h" /* LZ4_VERSION_STRING */
#define XXH_STATIC_LINKING_ONLY
@@ -67,7 +68,6 @@ static void FUZ_writeLE32 (void* dstVoidPtr, U32 value32)
#define GB *(1U<<30)
static const U32 nbTestsDefault = 256 KB;
-#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
#define FUZ_COMPRESSIBILITY_DEFAULT 50
static const U32 prime1 = 2654435761U;
static const U32 prime2 = 2246822519U;
@@ -166,7 +166,7 @@ static unsigned FUZ_highbit(U32 v32)
*********************************************************/
int basicTests(U32 seed, double compressibility)
{
- int testResult = 0;
+#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
void* const CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
size_t const cBuffSize = LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL);
void* const compressedBuffer = malloc(cBuffSize);
@@ -176,9 +176,10 @@ int basicTests(U32 seed, double compressibility)
LZ4F_decompressionContext_t dCtx = NULL;
LZ4F_compressionContext_t cctx = NULL;
U64 crcOrig;
-
+ int basicTests_error = 0;
LZ4F_preferences_t prefs;
memset(&prefs, 0, sizeof(prefs));
+
if (!CNBuffer || !compressedBuffer || !decodedBuffer) {
DISPLAY("allocation error, not enough memory to start fuzzer tests \n");
goto _output_error;
@@ -198,7 +199,7 @@ int basicTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : ");
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
if (LZ4F_isError(cSize)) goto _output_error;
- DISPLAYLEVEL(3, "Compressed null content into a %i bytes frame \n", (int)cSize);
+ DISPLAYLEVEL(3, "null content encoded into a %u bytes frame \n", (unsigned)cSize);
DISPLAYLEVEL(3, "LZ4F_createDecompressionContext \n");
{ LZ4F_errorCode_t const errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
@@ -236,8 +237,6 @@ int basicTests(U32 seed, double compressibility)
DISPLAYLEVEL(3, "Decompression test : \n");
{ size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
size_t compressedBufferSize = cSize;
- BYTE* ip = (BYTE*)compressedBuffer;
- BYTE* const iend = (BYTE*)compressedBuffer + cSize;
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
if (LZ4F_isError(errorCode)) goto _output_error;
@@ -280,6 +279,7 @@ int basicTests(U32 seed, double compressibility)
{ size_t oSize = 0;
size_t iSize = 0;
LZ4F_frameInfo_t fi;
+ const BYTE* ip = (BYTE*)compressedBuffer;
DISPLAYLEVEL(3, "Start by feeding 0 bytes, to get next input size : ");
errorCode = LZ4F_decompress(dCtx, NULL, &oSize, ip, &iSize, NULL);
@@ -290,7 +290,8 @@ int basicTests(U32 seed, double compressibility)
{ size_t nullSize = 0;
size_t const fiError = LZ4F_getFrameInfo(dCtx, &fi, ip, &nullSize);
if (LZ4F_getErrorCode(fiError) != LZ4F_ERROR_frameHeader_incomplete) {
- DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n", LZ4F_getErrorName(fiError));
+ DISPLAYLEVEL(3, "incorrect error : %s != ERROR_frameHeader_incomplete \n",
+ LZ4F_getErrorName(fiError));
goto _output_error;
}
DISPLAYLEVEL(3, " correctly failed : %s \n", LZ4F_getErrorName(fiError));
@@ -314,10 +315,30 @@ int basicTests(U32 seed, double compressibility)
ip += iSize;
}
+ DISPLAYLEVEL(3, "Decode a buggy input : ");
+ assert(COMPRESSIBLE_NOISE_LENGTH > 64);
+ assert(cSize > 48);
+ memcpy(decodedBuffer, (char*)compressedBuffer+16, 32); /* save correct data */
+ memcpy((char*)compressedBuffer+16, (const char*)decodedBuffer+32, 32); /* insert noise */
+ { size_t dbSize = COMPRESSIBLE_NOISE_LENGTH;
+ size_t cbSize = cSize;
+ size_t const decompressError = LZ4F_decompress(dCtx, decodedBuffer, &dbSize,
+ compressedBuffer, &cbSize,
+ NULL);
+ if (!LZ4F_isError(decompressError)) goto _output_error;
+ DISPLAYLEVEL(3, "error detected : %s \n", LZ4F_getErrorName(decompressError));
+ }
+ memcpy((char*)compressedBuffer+16, decodedBuffer, 32); /* restore correct data */
+
+ DISPLAYLEVEL(3, "Reset decompression context, since it's left in error state \n");
+ LZ4F_resetDecompressionContext(dCtx); /* always successful */
+
DISPLAYLEVEL(3, "Byte after byte : ");
{ BYTE* const ostart = (BYTE*)decodedBuffer;
BYTE* op = ostart;
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
+ const BYTE* ip = (const BYTE*) compressedBuffer;
+ const BYTE* const iend = ip + cSize;
while (ip < iend) {
size_t oSize = oend-op;
size_t iSize = 1;
@@ -329,11 +350,7 @@ int basicTests(U32 seed, double compressibility)
{ U64 const crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
if (crcDest != crcOrig) goto _output_error; }
DISPLAYLEVEL(3, "Regenerated %u/%u bytes \n", (unsigned)(op-ostart), COMPRESSIBLE_NOISE_LENGTH);
- }
-
- errorCode = LZ4F_freeDecompressionContext(dCtx);
- if (LZ4F_isError(errorCode)) goto _output_error;
- dCtx = NULL;
+ }
}
DISPLAYLEVEL(3, "Using 64 KB block : ");
@@ -365,9 +382,6 @@ int basicTests(U32 seed, double compressibility)
const BYTE* ip = (const BYTE*)compressedBuffer;
const BYTE* const iend = (const BYTE*)compressedBuffer + cSize;
- { LZ4F_errorCode_t const createError = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
- if (LZ4F_isError(createError)) goto _output_error; }
-
DISPLAYLEVEL(3, "random segment sizes : ");
while (ip < iend) {
unsigned const nbBits = FUZ_rand(&randState) % maxBits;
@@ -551,10 +565,10 @@ _end:
free(decodedBuffer);
LZ4F_freeDecompressionContext(dCtx); dCtx = NULL;
LZ4F_freeCompressionContext(cctx); cctx = NULL;
- return testResult;
+ return basicTests_error;
_output_error:
- testResult = 1;
+ basicTests_error = 1;
DISPLAY("Error detected ! \n");
goto _end;
}