diff options
author | Yann Collet <Cyan4973@users.noreply.github.com> | 2016-11-10 19:26:48 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-10 19:26:48 (GMT) |
commit | cd4462629e98d6c62ec147ada0d63cd389c8e5f9 (patch) | |
tree | 14a6c2e07b308d19d9f7a2f38a90f5a926cbc13c | |
parent | 924f00c86ce9075d520967c893dbfbe13a7bf073 (diff) | |
parent | 52251d970956c992801b6b7434fe092751f7731e (diff) | |
download | lz4-cd4462629e98d6c62ec147ada0d63cd389c8e5f9.zip lz4-cd4462629e98d6c62ec147ada0d63cd389c8e5f9.tar.gz lz4-cd4462629e98d6c62ec147ada0d63cd389c8e5f9.tar.bz2 |
Merge pull request #264 from inikep/dev
Dev
-rw-r--r-- | .travis.yml | 28 | ||||
-rw-r--r-- | Makefile | 48 | ||||
-rw-r--r-- | contrib/gen_manual/Makefile | 36 | ||||
-rw-r--r-- | contrib/gen_manual/README.md | 31 | ||||
-rw-r--r-- | contrib/gen_manual/gen-lz4-manual.sh | 9 | ||||
-rw-r--r-- | contrib/gen_manual/gen_manual.cpp | 216 | ||||
-rw-r--r-- | doc/lz4_manual.html | 240 | ||||
-rw-r--r-- | lib/README.md | 37 | ||||
-rw-r--r-- | lib/lz4.h | 67 | ||||
-rw-r--r-- | programs/bench.c | 6 | ||||
-rw-r--r-- | programs/lz4cli.c | 39 | ||||
-rw-r--r-- | programs/lz4io.c | 2 | ||||
-rw-r--r-- | tests/Makefile | 6 | ||||
-rw-r--r-- | tests/README.md | 48 |
14 files changed, 742 insertions, 71 deletions
diff --git a/.travis.yml b/.travis.yml index 1de67aa..4bef528 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,19 +9,19 @@ matrix: # Container-based 12.04 LTS Server Edition 64 bit (doesn't support 32-bit includes) - os: linux sudo: false - env: Ubu=12.04cont Cmd='make test' COMPILER=cc - + env: Ubu=12.04cont Cmd='make -C tests test-lz4 test-lz4c test-fasttest test-fullbench' COMPILER=cc + - os: linux sudo: false - env: Ubu=12.04cont Cmd="make gpptest && make clean && make examples && make clean && make cmake && make clean && make travis-install" COMPILER=cc + env: Ubu=12.04cont Cmd='make -C tests test-frametest test-fuzzer' COMPILER=cc - os: linux sudo: false - env: Ubu=12.04cont Cmd='make clangtest' COMPILER=clang + env: Ubu=12.04cont Cmd="make gpptest && make clean && make examples && make clean && make cmake && make clean && make travis-install && make clean && make clangtest" COMPILER=cc # 14.04 LTS Server Edition 64 bit - - env: Ubu=14.04 Cmd='make -C tests test32 versionsTest' COMPILER=cc + - env: Ubu=14.04 Cmd='make -C tests test-lz4c32 test-fullbench32 versionsTest' COMPILER=cc dist: trusty sudo: required addons: @@ -31,13 +31,29 @@ matrix: - libc6-dev-i386 - gcc-multilib - - env: Ubu=14.04 Cmd='make staticAnalyze sanitize' COMPILER=clang + - env: Ubu=14.04 Cmd='make -C tests test-frametest32 test-fuzzer32' COMPILER=cc + dist: trusty + sudo: required + addons: + apt: + packages: + - libc6-dev-i386 + - gcc-multilib + + - env: Ubu=14.04 Cmd='make sanitize' COMPILER=clang dist: trusty sudo: required addons: apt: packages: - valgrind + + - env: Ubu=14.04 Cmd='make staticAnalyze' COMPILER=clang + dist: trusty + sudo: required + addons: + apt: + packages: - clang - env: Ubu=14.04 Cmd='make platformTest CC=arm-linux-gnueabi-gcc QEMU_SYS=qemu-arm-static && make platformTest CC=aarch64-linux-gnu-gcc QEMU_SYS=qemu-aarch64-static' COMPILER=arm-linux-gnueabi-gcc @@ -75,6 +75,7 @@ clean: #make install is validated only for Linux, OSX, kFreeBSD, Hurd and #FreeBSD targets ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU FreeBSD)) +HOST_OS = POSIX install: @$(MAKE) -C $(LZ4DIR) $@ @@ -90,23 +91,8 @@ travis-install: test: $(MAKE) -C $(TESTDIR) test -cmake: - @cd contrib/cmake_unofficial; cmake CMakeLists.txt; $(MAKE) - -gpptest: clean - $(MAKE) all CC=g++ CFLAGS="-O3 -I../lib -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 - clangtest: clean + clang -v CFLAGS="-O3 -Werror -Wconversion -Wno-sign-conversion" $(MAKE) all CC=clang sanitize: clean @@ -132,3 +118,33 @@ examples: $(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 + $(MAKE) all CC=g++ CFLAGS="-O3 -I../lib -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 + +endif diff --git a/contrib/gen_manual/Makefile b/contrib/gen_manual/Makefile new file mode 100644 index 0000000..49616ee --- /dev/null +++ b/contrib/gen_manual/Makefile @@ -0,0 +1,36 @@ +# ########################################################################## +# Copyright (c) 2016-present, Przemyslaw Skibinski +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. An additional grant +# of patent rights can be found in the PATENTS file in the same directory. +# ########################################################################## + + +CFLAGS ?= -O3 +CFLAGS += -Wall -Wextra -Wcast-qual -Wcast-align -Wshadow -Wstrict-aliasing=1 -Wswitch-enum -Wno-comment +CFLAGS += $(MOREFLAGS) +FLAGS = $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) + + + +# Define *.exe as extension for Windows systems +ifneq (,$(filter Windows%,$(OS))) +EXT =.exe +else +EXT = +endif + + +.PHONY: default gen_manual + +default: gen_manual + +gen_manual: gen_manual.cpp + $(CXX) $(FLAGS) $^ -o $@$(EXT) + + +clean: + @$(RM) gen_manual$(EXT) + @echo Cleaning completed diff --git a/contrib/gen_manual/README.md b/contrib/gen_manual/README.md new file mode 100644 index 0000000..3d146d4 --- /dev/null +++ b/contrib/gen_manual/README.md @@ -0,0 +1,31 @@ +gen_manual - a program for automatic generation of zstd manual +============================================================ + +#### Introduction + +This simple C++ program generates a single-page HTML manual from `lz4.h`. + +The format of recognized comment blocks is following: +- comments of type `/*!` mean: this is a function declaration; switch comments with declarations +- comments of type `/**` and `/*-` mean: this is a comment; use a `<H2>` header for the first line +- comments of type `/*=` and `/**=` mean: use a `<H3>` header and show also all functions until first empty line +- comments of type `/*X` where `X` is different from above-mentioned are ignored + +Moreover: +- `LZ4LIB_API` is removed to improve readability +- `typedef` are detected and included even if uncommented +- comments of type `/**<` and `/*!<` are detected and only function declaration is highlighted (bold) + + +#### Usage + +The program requires 3 parameters: +``` +gen_manual [lz4_version] [input_file] [output_html] +``` + +To compile program and generate lz4 manual we have used: +``` +make +./gen_manual.exe 1.7.3 ../../lib/lz4.h zstd_manual.html +``` diff --git a/contrib/gen_manual/gen-lz4-manual.sh b/contrib/gen_manual/gen-lz4-manual.sh new file mode 100644 index 0000000..55d31a4 --- /dev/null +++ b/contrib/gen_manual/gen-lz4-manual.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +LIBVER_MAJOR_SCRIPT=`sed -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/lz4.h` +LIBVER_MINOR_SCRIPT=`sed -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/lz4.h` +LIBVER_PATCH_SCRIPT=`sed -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < ../../lib/lz4.h` +LIBVER_SCRIPT=$LIBVER_MAJOR_SCRIPT.$LIBVER_MINOR_SCRIPT.$LIBVER_PATCH_SCRIPT + +echo LZ4_VERSION=$LIBVER_SCRIPT +./gen_manual $LIBVER_SCRIPT ../../lib/lz4.h ./lz4_manual.html diff --git a/contrib/gen_manual/gen_manual.cpp b/contrib/gen_manual/gen_manual.cpp new file mode 100644 index 0000000..caf03fc --- /dev/null +++ b/contrib/gen_manual/gen_manual.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2016-present, Przemyslaw Skibinski + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +using namespace std; + + +/* trim string at the beginning and at the end */ +void trim(string& s, string characters) +{ + size_t p = s.find_first_not_of(characters); + s.erase(0, p); + + p = s.find_last_not_of(characters); + if (string::npos != p) + s.erase(p+1); +} + + +/* trim C++ style comments */ +void trim_comments(string &s) +{ + size_t spos, epos; + + spos = s.find("/*"); + epos = s.find("*/"); + s = s.substr(spos+3, epos-(spos+3)); +} + + +/* get lines until a given terminator */ +vector<string> get_lines(vector<string>& input, int& linenum, string terminator) +{ + vector<string> out; + string line; + size_t epos; + + while ((size_t)linenum < input.size()) { + line = input[linenum]; + + if (terminator.empty() && line.empty()) { linenum--; break; } + + epos = line.find(terminator); + if (!terminator.empty() && epos!=string::npos) { + out.push_back(line); + break; + } + out.push_back(line); + linenum++; + } + return out; +} + + +/* print line with LZ4LIB_API removed and C++ comments not bold */ +void print_line(stringstream &sout, string line) +{ + size_t spos; + + if (line.substr(0,11) == "LZ4LIB_API ") line = line.substr(11); + spos = line.find("/*"); + if (spos!=string::npos) { + sout << line.substr(0, spos); + sout << "</b>" << line.substr(spos) << "<b>" << endl; + } else { + // fprintf(stderr, "lines=%s\n", line.c_str()); + sout << line << endl; + } +} + + +int main(int argc, char *argv[]) { + char exclam; + int linenum, chapter = 1; + vector<string> input, lines, comments, chapters; + string line, version; + size_t spos, l; + stringstream sout; + ifstream istream; + ofstream ostream; + + if (argc < 4) { + cout << "usage: " << argv[0] << " [lz4_version] [input_file] [output_html]" << endl; + return 1; + } + + version = "lz4 " + string(argv[1]) + " Manual"; + + istream.open(argv[2], ifstream::in); + if (!istream.is_open()) { + cout << "Error opening file " << argv[2] << endl; + return 1; + } + + ostream.open(argv[3], ifstream::out); + if (!ostream.is_open()) { + cout << "Error opening file " << argv[3] << endl; + return 1; + } + + while (getline(istream, line)) { + input.push_back(line); + } + + for (linenum=0; (size_t)linenum < input.size(); linenum++) { + line = input[linenum]; + + /* typedefs are detected and included even if uncommented */ + if (line.substr(0,7) == "typedef" && line.find("{")!=string::npos) { + lines = get_lines(input, linenum, "}"); + sout << "<pre><b>"; + for (l=0; l<lines.size(); l++) { + print_line(sout, lines[l]); + } + sout << "</b></pre><BR>" << endl; + continue; + } + + /* comments of type /**< and /*!< are detected and only function declaration is highlighted (bold) */ + if ((line.find("/**<")!=string::npos || line.find("/*!<")!=string::npos) && line.find("*/")!=string::npos) { + sout << "<pre><b>"; + print_line(sout, line); + sout << "</b></pre><BR>" << endl; + continue; + } + + /* comments of type /*= and /**= mean: use a <H3> header and show also all functions until first empty line */ + if ((line.substr(0,3) == "/*=" || line.substr(0,4) == "/**=") && line.find("*/")!=string::npos) { + trim_comments(line); + trim(line, "= "); + sout << "<h3>" << line << "</h3><pre><b>"; + lines = get_lines(input, ++linenum, ""); + for (l=0; l<lines.size(); l++) { + print_line(sout, lines[l]); + } + sout << "</b></pre><BR>" << endl; + continue; + } + + spos = line.find("/*!"); + if (spos==string::npos) + spos = line.find("/**"); + if (spos==string::npos) + spos = line.find("/*-"); + + if (spos==string::npos) + continue; + + exclam = line[spos+2]; + comments = get_lines(input, linenum, "*/"); + if (!comments.empty()) comments[0] = line.substr(spos+3); + if (!comments.empty()) comments[comments.size()-1] = comments[comments.size()-1].substr(0, comments[comments.size()-1].find("*/")); + for (l=0; l<comments.size(); l++) { + if (comments[l].find(" *")==0) comments[l] = comments[l].substr(2); + else if (comments[l].find(" *")==0) comments[l] = comments[l].substr(3); + trim(comments[l], "*-"); + } + while (!comments.empty() && comments[comments.size()-1].empty()) comments.pop_back(); // remove empty line at the end + while (!comments.empty() && comments[0].empty()) comments.erase(comments.begin()); // remove empty line at the start + + /* comments of type /*! mean: this is a function declaration; switch comments with declarations */ + if (exclam == '!') { + if (!comments.empty()) comments.erase(comments.begin()); /* remove first line like "LZ4_XXX() :" */ + linenum++; + lines = get_lines(input, linenum, ""); + + sout << "<pre><b>"; + for (l=0; l<lines.size(); l++) { + // fprintf(stderr, "line[%d]=%s\n", l, lines[l].c_str()); + print_line(sout, lines[l]); + } + sout << "</b><p>"; + for (l=0; l<comments.size(); l++) { + print_line(sout, comments[l]); + } + sout << "</p></pre><BR>" << endl << endl; + } else { /* comments of type /** and /*- mean: this is a comment; use a <H2> header for the first line */ + if (comments.empty()) continue; + + trim(comments[0], " "); + sout << "<a name=\"Chapter" << chapter << "\"></a><h2>" << comments[0] << "</h2><pre>"; + chapters.push_back(comments[0]); + chapter++; + + for (l=1; l<comments.size(); l++) { + print_line(sout, comments[l]); + } + if (comments.size() > 1) + sout << "<BR></pre>" << endl << endl; + else + sout << "</pre>" << endl << endl; + } + } + + ostream << "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\">\n<title>" << version << "</title>\n</head>\n<body>" << endl; + ostream << "<h1>" << version << "</h1>\n"; + + ostream << "<hr>\n<a name=\"Contents\"></a><h2>Contents</h2>\n<ol>\n"; + for (size_t i=0; i<chapters.size(); i++) + ostream << "<li><a href=\"#Chapter" << i+1 << "\">" << chapters[i].c_str() << "</a></li>\n"; + ostream << "</ol>\n<hr>\n"; + + ostream << sout.str(); + ostream << "</html>" << endl << "</body>" << endl; + + return 0; +}
\ No newline at end of file diff --git a/doc/lz4_manual.html b/doc/lz4_manual.html new file mode 100644 index 0000000..838dbf4 --- /dev/null +++ b/doc/lz4_manual.html @@ -0,0 +1,240 @@ +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> +<title>lz4 1.7.2 Manual</title> +</head> +<body> +<h1>lz4 1.7.2 Manual</h1> +<hr> +<a name="Contents"></a><h2>Contents</h2> +<ol> +<li><a href="#Chapter1">Introduction</a></li> +<li><a href="#Chapter2">Tuning parameter</a></li> +<li><a href="#Chapter3">Simple Functions</a></li> +<li><a href="#Chapter4">Advanced Functions</a></li> +<li><a href="#Chapter5">Streaming Compression Functions</a></li> +<li><a href="#Chapter6">Streaming Decompression Functions</a></li> +</ol> +<hr> +<a name="Chapter1"></a><h2>Introduction</h2><pre> + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Block compression functions are not-enough to send information, + since it's still necessary to provide metadata (such as compressed size), + and each application can do it in whichever way it wants. + For interoperability, there is LZ4 frame specification (doc/lz4_Frame_format.md). + A library is provided to take care of it, see lz4frame.h. +<BR></pre> + +<h3>Version</h3><pre><b>int LZ4_versionNumber (void); +const char* LZ4_versionString (void); +</b></pre><BR> +<a name="Chapter2"></a><h2>Tuning parameter</h2><pre></pre> + +<pre><b>#define LZ4_MEMORY_USAGE 14 +</b><p> Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) + Increasing memory usage improves compression ratio + Reduced memory usage can improve speed, due to cache effect + Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache + +</p></pre><BR> + +<a name="Chapter3"></a><h2>Simple Functions</h2><pre></pre> + +<pre><b>int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); +</b><p> Compresses 'sourceSize' bytes from buffer 'source' + into already allocated 'dest' buffer of size 'maxDestSize'. + Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). + It also runs faster, so it's a recommended setting. + If the function cannot compress 'source' into a more limited 'dest' budget, + compression stops *immediately*, and the function result is zero. + As a consequence, 'dest' content is not valid. + This function never writes outside 'dest' buffer, nor read outside 'source' buffer. + sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE + maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) + return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) + or 0 if compression fails +</p></pre><BR> + +<pre><b>int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); +</b><p> compressedSize : is the precise full size of the compressed block. + maxDecompressedSize : is the size of destination buffer, which must be already allocated. + return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) + If destination buffer is not large enough, decoding will stop and output an error code (<0). + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function is protected against buffer overflow exploits, including malicious data packets. + It never writes outside output buffer, nor reads outside input buffer. +</p></pre><BR> + +<a name="Chapter4"></a><h2>Advanced Functions</h2><pre></pre> + +<pre><b>int LZ4_compressBound(int inputSize); +</b><p> Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) + This function is primarily useful for memory allocation purposes (destination buffer size). + Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). + Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + inputSize : max supported value is LZ4_MAX_INPUT_SIZE + return : maximum output size in a "worst case" scenario + or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) +</p></pre><BR> + +<pre><b>int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); +</b><p> Same as LZ4_compress_default(), but allows to select an "acceleration" factor. + The larger the acceleration value, the faster the algorithm, but also the lesser the compression. + It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. + An acceleration value of "1" is the same as regular LZ4_compress_default() + Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. +</p></pre><BR> + +<pre><b>int LZ4_sizeofState(void); +int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); +</b><p> Same compression function, just using an externally allocated memory space to store compression state. + Use LZ4_sizeofState() to know how much memory must be allocated, + and allocate it on 8-bytes boundaries (using malloc() typically). + Then, provide it as 'void* state' to compression function. +</p></pre><BR> + +<pre><b>int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); +</b><p> Reverse the logic, by compressing as much data as possible from 'source' buffer + into already allocated buffer 'dest' of size 'targetDestSize'. + This function either compresses the entire 'source' content into 'dest' if it's large enough, + or fill 'dest' buffer completely with as much data as possible from 'source'. + *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. + New value is necessarily <= old value. + return : Nb bytes written into 'dest' (necessarily <= targetDestSize) + or 0 if compression fails +</p></pre><BR> + +<pre><b>int LZ4_decompress_fast (const char* source, char* dest, int originalSize); +</b><p> originalSize : is the original and therefore uncompressed size + return : the number of bytes read from the source buffer (in other words, the compressed size) + If the source stream is detected malformed, the function will stop decoding and return a negative result. + Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. + note : This function fully respect memory boundaries for properly formed compressed data. + It is a bit faster than LZ4_decompress_safe(). + However, it does not provide any protection against intentionally modified data stream (malicious input). + Use this function in trusted environment only (data to decode comes from a trusted source). +</p></pre><BR> + +<pre><b>int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); +</b><p> This function decompress a compressed block of size 'compressedSize' at position 'source' + into destination buffer 'dest' of size 'maxDecompressedSize'. + The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, + reducing decompression time. + return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) + Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. + Always control how many bytes were decoded. + If the source stream is detected malformed, the function will stop decoding and return a negative result. + This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets +</p></pre><BR> + +<a name="Chapter5"></a><h2>Streaming Compression Functions</h2><pre></pre> + +<pre><b>typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; +</b><p> information structure to track an LZ4 stream. + important : init this structure content before first use ! + note : only allocated directly the structure if you are statically linking LZ4 + If you are using liblz4 as a DLL, please use below construction methods instead. + +</p></pre><BR> + +<pre><b>void LZ4_resetStream (LZ4_stream_t* streamPtr); +</b><p> Use this function to init an allocated `LZ4_stream_t` structure + +</p></pre><BR> + +<pre><b>LZ4_stream_t* LZ4_createStream(void); +int LZ4_freeStream (LZ4_stream_t* streamPtr); +</b><p> LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. + LZ4_freeStream() releases its memory. + In the context of a DLL (liblz4), please use these methods rather than the static struct. + They are more future proof, in case of a change of `LZ4_stream_t` size. + +</p></pre><BR> + +<pre><b>int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); +</b><p> Use this function to load a static dictionary into LZ4_stream. + Any previous data will be forgotten, only 'dictionary' will remain in memory. + Loading a size of 0 is allowed. + Return : dictionary size, in bytes (necessarily <= 64 KB) + +</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); +</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 ! + 'dst' buffer must be already allocated. + If maxDstSize >= 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. + +</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, + 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. + +</p></pre><BR> + +<a name="Chapter6"></a><h2>Streaming Decompression Functions</h2><pre></pre> + +<pre><b>typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; +</b></pre><BR> +<pre><b>LZ4_streamDecode_t* LZ4_createStreamDecode(void); +int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); +</b><p> information structure to track an LZ4 stream. + init this structure content using LZ4_setStreamDecode or memset() before first use ! + + In the context of a DLL (liblz4) please prefer usage of construction methods below. + They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. + LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure + LZ4_freeStreamDecode releases its memory. + +</p></pre><BR> + +<pre><b>int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); +</b><p> Use this function to instruct where to find the dictionary. + Setting a size of 0 is allowed (same effect as reset). + @return : 1 if OK, 0 if error + +</p></pre><BR> + +<pre><b>int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); +int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); +</b><p> These decoding functions allow decompression of multiple blocks in "streaming" mode. + Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) + In the case of a ring buffers, decoding buffer must be either : + - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) + In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). + - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. + maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including small ones ( < 64 KB). + - _At least_ 64 KB + 8 bytes + maxBlockSize. + In which case, encoding and decoding buffers do not need to be synchronized, + and encoding ring buffer can have any size, including larger than decoding buffer. + Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, + and indicate where it is saved using LZ4_setStreamDecode() +</p></pre><BR> + +<pre><b>int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); +int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); +</b><p>Advanced decoding functions : + These decoding functions work the same as + a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() + They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. +</p></pre><BR> + +</html> +</body> diff --git a/lib/README.md b/lib/README.md index 209cac1..051ef54 100644 --- a/lib/README.md +++ b/lib/README.md @@ -1,22 +1,26 @@ LZ4 - Library Files ================================ -All source material within __lib__ directory are BSD 2-Clause licensed. -See [LICENSE](LICENSE) for details. -The license is also repeated at the top of each source file. - The directory contains many files, but depending on project's objectives, not all of them are necessary. +#### Minimal LZ4 build + The minimum required is **`lz4.c`** and **`lz4.h`**, which will provide the fast compression and decompression algorithm. + +#### The High Compression variant od LZ4 + For more compression at the cost of compression speed, the High Compression variant **lz4hc** is available. It's necessary to add **`lz4hc.c`** and **`lz4hc.h`**. The variant still depends on regular `lz4` source files. In particular, the decompression is still provided by `lz4.c`. + +#### Compatibility issues + In order to produce files or streams compatible with `lz4` command line utility, it's necessary to encode lz4-compressed blocks using the [official interoperable frame format]. This format is generated and decoded automatically by the **lz4frame** library. @@ -26,10 +30,28 @@ which provides error detection. This is what `liblz4` does, to avoid symbol duplication in case a user program would link to several libraries containing xxhash symbols.) + +#### Advanced API + A more complex `lz4frame_static.h` is also provided. It contains definitions which are not guaranteed to remain stable within future versions. It must be used with static linking ***only***. + +#### Using MinGW+MSYS to create DLL + +DLL can be created using MinGW+MSYS with the "make liblz4" command. +This command creates "liblz4.dll" and the import library "liblz4.dll.a". +To compile a project the import library has to be added to linking options. +It means that if a project that uses LZ4 consists of a single test-dll.c +file it should be compiled with "liblz4.dll.a". For example: +``` + gcc $CFLAGS test-dll.c -o test-dll liblz4.dll.a +``` + + +#### Miscellaneous + Other files present in the directory are not source code. There are : - LICENSE : contains the BSD license text @@ -38,3 +60,10 @@ Other files present in the directory are not source code. There are : - README.md : this file [official interoperable frame format]: ../doc/lz4_Frame_format.md + + +#### License + +All source material within __lib__ directory are BSD 2-Clause licensed. +See [LICENSE](LICENSE) for details. +The license is also repeated at the top of each source file. @@ -39,19 +39,31 @@ extern "C" { #endif -/* - * lz4.h provides block compression functions. It gives full buffer control to user. - * Block compression functions are not-enough to send information, - * since it's still necessary to provide metadata (such as compressed size), - * and each application can do it in whichever way it wants. - * For interoperability, there is LZ4 frame specification (doc/lz4_Frame_format.md). - * A library is provided to take care of it, see lz4frame.h. +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h provides block compression functions. It gives full buffer control to user. + Block compression functions are not-enough to send information, + since it's still necessary to provide metadata (such as compressed size), + and each application can do it in whichever way it wants. + For interoperability, there is LZ4 frame specification (doc/lz4_Frame_format.md). + A library is provided to take care of it, see lz4frame.h. */ -/*-*************************************************************** +/*^*************************************************************** * Export parameters *****************************************************************/ -/*! +/* * LZ4_DLL_EXPORT : * Enable exporting of functions when building a Windows DLL */ @@ -64,27 +76,26 @@ extern "C" { #endif -/*-************************************ -* Version -**************************************/ +/*========== Version =========== */ +LZ4LIB_API int LZ4_versionNumber (void); +LZ4LIB_API const char* LZ4_versionString (void); + #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ #define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */ #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) -LZ4LIB_API int LZ4_versionNumber (void); #define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE #define LZ4_QUOTE(str) #str #define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) #define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) -LZ4LIB_API const char* LZ4_versionString (void); /*-************************************ * Tuning parameter **************************************/ -/* +/*! * LZ4_MEMORY_USAGE : * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) * Increasing memory usage improves compression ratio @@ -97,12 +108,7 @@ LZ4LIB_API const char* LZ4_versionString (void); /*-************************************ * Simple Functions **************************************/ - -LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); -LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); - -/* -LZ4_compress_default() : +/*! LZ4_compress_default() : Compresses 'sourceSize' bytes from buffer 'source' into already allocated 'dest' buffer of size 'maxDestSize'. Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). @@ -114,9 +120,10 @@ LZ4_compress_default() : sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails + or 0 if compression fails */ +LZ4LIB_API int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); -LZ4_decompress_safe() : +/*! LZ4_decompress_safe() : compressedSize : is the precise full size of the compressed block. maxDecompressedSize : is the size of destination buffer, which must be already allocated. return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) @@ -125,6 +132,7 @@ LZ4_decompress_safe() : This function is protected against buffer overflow exploits, including malicious data packets. It never writes outside output buffer, nor reads outside input buffer. */ +LZ4LIB_API int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); /*-************************************ @@ -214,7 +222,7 @@ LZ4LIB_API int LZ4_decompress_safe_partial (const char* source, char* dest, int ***********************************************/ #define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) #define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) -/* +/*! * LZ4_stream_t : * information structure to track an LZ4 stream. * important : init this structure content before first use ! @@ -228,7 +236,8 @@ typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; */ LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); -/*! LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. +/*! LZ4_createStream() and LZ4_freeStream() : + * LZ4_createStream() will allocate and initialize an `LZ4_stream_t` structure. * LZ4_freeStream() releases its memory. * In the context of a DLL (liblz4), please use these methods rather than the static struct. * They are more future proof, in case of a change of `LZ4_stream_t` size. @@ -270,7 +279,7 @@ LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dict #define LZ4_STREAMDECODESIZE_U64 4 #define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; -/* +/*! * LZ4_streamDecode_t * information structure to track an LZ4 stream. * init this structure content using LZ4_setStreamDecode or memset() before first use ! @@ -290,7 +299,7 @@ LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_str */ LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); -/* +/*! *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) @@ -311,9 +320,9 @@ LZ4LIB_API int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecod LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); -/* -Advanced decoding functions : +/*! *_usingDict() : +Advanced decoding functions : These decoding functions work the same as a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. diff --git a/programs/bench.c b/programs/bench.c index c493682..cfd60db 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -122,7 +122,6 @@ void BMK_SetNbSeconds(unsigned nbSeconds) void BMK_SetBlockSize(size_t blockSize) { g_blockSize = blockSize; - DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); } @@ -494,6 +493,11 @@ int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, { double const compressibility = (double)g_compressibilityDefault / 100; + if (cLevel > LZ4HC_MAX_CLEVEL) cLevel = LZ4HC_MAX_CLEVEL; + if (cLevelLast > LZ4HC_MAX_CLEVEL) cLevelLast = LZ4HC_MAX_CLEVEL; + if (cLevelLast < cLevel) cLevelLast = cLevel; + if (cLevelLast > cLevel) DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast); + if (nbFiles == 0) BMK_syntheticTest(cLevel, cLevelLast, compressibility); else diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 1f6b391..1f25a21 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -161,7 +161,7 @@ static int usage_advanced(const char* exeName) DISPLAY( " -r : operate recursively on directories (sets also -m)\n"); #endif DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\n"); - DISPLAY( " -B# : Block size [4-7](default : 7)\n"); + DISPLAY( " -B# : Block size [4-7] (default : 7)\n"); DISPLAY( " -BD : Block dependency (improve compression ratio)\n"); /* DISPLAY( " -BX : enable block checksum (default:disabled)\n"); *//* Option currently inactive */ DISPLAY( "--no-frame-crc : disable stream checksum (default:enabled)\n"); @@ -171,6 +171,8 @@ static int usage_advanced(const char* exeName) DISPLAY( " -b# : benchmark file(s), using # compression level (default : 1) \n"); DISPLAY( " -e# : test all compression levels from -bX to # (default : 1)\n"); DISPLAY( " -i# : minimum evaluation time in seconds (default : 3s)\n"); + DISPLAY( " -B# : cut file into independent blocks of size # bytes [32+]\n"); + DISPLAY( " or predefined block size [4-7] (default: 7)\n"); #if defined(ENABLE_LZ4C_LEGACY_OPTIONS) DISPLAY( "Legacy arguments :\n"); DISPLAY( " -c0 : fast compression\n"); @@ -417,20 +419,33 @@ int main(int argc, const char** argv) int exitBlockProperties=0; switch(argument[1]) { - case '4': - case '5': - case '6': - case '7': - { int const B = argument[1] - '0'; - blockSize = LZ4IO_setBlockSizeID(B); - BMK_setNotificationLevel(displayLevel); - BMK_SetBlockSize(blockSize); + case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break; + case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* disabled by default */ + default : + if (argument[1] < '0' || argument[1] > '9') { + exitBlockProperties=1; + break; + } else { + unsigned B; argument++; + B = readU32FromChar(&argument); + argument--; + if (B < 4) badusage(exeName); + if (B <= 7) { + blockSize = LZ4IO_setBlockSizeID(B); + BMK_SetBlockSize(blockSize); + DISPLAYLEVEL(2, "using blocks of size %u KB \n", (U32)(blockSize>>10)); + } else { + if (B < 32) badusage(exeName); + BMK_SetBlockSize(B); + if (B >= 1024) { + DISPLAYLEVEL(2, "bench: using blocks of size %u KB \n", (U32)(B>>10)); + } else { + DISPLAYLEVEL(2, "bench: using blocks of size %u bytes \n", (U32)(B)); + } + } break; } - case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break; - case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* disabled by default */ - default : exitBlockProperties=1; } if (exitBlockProperties) break; } diff --git a/programs/lz4io.c b/programs/lz4io.c index 61d8009..725d3a8 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -301,7 +301,7 @@ static FILE* LZ4IO_openDstFile(const char* dstFileName) } /* sparse file */ - if (f && g_sparseFileSupport) { SET_SPARSE_FILE_MODE(foutput); } + if (f && g_sparseFileSupport) { SET_SPARSE_FILE_MODE(f); } return f; } diff --git a/tests/Makefile b/tests/Makefile index 16771da..2b88f73 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -39,7 +39,7 @@ MANDIR := $(PREFIX)/share/man/man1 LZ4DIR := ../lib PRGDIR := ../programs TESTDIR := versionsTest -PYTHON?= python3 +PYTHON ?= python3 CFLAGS ?= -O3 # can select custom flags. For example : CFLAGS="-O2 -g" make CFLAGS += -Wall -Wextra -Wundef -Wcast-qual -Wcast-align -Wshadow -Wswitch-enum -Wdeclaration-after-statement -Wstrict-prototypes @@ -58,7 +58,8 @@ endif # Default test parameters TEST_FILES := COPYING -FUZZER_TIME := -T9mn +FUZZER_TIME := -T3mn +NB_LOOPS ?= -i1 default: bins @@ -114,6 +115,7 @@ datagen : $(PRGDIR)/datagen.c datagencli.c clean: @$(MAKE) -C $(LZ4DIR) $@ > $(VOID) @$(RM) core *.o *.test tmp* \ + fullbench-dll$(EXT) fullbench-lib$(EXT) \ fullbench$(EXT) fullbench32$(EXT) \ fuzzer$(EXT) fuzzer32$(EXT) \ frametest$(EXT) frametest32$(EXT) \ diff --git a/tests/README.md b/tests/README.md index 9070317..75b7b9f 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,6 +6,7 @@ This directory contains the following programs and scripts: - `frametest` : Test tool that checks lz4frame integrity on target platform - `fullbench` : Precisely measure speed for each lz4 inner functions - `fuzzer` : Test tool, to check lz4 integrity on target platform +- `test-lz4-speed.py` : script for testing lz4 speed difference between commits - `test-lz4-versions.py` : compatibility test between lz4 versions stored on Github @@ -16,6 +17,53 @@ Then all taged (released) versions of lz4 are compiled. In the following step interoperability between lz4 versions is checked. +#### `test-lz4-speed.py` - script for testing lz4 speed difference between commits + +This script creates `speedTest` directory to which lz4 repository is cloned. +Then it compiles all branches of lz4 and performs a speed benchmark for a given list of files (the `testFileNames` parameter). +After `sleepTime` (an optional parameter, default 300 seconds) seconds the script checks repository for new commits. +If a new commit is found it is compiled and a speed benchmark for this commit is performed. +The results of the speed benchmark are compared to the previous results. +If compression or decompression speed for one of lz4 levels is lower than `lowerLimit` (an optional parameter, default 0.98) the speed benchmark is restarted. +If second results are also lower than `lowerLimit` the warning e-mail is send to recipients from the list (the `emails` parameter). + +Additional remarks: +- To be sure that speed results are accurate the script should be run on a "stable" target system with no other jobs running in parallel +- Using the script with virtual machines can lead to large variations of speed results +- The speed benchmark is not performed until computers' load average is lower than `maxLoadAvg` (an optional parameter, default 0.75) +- The script sends e-mails using `mutt`; if `mutt` is not available it sends e-mails without attachments using `mail`; if both are not available it only prints a warning + + +The example usage with two test files, one e-mail address, and with an additional message: +``` +./test-lz4-speed.py "silesia.tar calgary.tar" "email@gmail.com" --message "tested on my laptop" --sleepTime 60 +``` + +To run the script in background please use: +``` +nohup ./test-lz4-speed.py testFileNames emails & +``` + +The full list of parameters: +``` +positional arguments: + testFileNames file names list for speed benchmark + emails list of e-mail addresses to send warnings + +optional arguments: + -h, --help show this help message and exit + --message MESSAGE attach an additional message to e-mail + --lowerLimit LOWERLIMIT + send email if speed is lower than given limit + --maxLoadAvg MAXLOADAVG + maximum load average to start testing + --lastCLevel LASTCLEVEL + last compression level for testing + --sleepTime SLEEPTIME + frequency of repository checking in seconds +``` + + #### License All files in this directory are licensed under GPL-v2. |