diff options
46 files changed, 1093 insertions, 246 deletions
diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 0000000..0c0e7a7 --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,5 @@ +freebsd_instance: + image_family: freebsd-12-1 + +task: + script: pkg install -y gmake && gmake test diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..86b7696 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**Expected behavior** +Please describe what you expected to happen. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error '...' +If applicable, add screenshots to help explain your problem. + +**System (please complete the following information):** + - OS: [e.g. Mac] + - Version [e.g. 22] + - Compiler [e.g. gcc] + - Build System [e.g. Makefile] + - Other hardware specs [e.g Core 2 duo...] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..bbcbbe7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. @@ -26,6 +26,9 @@ _codelite_lz4/ bin/ *.zip +# analyzers +infer-out + # Mac .DS_Store *.dSYM @@ -1,3 +1,21 @@ +v1.9.3 +perf: faster speed on Visual Studio, by @wolfpld + + +v1.9.2 +fix : out-of-bound read in exceptional circumstances when using decompress_partial(), by @terrelln +fix : slim opportunity for out-of-bound write with compress_fast() with a large enough input and when providing an output smaller than recommended (< LZ4_compressBound(inputSize)), by @terrelln +fix : rare data corruption bug with LZ4_compress_destSize(), by @terrelln +fix : data corruption bug when Streaming with an Attached Dict in HC Mode, by @felixhandte +perf: enable LZ4_FAST_DEC_LOOP on aarch64/GCC by default, by @prekageo +perf: improved lz4frame streaming API speed, by @dreambottle +perf: speed up lz4hc on slow patterns when using external dictionary, by @terrelln +api: better in-place decompression and compression support +cli : --list supports multi-frames files, by @gstedman +cli: --version outputs to stdout +cli : add option --best as an alias of -12 , by @Low-power +misc: Integration into oss-fuzz by @cmeister2, expanded list of scenarios by @terrelln + v1.9.1 fix : decompression functions were reading a few bytes beyond input size (introduced in v1.9.0, reported by @ppodolsky and @danlark1) api : fix : lz4frame initializers compatibility with c++, reported by @degski @@ -95,6 +95,17 @@ It is compatible with parallel builds (`-j#`). [redirection]: https://www.gnu.org/prep/standards/html_node/Directory-Variables.html [command redefinition]: https://www.gnu.org/prep/standards/html_node/Utilities-in-Makefiles.html +Building LZ4 - Using vcpkg + +You can download and install LZ4 using the [vcpkg](https://github.com/Microsoft/vcpkg) dependency manager: + + git clone https://github.com/Microsoft/vcpkg.git + cd vcpkg + ./bootstrap-vcpkg.sh + ./vcpkg integrate install + vcpkg install lz4 + +The LZ4 port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository. Documentation ------------------------- diff --git a/contrib/meson/meson.build b/contrib/meson/meson.build index 65a4c26..d1e97d9 100644 --- a/contrib/meson/meson.build +++ b/contrib/meson/meson.build @@ -7,6 +7,10 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# +# This is a dummy meson file. +# The intention is that it can be easily moved to the root of the project +# (together with meson_options.txt) and packaged for wrapdb. + project('lz4', ['c'], license: ['BSD', 'GPLv2'], default_options : ['c_std=c99', @@ -14,112 +18,4 @@ project('lz4', ['c'], version: 'DUMMY', meson_version: '>=0.47.0') -cc = meson.get_compiler('c') -pkgconfig = import('pkgconfig') -python3 = import('python').find_installation() -c_std = get_option('c_std') -default_library = get_option('default_library') - -host_machine_os = host_machine.system() -os_windows = 'windows' -os_linux = 'linux' -os_darwin = 'darwin' -os_freebsd = 'freebsd' -os_sun = 'sunos' - -cc_id = cc.get_id() -compiler_gcc = 'gcc' -compiler_clang = 'clang' -compiler_msvc = 'msvc' - -lz4_version = meson.project_version() - -lz4_h_file = join_paths(meson.current_source_dir(), '../../lib/lz4.h') -GetLz4LibraryVersion_py = files('GetLz4LibraryVersion.py') -r = run_command(python3, GetLz4LibraryVersion_py, lz4_h_file) -if r.returncode() == 0 - lz4_version = r.stdout().strip() - message('Project version is now: @0@'.format(lz4_version)) -else - error('Cannot find project version in @0@'.format(lz4_h_file)) -endif - -lz4_libversion = lz4_version - -# ============================================================================= -# Installation directories -# ============================================================================= - -lz4_prefix = get_option('prefix') -lz4_bindir = get_option('bindir') -lz4_datadir = get_option('datadir') -lz4_mandir = get_option('mandir') -lz4_docdir = join_paths(lz4_datadir, 'doc', meson.project_name()) - -# ============================================================================= -# Project options -# ============================================================================= - -buildtype = get_option('buildtype') - -# Built-in options -use_debug = get_option('debug') - -# Custom options -debug_level = get_option('debug_level') -use_backtrace = get_option('backtrace') - -bin_programs = get_option('bin_programs') -bin_contrib = get_option('bin_contrib') -bin_tests = get_option('bin_tests') -bin_examples = get_option('bin_examples') -#feature_multi_thread = get_option('multi_thread') - -# ============================================================================= -# Dependencies -# ============================================================================= - -#libm_dep = cc.find_library('m', required: bin_tests) -#thread_dep = dependency('threads', required: feature_multi_thread) -#use_multi_thread = thread_dep.found() - -# ============================================================================= -# Compiler flags -# ============================================================================= - -add_project_arguments(['-DXXH_NAMESPACE=LZ4_'], language: 'c') - -if [compiler_gcc, compiler_clang].contains(cc_id) - common_warning_flags = [] - # Should use Meson's own --werror build option - #common_warning_flags += ['-Werror'] - if c_std == 'c89' or c_std == 'gnu89' - common_warning_flags += ['-pedantic', '-Wno-long-long', '-Wno-variadic-macros'] - elif c_std == 'c99' or c_std == 'gnu99' - common_warning_flags += ['-pedantic'] - endif - cc_compile_flags = cc.get_supported_arguments(common_warning_flags) - add_project_arguments(cc_compile_flags, language: 'c') -endif - -# ============================================================================= -# Subdirs -# ============================================================================= - -subdir('lib') - -if bin_programs - subdir('programs') -endif - -if bin_tests - subdir('tests') -endif - -if bin_contrib - subdir('contrib') -endif - -if bin_examples - subdir('examples') -endif +subdir('meson') diff --git a/contrib/meson/GetLz4LibraryVersion.py b/contrib/meson/meson/GetLz4LibraryVersion.py index d8abfcb..d8abfcb 100644 --- a/contrib/meson/GetLz4LibraryVersion.py +++ b/contrib/meson/meson/GetLz4LibraryVersion.py diff --git a/contrib/meson/InstallSymlink.py b/contrib/meson/meson/InstallSymlink.py index 3f2998c..3f2998c 100644 --- a/contrib/meson/InstallSymlink.py +++ b/contrib/meson/meson/InstallSymlink.py diff --git a/contrib/meson/contrib/gen_manual/meson.build b/contrib/meson/meson/contrib/gen_manual/meson.build index 38180e9..a872bd6 100644 --- a/contrib/meson/contrib/gen_manual/meson.build +++ b/contrib/meson/meson/contrib/gen_manual/meson.build @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# -lz4_root_dir = '../../../..' +lz4_root_dir = '../../../../..' add_languages('cpp') cxx = meson.get_compiler('cpp') diff --git a/contrib/meson/contrib/meson.build b/contrib/meson/meson/contrib/meson.build index 5249a4c..5249a4c 100644 --- a/contrib/meson/contrib/meson.build +++ b/contrib/meson/meson/contrib/meson.build diff --git a/contrib/meson/examples/meson.build b/contrib/meson/meson/examples/meson.build index 3c13214..493049d 100644 --- a/contrib/meson/examples/meson.build +++ b/contrib/meson/meson/examples/meson.build @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# -lz4_root_dir = '../../..' +lz4_root_dir = '../../../..' #examples_c_args = ['-Wextra', '-Wundef', '-Wshadow', '-Wcast-align', '-Wstrict-prototypes'] diff --git a/contrib/meson/lib/meson.build b/contrib/meson/meson/lib/meson.build index e782334..131edcb 100644 --- a/contrib/meson/lib/meson.build +++ b/contrib/meson/meson/lib/meson.build @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# -lz4_root_dir = '../../..' +lz4_root_dir = '../../../..' liblz4_includes = [include_directories(join_paths(lz4_root_dir, 'lib'))] liblz4_sources = [join_paths(lz4_root_dir, 'lib/lz4.c'), diff --git a/contrib/meson/meson/meson.build b/contrib/meson/meson/meson.build new file mode 100644 index 0000000..387e7bd --- /dev/null +++ b/contrib/meson/meson/meson.build @@ -0,0 +1,118 @@ +# ############################################################################# +# Copyright (c) 2018-present lzutao <taolzu(at)gmail.com> +# All rights reserved. +# +# This source code is licensed under both the BSD-style license (found in the +# LICENSE file in the root directory of this source tree) and the GPLv2 (found +# in the COPYING file in the root directory of this source tree). +# ############################################################################# + +cc = meson.get_compiler('c') +pkgconfig = import('pkgconfig') +python3 = import('python').find_installation() +c_std = get_option('c_std') +default_library = get_option('default_library') + +host_machine_os = host_machine.system() +os_windows = 'windows' +os_linux = 'linux' +os_darwin = 'darwin' +os_freebsd = 'freebsd' +os_sun = 'sunos' + +cc_id = cc.get_id() +compiler_gcc = 'gcc' +compiler_clang = 'clang' +compiler_msvc = 'msvc' + +lz4_version = meson.project_version() + +lz4_h_file = join_paths(meson.current_source_dir(), '../../../lib/lz4.h') +GetLz4LibraryVersion_py = files('GetLz4LibraryVersion.py') +r = run_command(python3, GetLz4LibraryVersion_py, lz4_h_file) +if r.returncode() == 0 + lz4_version = r.stdout().strip() + message('Project version is now: @0@'.format(lz4_version)) +else + error('Cannot find project version in @0@'.format(lz4_h_file)) +endif + +lz4_libversion = lz4_version + +# ============================================================================= +# Installation directories +# ============================================================================= + +lz4_prefix = get_option('prefix') +lz4_bindir = get_option('bindir') +lz4_datadir = get_option('datadir') +lz4_mandir = get_option('mandir') +lz4_docdir = join_paths(lz4_datadir, 'doc', meson.project_name()) + +# ============================================================================= +# Project options +# ============================================================================= + +buildtype = get_option('buildtype') + +# Built-in options +use_debug = get_option('debug') + +# Custom options +debug_level = get_option('debug_level') +use_backtrace = get_option('backtrace') + +bin_programs = get_option('bin_programs') +bin_contrib = get_option('bin_contrib') +bin_tests = get_option('bin_tests') +bin_examples = get_option('bin_examples') +#feature_multi_thread = get_option('multi_thread') + +# ============================================================================= +# Dependencies +# ============================================================================= + +#libm_dep = cc.find_library('m', required: bin_tests) +#thread_dep = dependency('threads', required: feature_multi_thread) +#use_multi_thread = thread_dep.found() + +# ============================================================================= +# Compiler flags +# ============================================================================= + +add_project_arguments(['-DXXH_NAMESPACE=LZ4_'], language: 'c') + +if [compiler_gcc, compiler_clang].contains(cc_id) + common_warning_flags = [] + # Should use Meson's own --werror build option + #common_warning_flags += ['-Werror'] + if c_std == 'c89' or c_std == 'gnu89' + common_warning_flags += ['-pedantic', '-Wno-long-long', '-Wno-variadic-macros'] + elif c_std == 'c99' or c_std == 'gnu99' + common_warning_flags += ['-pedantic'] + endif + cc_compile_flags = cc.get_supported_arguments(common_warning_flags) + add_project_arguments(cc_compile_flags, language: 'c') +endif + +# ============================================================================= +# Subdirs +# ============================================================================= + +subdir('lib') + +if bin_programs + subdir('programs') +endif + +if bin_tests + subdir('tests') +endif + +if bin_contrib + subdir('contrib') +endif + +if bin_examples + subdir('examples') +endif diff --git a/contrib/meson/programs/meson.build b/contrib/meson/meson/programs/meson.build index df64eb0..705dbf5 100644 --- a/contrib/meson/programs/meson.build +++ b/contrib/meson/meson/programs/meson.build @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# -lz4_root_dir = '../../..' +lz4_root_dir = '../../../..' lz4_includes = include_directories(join_paths(lz4_root_dir, 'programs')) lz4_sources = [join_paths(lz4_root_dir, 'programs/bench.c'), diff --git a/contrib/meson/tests/meson.build b/contrib/meson/meson/tests/meson.build index 392bcf2..7800475 100644 --- a/contrib/meson/tests/meson.build +++ b/contrib/meson/meson/tests/meson.build @@ -7,7 +7,7 @@ # in the COPYING file in the root directory of this source tree). # ############################################################################# -lz4_root_dir = '../../..' +lz4_root_dir = '../../../..' programs_dir_inc = include_directories(join_paths(lz4_root_dir, 'programs')) lib_dir_inc = include_directories(join_paths(lz4_root_dir, 'lib')) diff --git a/examples/frameCompress.c b/examples/frameCompress.c index a189329..aac4a3b 100644 --- a/examples/frameCompress.c +++ b/examples/frameCompress.c @@ -32,12 +32,12 @@ static void safe_fwrite(void* buf, size_t eltSize, size_t nbElt, FILE* f) { size_t const writtenSize = fwrite(buf, eltSize, nbElt, f); size_t const expectedSize = eltSize * nbElt; - assert(expectedSize / nbElt == eltSize); /* check overflow */ + if (nbElt>0) assert(expectedSize / nbElt == eltSize); /* check overflow */ if (writtenSize < expectedSize) { if (ferror(f)) /* note : ferror() must follow fwrite */ fprintf(stderr, "Write failed \n"); else - fprintf(stderr, "Short write \n"); + fprintf(stderr, "Write too short \n"); exit(1); } } diff --git a/examples/streaming_api_basics.md b/examples/streaming_api_basics.md index 90065e4..1ccc6e3 100644 --- a/examples/streaming_api_basics.md +++ b/examples/streaming_api_basics.md @@ -10,7 +10,7 @@ LZ4 has the following API sets : such as LZ4 command line utility, node-lz4, etc. - "Block" API : This is recommended for simple purpose. It compress single raw memory block to LZ4 memory block and vice versa. - - "Streaming" API : This is designed for complex thing. + - "Streaming" API : This is designed for complex things. For example, compress huge stream data in restricted memory environment. Basically, you should use "Auto Framing" API. @@ -19,13 +19,13 @@ But if you want to write advanced application, it's time to use Block or Streami ## What is difference between Block and Streaming API ? -Block API (de)compresses single contiguous memory block. -In other words, LZ4 library find redundancy from single contiguous memory block. -Streaming API does same thing but (de)compress multiple adjacent contiguous memory block. +Block API (de)compresses a single contiguous memory block. +In other words, LZ4 library finds redundancy from a single contiguous memory block. +Streaming API does same thing but (de)compresses multiple adjacent contiguous memory blocks. So LZ4 library could find more redundancy than Block API. The following figure shows difference between API and block sizes. -In these figures, original data is splitted to 4KiBytes contiguous chunks. +In these figures, the original data is split into 4KiBytes contiguous chunks. ``` Original Data @@ -81,7 +81,7 @@ This dependency improves compression ratio. ## Restriction of Streaming API -For the efficiency, Streaming API doesn't keep mirror copy of dependent (de)compressed memory. +For efficiency, Streaming API doesn't keep a mirror copy of dependent (de)compressed memory. This means users should keep these dependent (de)compressed memory explicitly. Usually, "Dependent memory" is previous adjacent contiguous memory up to 64KiBytes. LZ4 will not access further memories. @@ -225,15 +225,15 @@ static const int LZ4_minLength = (MFLIMIT+1); #if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) # include <stdio.h> -static int g_debuglog_enable = 1; -# define DEBUGLOG(l, ...) { \ - if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ - fprintf(stderr, __FILE__ ": "); \ - fprintf(stderr, __VA_ARGS__); \ - fprintf(stderr, " \n"); \ - } } + static int g_debuglog_enable = 1; +# define DEBUGLOG(l, ...) { \ + if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ ": "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } #else -# define DEBUGLOG(l, ...) {} /* disabled */ +# define DEBUGLOG(l, ...) {} /* disabled */ #endif @@ -249,6 +249,10 @@ static int g_debuglog_enable = 1; typedef uint64_t U64; typedef uintptr_t uptrval; #else +# include <limits.h> +# if UINT_MAX != 4294967295UL +# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" +# endif typedef unsigned char BYTE; typedef unsigned short U16; typedef unsigned int U32; @@ -370,12 +374,12 @@ static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3}; #ifndef LZ4_FAST_DEC_LOOP -# if defined(__i386__) || defined(__x86_64__) +# if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64 # define LZ4_FAST_DEC_LOOP 1 # elif defined(__aarch64__) && !defined(__clang__) /* On aarch64, we disable this optimization for clang because on certain - * mobile chipsets and clang, it reduces performance. For more information - * refer to https://github.com/lz4/lz4/pull/707. */ + * mobile chipsets, performance is reduced with clang. For information + * refer to https://github.com/lz4/lz4/pull/707 */ # define LZ4_FAST_DEC_LOOP 1 # else # define LZ4_FAST_DEC_LOOP 0 @@ -628,7 +632,7 @@ int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, /*-****************************** * Compression functions ********************************/ -static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); @@ -636,7 +640,7 @@ static U32 LZ4_hash4(U32 sequence, tableType_t const tableType) return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -static U32 LZ4_hash5(U64 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; if (LZ4_isLittleEndian()) { @@ -654,7 +658,7 @@ LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tab return LZ4_hash4(LZ4_read32(p), tableType); } -static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) +LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { @@ -666,7 +670,7 @@ static void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) } } -static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) +LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { @@ -678,7 +682,7 @@ static void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t cons } } -static void LZ4_putPositionOnHash(const BYTE* p, U32 h, +LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) { @@ -703,7 +707,7 @@ LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_ * Assumption 1 : only valid if tableType == byU32 or byU16. * Assumption 2 : h is presumed valid (within limits of hash table) */ -static U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) +LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) { LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); if (tableType == byU32) { @@ -815,7 +819,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ - const BYTE* const dictEnd = dictionary + dictSize; + const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; @@ -823,7 +827,7 @@ LZ4_FORCE_INLINE int LZ4_compress_generic( /* the dictCtx currentOffset is indexed on the start of the dictionary, * while a dictionary in the current context precedes the currentOffset */ - const BYTE* dictBase = (dictDirective == usingDictCtx) ? + const BYTE* dictBase = !dictionary ? NULL : (dictDirective == usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; @@ -1345,8 +1349,8 @@ LZ4_stream_t* LZ4_createStream(void) while actually aligning LZ4_stream_t on 4 bytes. */ static size_t LZ4_stream_t_alignment(void) { - struct { char c; LZ4_stream_t t; } t_a; - return sizeof(t_a) - sizeof(t_a.t); + typedef struct { char c; LZ4_stream_t t; } t_a; + return sizeof(t_a) - sizeof(LZ4_stream_t); } #endif @@ -1625,8 +1629,8 @@ typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_err LZ4_FORCE_INLINE unsigned read_variable_length(const BYTE**ip, const BYTE* lencheck, int loop_check, int initial_check, variable_length_error* error) { - unsigned length = 0; - unsigned s; + U32 length = 0; + U32 s; if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */ *error = initial_error; return length; diff --git a/lib/lz4frame.c b/lib/lz4frame.c index c9f630d..5d716ea 100644 --- a/lib/lz4frame.c +++ b/lib/lz4frame.c @@ -725,6 +725,9 @@ size_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr, */ size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr) { + if (preferencesPtr && preferencesPtr->autoFlush) { + return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0); + } return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1); } diff --git a/lib/lz4frame.h b/lib/lz4frame.h index 391e484..87b0b2a 100644 --- a/lib/lz4frame.h +++ b/lib/lz4frame.h @@ -284,7 +284,7 @@ LZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx, * @return is always the same for a srcSize and prefsPtr. * prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario. * tech details : - * @return includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes. + * @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes. * It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd(). * @return doesn't include frame header, as it was already generated by LZ4F_compressBegin(). */ diff --git a/lib/lz4hc.c b/lib/lz4hc.c index 5922ed7..687f87e 100644 --- a/lib/lz4hc.c +++ b/lib/lz4hc.c @@ -389,8 +389,8 @@ LZ4HC_InsertAndGetWiderMatch ( if (lookBackLength==0) { /* no back possible */ size_t const maxML = MIN(currentSegmentLength, srcPatternLength); if ((size_t)longest < maxML) { - assert(base + matchIndex < ip); - if (ip - (base+matchIndex) > LZ4_DISTANCE_MAX) break; + assert(base + matchIndex != ip); + if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break; assert(maxML < 2 GB); longest = (int)maxML; *matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */ @@ -886,8 +886,8 @@ int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); } * while actually aligning LZ4_streamHC_t on 4 bytes. */ static size_t LZ4_streamHC_t_alignment(void) { - struct { char c; LZ4_streamHC_t t; } t_a; - return sizeof(t_a) - sizeof(t_a.t); + typedef struct { char c; LZ4_streamHC_t t; } t_a; + return sizeof(t_a) - sizeof(LZ4_streamHC_t); } #endif @@ -1028,7 +1028,7 @@ int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize) { LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; - DEBUGLOG(4, "LZ4_loadDictHC(%p, %p, %d)", LZ4_streamHCPtr, dictionary, dictSize); + DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize); assert(LZ4_streamHCPtr != NULL); if (dictSize > 64 KB) { dictionary += (size_t)dictSize - 64 KB; @@ -1287,8 +1287,13 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, const dictCtx_directive dict, const HCfavor_e favorDecSpeed) { + int retval = 0; #define TRAILING_LITERALS 3 +#ifdef LZ4HC_HEAPMODE + LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)malloc(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS)); +#else LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */ +#endif const BYTE* ip = (const BYTE*) source; const BYTE* anchor = ip; @@ -1300,6 +1305,9 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, BYTE* oend = op + dstCapacity; /* init */ +#ifdef LZ4HC_HEAPMODE + if (opt == NULL) goto _return_label; +#endif DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity); *srcSizePtr = 0; if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ @@ -1505,7 +1513,10 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, size_t const totalSize = 1 + litLength + lastRunSize; if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit && (op + totalSize > oend)) { - if (limit == limitedOutput) return 0; /* Check output limit */ + if (limit == limitedOutput) { /* Check output limit */ + retval = 0; + goto _return_label; + } /* adapt lastRunSize to fill 'dst' */ lastRunSize = (size_t)(oend - op) - 1; litLength = (lastRunSize + 255 - RUN_MASK) / 255; @@ -1527,12 +1538,17 @@ static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, /* End */ *srcSizePtr = (int) (((const char*)ip) - source); - return (int) ((char*)op-dst); + retval = (int) ((char*)op-dst); + goto _return_label; _dest_overflow: if (limit == fillOutput) { op = opSaved; /* restore correct out pointer */ goto _last_literals; } - return 0; + _return_label: +#ifdef LZ4HC_HEAPMODE + free(opt); +#endif + return retval; } diff --git a/ossfuzz/Makefile b/ossfuzz/Makefile index 6875eb6..7e043a1 100644 --- a/ossfuzz/Makefile +++ b/ossfuzz/Makefile @@ -58,7 +58,7 @@ $(LZ4DIR)/liblz4.a: $(CC) -c $(LZ4_CFLAGS) $(LZ4_CPPFLAGS) $< -o $@ # Generic rule for generating fuzzers -%_fuzzer: %_fuzzer.o lz4_helpers.o $(LZ4DIR)/liblz4.a +%_fuzzer: %_fuzzer.o lz4_helpers.o fuzz_data_producer.o $(LZ4DIR)/liblz4.a # Compile the standalone code just in case. The OSS-Fuzz code might # override the LIB_FUZZING_ENGINE value to "-fsanitize=fuzzer" $(CC) -c $(LZ4_CFLAGS) $(LZ4_CPPFLAGS) standaloneengine.c -o standaloneengine.o diff --git a/ossfuzz/compress_frame_fuzzer.c b/ossfuzz/compress_frame_fuzzer.c index 75c609f..bb14fc2 100644 --- a/ossfuzz/compress_frame_fuzzer.c +++ b/ossfuzz/compress_frame_fuzzer.c @@ -13,13 +13,18 @@ #include "lz4.h" #include "lz4frame.h" #include "lz4_helpers.h" +#include "fuzz_data_producer.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); - LZ4F_preferences_t const prefs = FUZZ_randomPreferences(&seed); + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + LZ4F_preferences_t const prefs = FUZZ_dataProducer_preferences(producer); + size_t const dstCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); + size_t const compressBound = LZ4F_compressFrameBound(size, &prefs); - size_t const dstCapacity = FUZZ_rand32(&seed, 0, compressBound); + size_t const dstCapacity = FUZZ_getRange_from_uint32(dstCapacitySeed, 0, compressBound); + char* const dst = (char*)malloc(dstCapacity); char* const rt = (char*)malloc(size); @@ -37,6 +42,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/compress_fuzzer.c b/ossfuzz/compress_fuzzer.c index 7021624..edc8aad 100644 --- a/ossfuzz/compress_fuzzer.c +++ b/ossfuzz/compress_fuzzer.c @@ -10,12 +10,18 @@ #include <string.h> #include "fuzz_helpers.h" +#include "fuzz_data_producer.h" #include "lz4.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); - size_t const dstCapacity = FUZZ_rand32(&seed, 0, LZ4_compressBound(size)); + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + size_t const dstCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); + + size_t const compressBound = LZ4_compressBound(size); + size_t const dstCapacity = FUZZ_getRange_from_uint32(dstCapacitySeed, 0, compressBound); + char* const dst = (char*)malloc(dstCapacity); char* const rt = (char*)malloc(size); @@ -46,6 +52,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/compress_hc_fuzzer.c b/ossfuzz/compress_hc_fuzzer.c index 4841367..7d8e45a 100644 --- a/ossfuzz/compress_hc_fuzzer.c +++ b/ossfuzz/compress_hc_fuzzer.c @@ -10,16 +10,22 @@ #include <string.h> #include "fuzz_helpers.h" +#include "fuzz_data_producer.h" #include "lz4.h" #include "lz4hc.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); - size_t const dstCapacity = FUZZ_rand32(&seed, 0, LZ4_compressBound(size)); + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + size_t const dstCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size_t const levelSeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); + + size_t const dstCapacity = FUZZ_getRange_from_uint32(dstCapacitySeed, 0, size); + int const level = FUZZ_getRange_from_uint32(levelSeed, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); + char* const dst = (char*)malloc(dstCapacity); char* const rt = (char*)malloc(size); - int const level = FUZZ_rand32(&seed, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); FUZZ_ASSERT(dst); FUZZ_ASSERT(rt); @@ -52,6 +58,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/decompress_frame_fuzzer.c b/ossfuzz/decompress_frame_fuzzer.c index bda25b0..0fcbb16 100644 --- a/ossfuzz/decompress_frame_fuzzer.c +++ b/ossfuzz/decompress_frame_fuzzer.c @@ -9,6 +9,7 @@ #include <string.h> #include "fuzz_helpers.h" +#include "fuzz_data_producer.h" #include "lz4.h" #define LZ4F_STATIC_LINKING_ONLY #include "lz4frame.h" @@ -29,11 +30,17 @@ static void decompress(LZ4F_dctx* dctx, void* dst, size_t dstCapacity, int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + size_t const dstCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size_t const dictSizeSeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); - uint32_t seed = FUZZ_seed(&data, &size); - size_t const dstCapacity = FUZZ_rand32(&seed, 0, 4 * size); + size_t const dstCapacity = FUZZ_getRange_from_uint32( + dstCapacitySeed, 0, 4 * size); size_t const largeDictSize = 64 * 1024; - size_t const dictSize = FUZZ_rand32(&seed, 0, largeDictSize); + size_t const dictSize = FUZZ_getRange_from_uint32( + dictSizeSeed, 0, largeDictSize); + char* const dst = (char*)malloc(dstCapacity); char* const dict = (char*)malloc(dictSize); LZ4F_decompressOptions_t opts; @@ -62,6 +69,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) LZ4F_freeDecompressionContext(dctx); free(dst); free(dict); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/decompress_fuzzer.c b/ossfuzz/decompress_fuzzer.c index 0267c93..6f48e30 100644 --- a/ossfuzz/decompress_fuzzer.c +++ b/ossfuzz/decompress_fuzzer.c @@ -9,13 +9,16 @@ #include <string.h> #include "fuzz_helpers.h" +#include "fuzz_data_producer.h" #include "lz4.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + size_t const dstCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); - uint32_t seed = FUZZ_seed(&data, &size); - size_t const dstCapacity = FUZZ_rand32(&seed, 0, 4 * size); + size_t const dstCapacity = FUZZ_getRange_from_uint32(dstCapacitySeed, 0, 4 * size); size_t const smallDictSize = size + 1; size_t const largeDictSize = 64 * 1024 - 1; size_t const dictSize = MAX(smallDictSize, largeDictSize); @@ -53,6 +56,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) dstCapacity, dstCapacity); free(dst); free(dict); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/fuzz_data_producer.c b/ossfuzz/fuzz_data_producer.c new file mode 100644 index 0000000..cc06958 --- /dev/null +++ b/ossfuzz/fuzz_data_producer.c @@ -0,0 +1,77 @@ +#include "fuzz_data_producer.h" + +struct FUZZ_dataProducer_s{ + const uint8_t *data; + size_t size; +}; + +FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size) { + FUZZ_dataProducer_t *producer = malloc(sizeof(FUZZ_dataProducer_t)); + + FUZZ_ASSERT(producer != NULL); + + producer->data = data; + producer->size = size; + return producer; +} + +void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer) { free(producer); } + +uint32_t FUZZ_dataProducer_retrieve32(FUZZ_dataProducer_t *producer) { + const uint8_t* data = producer->data; + const size_t size = producer->size; + if (size == 0) { + return 0; + } else if (size < 4) { + producer->size -= 1; + return (uint32_t)data[size - 1]; + } else { + producer->size -= 4; + return *(data + size - 4); + } +} + +uint32_t FUZZ_getRange_from_uint32(uint32_t seed, uint32_t min, uint32_t max) +{ + uint32_t range = max - min; + if (range == 0xffffffff) { + return seed; + } + return min + seed % (range + 1); +} + +uint32_t FUZZ_dataProducer_range32(FUZZ_dataProducer_t* producer, + uint32_t min, uint32_t max) +{ + size_t const seed = FUZZ_dataProducer_retrieve32(producer); + return FUZZ_getRange_from_uint32(seed, min, max); +} + +LZ4F_frameInfo_t FUZZ_dataProducer_frameInfo(FUZZ_dataProducer_t* producer) +{ + LZ4F_frameInfo_t info = LZ4F_INIT_FRAMEINFO; + info.blockSizeID = FUZZ_dataProducer_range32(producer, LZ4F_max64KB - 1, LZ4F_max4MB); + if (info.blockSizeID < LZ4F_max64KB) { + info.blockSizeID = LZ4F_default; + } + info.blockMode = FUZZ_dataProducer_range32(producer, LZ4F_blockLinked, LZ4F_blockIndependent); + info.contentChecksumFlag = FUZZ_dataProducer_range32(producer, LZ4F_noContentChecksum, + LZ4F_contentChecksumEnabled); + info.blockChecksumFlag = FUZZ_dataProducer_range32(producer, LZ4F_noBlockChecksum, + LZ4F_blockChecksumEnabled); + return info; +} + +LZ4F_preferences_t FUZZ_dataProducer_preferences(FUZZ_dataProducer_t* producer) +{ + LZ4F_preferences_t prefs = LZ4F_INIT_PREFERENCES; + prefs.frameInfo = FUZZ_dataProducer_frameInfo(producer); + prefs.compressionLevel = FUZZ_dataProducer_range32(producer, 0, LZ4HC_CLEVEL_MAX + 3) - 3; + prefs.autoFlush = FUZZ_dataProducer_range32(producer, 0, 1); + prefs.favorDecSpeed = FUZZ_dataProducer_range32(producer, 0, 1); + return prefs; +} + +size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){ + return producer->size; +} diff --git a/ossfuzz/fuzz_data_producer.h b/ossfuzz/fuzz_data_producer.h new file mode 100644 index 0000000..b96dcba --- /dev/null +++ b/ossfuzz/fuzz_data_producer.h @@ -0,0 +1,36 @@ +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include "fuzz_helpers.h" +#include "lz4frame.h" +#include "lz4hc.h" + +/* Struct used for maintaining the state of the data */ +typedef struct FUZZ_dataProducer_s FUZZ_dataProducer_t; + +/* Returns a data producer state struct. Use for producer initialization. */ +FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size); + +/* Frees the data producer */ +void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer); + +/* Returns 32 bits from the end of data */ +uint32_t FUZZ_dataProducer_retrieve32(FUZZ_dataProducer_t *producer); + +/* Returns value between [min, max] */ +uint32_t FUZZ_getRange_from_uint32(uint32_t seed, uint32_t min, uint32_t max); + +/* Combination of above two functions for non adaptive use cases. ie where size is not involved */ +uint32_t FUZZ_dataProducer_range32(FUZZ_dataProducer_t *producer, uint32_t min, + uint32_t max); + +/* Returns lz4 preferences */ +LZ4F_preferences_t FUZZ_dataProducer_preferences(FUZZ_dataProducer_t* producer); + +/* Returns lz4 frame info */ +LZ4F_frameInfo_t FUZZ_dataProducer_frameInfo(FUZZ_dataProducer_t* producer); + +/* Returns the size of the remaining bytes of data in the producer */ +size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer); diff --git a/ossfuzz/round_trip_frame_fuzzer.c b/ossfuzz/round_trip_frame_fuzzer.c index 1eea90c..149542d 100644 --- a/ossfuzz/round_trip_frame_fuzzer.c +++ b/ossfuzz/round_trip_frame_fuzzer.c @@ -12,14 +12,17 @@ #include "lz4.h" #include "lz4frame.h" #include "lz4_helpers.h" +#include "fuzz_data_producer.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); - LZ4F_preferences_t const prefs = FUZZ_randomPreferences(&seed); - size_t const dstCapacity = LZ4F_compressFrameBound(size, &prefs); + FUZZ_dataProducer_t* producer = FUZZ_dataProducer_create(data, size); + LZ4F_preferences_t const prefs = FUZZ_dataProducer_preferences(producer); + size = FUZZ_dataProducer_remainingBytes(producer); + + size_t const dstCapacity = LZ4F_compressFrameBound(LZ4_compressBound(size), &prefs); char* const dst = (char*)malloc(dstCapacity); - char* const rt = (char*)malloc(size); + char* const rt = (char*)malloc(FUZZ_dataProducer_remainingBytes(producer)); FUZZ_ASSERT(dst); FUZZ_ASSERT(rt); @@ -34,6 +37,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/round_trip_fuzzer.c b/ossfuzz/round_trip_fuzzer.c index 3a66e80..6307058 100644 --- a/ossfuzz/round_trip_fuzzer.c +++ b/ossfuzz/round_trip_fuzzer.c @@ -10,11 +10,17 @@ #include "fuzz_helpers.h" #include "lz4.h" +#include "fuzz_data_producer.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + size_t const partialCapacitySeed = FUZZ_dataProducer_retrieve32(producer); + size = FUZZ_dataProducer_remainingBytes(producer); + + size_t const partialCapacity = FUZZ_getRange_from_uint32(partialCapacitySeed, 0, size); size_t const dstCapacity = LZ4_compressBound(size); + char* const dst = (char*)malloc(dstCapacity); char* const rt = (char*)malloc(size); @@ -32,7 +38,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) /* Partial decompression must succeed. */ { - size_t const partialCapacity = FUZZ_rand32(&seed, 0, size); char* const partial = (char*)malloc(partialCapacity); FUZZ_ASSERT(partial); int const partialSize = LZ4_decompress_safe_partial( @@ -43,8 +48,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(partial); } + free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/ossfuzz/round_trip_hc_fuzzer.c b/ossfuzz/round_trip_hc_fuzzer.c index 325cdf0..7d03ee2 100644 --- a/ossfuzz/round_trip_hc_fuzzer.c +++ b/ossfuzz/round_trip_hc_fuzzer.c @@ -9,16 +9,20 @@ #include <string.h> #include "fuzz_helpers.h" +#include "fuzz_data_producer.h" #include "lz4.h" #include "lz4hc.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - uint32_t seed = FUZZ_seed(&data, &size); + FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(data, size); + int const level = FUZZ_dataProducer_range32(producer, + LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); + size = FUZZ_dataProducer_remainingBytes(producer); + size_t const dstCapacity = LZ4_compressBound(size); char* const dst = (char*)malloc(dstCapacity); char* const rt = (char*)malloc(size); - int const level = FUZZ_rand32(&seed, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); FUZZ_ASSERT(dst); FUZZ_ASSERT(rt); @@ -34,6 +38,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) free(dst); free(rt); + FUZZ_dataProducer_free(producer); return 0; } diff --git a/programs/bench.c b/programs/bench.c index 5934935..3357d14 100644 --- a/programs/bench.c +++ b/programs/bench.c @@ -45,17 +45,176 @@ #include "datagen.h" /* RDG_genBuffer */ #include "xxhash.h" +#include "bench.h" - +#define LZ4_STATIC_LINKING_ONLY #include "lz4.h" -#define COMPRESSOR0 LZ4_compress_local -static int LZ4_compress_local(const char* src, char* dst, int srcSize, int dstSize, int clevel) { - int const acceleration = (clevel < 0) ? -clevel + 1 : 1; - return LZ4_compress_fast(src, dst, srcSize, dstSize, acceleration); -} +#define LZ4_HC_STATIC_LINKING_ONLY #include "lz4hc.h" -#define COMPRESSOR1 LZ4_compress_HC -#define DEFAULTCOMPRESSOR COMPRESSOR0 + + +/* ************************************* +* Compression parameters and functions +***************************************/ + +struct compressionParameters +{ + int cLevel; + const char* dictBuf; + int dictSize; + + LZ4_stream_t* LZ4_stream; + LZ4_stream_t* LZ4_dictStream; + LZ4_streamHC_t* LZ4_streamHC; + LZ4_streamHC_t* LZ4_dictStreamHC; + + void (*initFunction)( + struct compressionParameters* pThis); + void (*resetFunction)( + const struct compressionParameters* pThis); + int (*blockFunction)( + const struct compressionParameters* pThis, + const char* src, char* dst, int srcSize, int dstSize); + void (*cleanupFunction)( + const struct compressionParameters* pThis); +}; + +static void LZ4_compressInitNoStream( + struct compressionParameters* pThis) +{ + pThis->LZ4_stream = NULL; + pThis->LZ4_dictStream = NULL; + pThis->LZ4_streamHC = NULL; + pThis->LZ4_dictStreamHC = NULL; +} + +static void LZ4_compressInitStream( + struct compressionParameters* pThis) +{ + pThis->LZ4_stream = LZ4_createStream(); + pThis->LZ4_dictStream = LZ4_createStream(); + pThis->LZ4_streamHC = NULL; + pThis->LZ4_dictStreamHC = NULL; + LZ4_loadDict(pThis->LZ4_dictStream, pThis->dictBuf, pThis->dictSize); +} + +static void LZ4_compressInitStreamHC( + struct compressionParameters* pThis) +{ + pThis->LZ4_stream = NULL; + pThis->LZ4_dictStream = NULL; + pThis->LZ4_streamHC = LZ4_createStreamHC(); + pThis->LZ4_dictStreamHC = LZ4_createStreamHC(); + LZ4_loadDictHC(pThis->LZ4_dictStreamHC, pThis->dictBuf, pThis->dictSize); +} + +static void LZ4_compressResetNoStream( + const struct compressionParameters* pThis) +{ + (void)pThis; +} + +static void LZ4_compressResetStream( + const struct compressionParameters* pThis) +{ + LZ4_resetStream_fast(pThis->LZ4_stream); + LZ4_attach_dictionary(pThis->LZ4_stream, pThis->LZ4_dictStream); +} + +static void LZ4_compressResetStreamHC( + const struct compressionParameters* pThis) +{ + LZ4_resetStreamHC_fast(pThis->LZ4_streamHC, pThis->cLevel); + LZ4_attach_HC_dictionary(pThis->LZ4_streamHC, pThis->LZ4_dictStreamHC); +} + +static int LZ4_compressBlockNoStream( + const struct compressionParameters* pThis, + const char* src, char* dst, + int srcSize, int dstSize) +{ + int const acceleration = (pThis->cLevel < 0) ? -pThis->cLevel + 1 : 1; + return LZ4_compress_fast(src, dst, srcSize, dstSize, acceleration); +} + +static int LZ4_compressBlockNoStreamHC( + const struct compressionParameters* pThis, + const char* src, char* dst, + int srcSize, int dstSize) +{ + return LZ4_compress_HC(src, dst, srcSize, dstSize, pThis->cLevel); +} + +static int LZ4_compressBlockStream( + const struct compressionParameters* pThis, + const char* src, char* dst, + int srcSize, int dstSize) +{ + int const acceleration = (pThis->cLevel < 0) ? -pThis->cLevel + 1 : 1; + return LZ4_compress_fast_continue(pThis->LZ4_stream, src, dst, srcSize, dstSize, acceleration); +} + +static int LZ4_compressBlockStreamHC( + const struct compressionParameters* pThis, + const char* src, char* dst, + int srcSize, int dstSize) +{ + return LZ4_compress_HC_continue(pThis->LZ4_streamHC, src, dst, srcSize, dstSize); +} + +static void LZ4_compressCleanupNoStream( + const struct compressionParameters* pThis) +{ + (void)pThis; +} + +static void LZ4_compressCleanupStream( + const struct compressionParameters* pThis) +{ + LZ4_freeStream(pThis->LZ4_stream); + LZ4_freeStream(pThis->LZ4_dictStream); +} + +static void LZ4_compressCleanupStreamHC( + const struct compressionParameters* pThis) +{ + LZ4_freeStreamHC(pThis->LZ4_streamHC); + LZ4_freeStreamHC(pThis->LZ4_dictStreamHC); +} + +static void LZ4_buildCompressionParameters( + struct compressionParameters* pParams, + int cLevel, const char* dictBuf, int dictSize) +{ + pParams->cLevel = cLevel; + pParams->dictBuf = dictBuf; + pParams->dictSize = dictSize; + + if (dictSize) { + if (cLevel < LZ4HC_CLEVEL_MIN) { + pParams->initFunction = LZ4_compressInitStream; + pParams->resetFunction = LZ4_compressResetStream; + pParams->blockFunction = LZ4_compressBlockStream; + pParams->cleanupFunction = LZ4_compressCleanupStream; + } else { + pParams->initFunction = LZ4_compressInitStreamHC; + pParams->resetFunction = LZ4_compressResetStreamHC; + pParams->blockFunction = LZ4_compressBlockStreamHC; + pParams->cleanupFunction = LZ4_compressCleanupStreamHC; + } + } else { + pParams->initFunction = LZ4_compressInitNoStream; + pParams->resetFunction = LZ4_compressResetNoStream; + pParams->cleanupFunction = LZ4_compressCleanupNoStream; + + if (cLevel < LZ4HC_CLEVEL_MIN) { + pParams->blockFunction = LZ4_compressBlockNoStream; + } else { + pParams->blockFunction = LZ4_compressBlockNoStreamHC; + } + } +} + #define LZ4_isError(errcode) (errcode==0) @@ -79,6 +238,8 @@ static int LZ4_compress_local(const char* src, char* dst, int srcSize, int dstSi #define MB *(1 <<20) #define GB *(1U<<30) +#define LZ4_MAX_DICT_SIZE (64 KB) + static const size_t maxMemory = (sizeof(size_t)==4) ? (2 GB - 64 MB) : (size_t)(1ULL << ((sizeof(size_t)*8)-31)); static U32 g_compressibilityDefault = 50; @@ -152,17 +313,13 @@ typedef struct { size_t resSize; } blockParam_t; -struct compressionParameters -{ - int (*compressionFunction)(const char* src, char* dst, int srcSize, int dstSize, int cLevel); -}; - #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) static int BMK_benchMem(const void* srcBuffer, size_t srcSize, const char* displayName, int cLevel, - const size_t* fileSizes, U32 nbFiles) + const size_t* fileSizes, U32 nbFiles, + const char* dictBuf, int dictSize) { size_t const blockSize = (g_blockSize>=32 ? g_blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ; U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles; @@ -172,27 +329,16 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, void* const resultBuffer = malloc(srcSize); U32 nbBlocks; struct compressionParameters compP; - int cfunctionId; /* checks */ if (!compressedBuffer || !resultBuffer || !blockTable) EXM_THROW(31, "allocation error : not enough memory"); - /* init */ if (strlen(displayName)>17) displayName += strlen(displayName)-17; /* can only display 17 characters */ - /* Init */ - if (cLevel < LZ4HC_CLEVEL_MIN) cfunctionId = 0; else cfunctionId = 1; - switch (cfunctionId) - { -#ifdef COMPRESSOR0 - case 0 : compP.compressionFunction = COMPRESSOR0; break; -#endif -#ifdef COMPRESSOR1 - case 1 : compP.compressionFunction = COMPRESSOR1; break; -#endif - default : compP.compressionFunction = DEFAULTCOMPRESSOR; - } + /* init */ + LZ4_buildCompressionParameters(&compP, cLevel, dictBuf, dictSize); + compP.initFunction(&compP); /* Init blockTable data */ { const char* srcPtr = (const char*)srcBuffer; @@ -256,8 +402,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, U32 nbLoops; for (nbLoops=0; nbLoops < nbCompressionLoops; nbLoops++) { U32 blockNb; + compP.resetFunction(&compP); for (blockNb=0; blockNb<nbBlocks; blockNb++) { - size_t const rSize = (size_t)compP.compressionFunction(blockTable[blockNb].srcPtr, blockTable[blockNb].cPtr, (int)blockTable[blockNb].srcSize, (int)blockTable[blockNb].cRoom, cLevel); + size_t const rSize = (size_t)compP.blockFunction( + &compP, + blockTable[blockNb].srcPtr, blockTable[blockNb].cPtr, + (int)blockTable[blockNb].srcSize, (int)blockTable[blockNb].cRoom); if (LZ4_isError(rSize)) EXM_THROW(1, "LZ4 compression failed"); blockTable[blockNb].cSize = rSize; } } @@ -298,9 +448,12 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, for (nbLoops=0; nbLoops < nbDecodeLoops; nbLoops++) { U32 blockNb; for (blockNb=0; blockNb<nbBlocks; blockNb++) { - int const regenSize = LZ4_decompress_safe(blockTable[blockNb].cPtr, blockTable[blockNb].resPtr, (int)blockTable[blockNb].cSize, (int)blockTable[blockNb].srcSize); + int const regenSize = LZ4_decompress_safe_usingDict( + blockTable[blockNb].cPtr, blockTable[blockNb].resPtr, + (int)blockTable[blockNb].cSize, (int)blockTable[blockNb].srcSize, + dictBuf, dictSize); if (regenSize < 0) { - DISPLAY("LZ4_decompress_safe() failed on block %u \n", blockNb); + DISPLAY("LZ4_decompress_safe_usingDict() failed on block %u \n", blockNb); break; } blockTable[blockNb].resSize = (size_t)regenSize; @@ -364,6 +517,7 @@ static int BMK_benchMem(const void* srcBuffer, size_t srcSize, } /* Bench */ /* clean up */ + compP.cleanupFunction(&compP); free(blockTable); free(compressedBuffer); free(resultBuffer); @@ -397,7 +551,8 @@ static size_t BMK_findMaxMem(U64 requiredMem) static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, const char* displayName, int cLevel, int cLevelLast, - const size_t* fileSizes, unsigned nbFiles) + const size_t* fileSizes, unsigned nbFiles, + const char* dictBuf, int dictSize) { int l; @@ -415,7 +570,8 @@ static void BMK_benchCLevel(void* srcBuffer, size_t benchedSize, for (l=cLevel; l <= cLevelLast; l++) { BMK_benchMem(srcBuffer, benchedSize, displayName, l, - fileSizes, nbFiles); + fileSizes, nbFiles, + dictBuf, dictSize); } } @@ -456,7 +612,8 @@ static void BMK_loadFiles(void* buffer, size_t bufferSize, } static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles, - int cLevel, int cLevelLast) + int cLevel, int cLevelLast, + const char* dictBuf, int dictSize) { void* srcBuffer; size_t benchedSize; @@ -488,7 +645,8 @@ static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles, { const char* displayName = (nbFiles > 1) ? mfName : fileNamesTable[0]; BMK_benchCLevel(srcBuffer, benchedSize, displayName, cLevel, cLevelLast, - fileSizes, nbFiles); + fileSizes, nbFiles, + dictBuf, dictSize); } /* clean up */ @@ -497,7 +655,8 @@ static void BMK_benchFileTable(const char** fileNamesTable, unsigned nbFiles, } -static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility) +static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility, + const char* dictBuf, int dictSize) { char name[20] = {0}; size_t benchedSize = 10000000; @@ -511,7 +670,7 @@ static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility /* Bench */ snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100)); - BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1); + BMK_benchCLevel(srcBuffer, benchedSize, name, cLevel, cLevelLast, &benchedSize, 1, dictBuf, dictSize); /* clean up */ free(srcBuffer); @@ -519,7 +678,8 @@ static void BMK_syntheticTest(int cLevel, int cLevelLast, double compressibility int BMK_benchFilesSeparately(const char** fileNamesTable, unsigned nbFiles, - int cLevel, int cLevelLast) + int cLevel, int cLevelLast, + const char* dictBuf, int dictSize) { unsigned fileNb; if (cLevel > LZ4HC_CLEVEL_MAX) cLevel = LZ4HC_CLEVEL_MAX; @@ -528,29 +688,59 @@ int BMK_benchFilesSeparately(const char** fileNamesTable, unsigned nbFiles, if (cLevelLast > cLevel) DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast); for (fileNb=0; fileNb<nbFiles; fileNb++) - BMK_benchFileTable(fileNamesTable+fileNb, 1, cLevel, cLevelLast); + BMK_benchFileTable(fileNamesTable+fileNb, 1, cLevel, cLevelLast, dictBuf, dictSize); return 0; } int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, - int cLevel, int cLevelLast) + int cLevel, int cLevelLast, + const char* dictFileName) { double const compressibility = (double)g_compressibilityDefault / 100; + char* dictBuf = NULL; + int dictSize = 0; if (cLevel > LZ4HC_CLEVEL_MAX) cLevel = LZ4HC_CLEVEL_MAX; if (cLevelLast > LZ4HC_CLEVEL_MAX) cLevelLast = LZ4HC_CLEVEL_MAX; if (cLevelLast < cLevel) cLevelLast = cLevel; if (cLevelLast > cLevel) DISPLAYLEVEL(2, "Benchmarking levels from %d to %d\n", cLevel, cLevelLast); + if (dictFileName) { + FILE* dictFile = NULL; + U64 dictFileSize = UTIL_getFileSize(dictFileName); + if (!dictFileSize) EXM_THROW(25, "Dictionary error : could not stat dictionary file"); + + dictFile = fopen(dictFileName, "rb"); + if (!dictFile) EXM_THROW(25, "Dictionary error : could not open dictionary file"); + + if (dictFileSize > LZ4_MAX_DICT_SIZE) { + dictSize = LZ4_MAX_DICT_SIZE; + if (UTIL_fseek(dictFile, dictFileSize - dictSize, SEEK_SET)) + EXM_THROW(25, "Dictionary error : could not seek dictionary file"); + } else { + dictSize = (int)dictFileSize; + } + + dictBuf = (char *)malloc(dictSize); + if (!dictBuf) EXM_THROW(25, "Allocation error : not enough memory"); + + if (fread(dictBuf, 1, dictSize, dictFile) != (size_t)dictSize) + EXM_THROW(25, "Dictionary error : could not read dictionary file"); + + fclose(dictFile); + } + if (nbFiles == 0) - BMK_syntheticTest(cLevel, cLevelLast, compressibility); + BMK_syntheticTest(cLevel, cLevelLast, compressibility, dictBuf, dictSize); else { if (g_benchSeparately) - BMK_benchFilesSeparately(fileNamesTable, nbFiles, cLevel, cLevelLast); + BMK_benchFilesSeparately(fileNamesTable, nbFiles, cLevel, cLevelLast, dictBuf, dictSize); else - BMK_benchFileTable(fileNamesTable, nbFiles, cLevel, cLevelLast); + BMK_benchFileTable(fileNamesTable, nbFiles, cLevel, cLevelLast, dictBuf, dictSize); } + + free(dictBuf); return 0; } diff --git a/programs/bench.h b/programs/bench.h index bb67bee..22ebf60 100644 --- a/programs/bench.h +++ b/programs/bench.h @@ -26,7 +26,8 @@ #include <stddef.h> int BMK_benchFiles(const char** fileNamesTable, unsigned nbFiles, - int cLevel, int cLevelLast); + int cLevel, int cLevelLast, + const char* dictFileName); /* Set Parameters */ void BMK_setNbSeconds(unsigned nbLoops); diff --git a/programs/lz4cli.c b/programs/lz4cli.c index 5da7654..67dcaa1 100644 --- a/programs/lz4cli.c +++ b/programs/lz4cli.c @@ -94,7 +94,10 @@ static unsigned displayLevel = 2; /* 0 : no display ; 1: errors only ; 2 : dow #define DEFAULT_COMPRESSOR LZ4IO_compressFilename #define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename int LZ4IO_compressFilename_Legacy(LZ4IO_prefs_t* const prefs, const char* input_filename, const char* output_filename, int compressionlevel); /* hidden function */ - +int LZ4IO_compressMultipleFilenames_Legacy(LZ4IO_prefs_t* const prefs, + const char** inFileNamesTable, int ifntSize, + const char* suffix, + int compressionLevel); /*-*************************** * Functions @@ -625,10 +628,18 @@ int main(int argc, const char** argv) #endif } + if (dictionary_filename) { + if (!strcmp(dictionary_filename, stdinmark) && IS_CONSOLE(stdin)) { + DISPLAYLEVEL(1, "refusing to read from a console\n"); + exit(1); + } + LZ4IO_setDictionaryFilename(prefs, dictionary_filename); + } + /* benchmark and test modes */ if (mode == om_bench) { BMK_setNotificationLevel(displayLevel); - operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast); + operationResult = BMK_benchFiles(inFileNames, ifnIdx, cLevel, cLevelLast, dictionary_filename); goto _cleanup; } @@ -638,14 +649,6 @@ int main(int argc, const char** argv) mode = om_decompress; /* defer to decompress */ } - if (dictionary_filename) { - if (!strcmp(dictionary_filename, stdinmark) && IS_CONSOLE(stdin)) { - DISPLAYLEVEL(1, "refusing to read from a console\n"); - exit(1); - } - LZ4IO_setDictionaryFilename(prefs, dictionary_filename); - } - /* compress or decompress */ if (!input_filename) input_filename = stdinmark; /* Check if input is defined as console; trigger an error in this case */ @@ -658,7 +661,11 @@ int main(int argc, const char** argv) if (!output_filename) output_filename = stdoutmark; } else{ +#ifdef UTIL_HAS_CREATEFILELIST if (!recursive && !UTIL_isRegFile(input_filename)) { +#else + if (!UTIL_isRegFile(input_filename)) { +#endif DISPLAYLEVEL(1, "%s: is not a regular file \n", input_filename); exit(1); } @@ -666,7 +673,7 @@ int main(int argc, const char** argv) /* No output filename ==> try to select one automatically (when possible) */ while ((!output_filename) && (multiple_inputs==0)) { - if (!IS_CONSOLE(stdout)) { + if (!IS_CONSOLE(stdout) && mode != om_list) { /* Default to stdout whenever stdout is not the console. * Note : this policy may change in the future, therefore don't rely on it ! * To ensure `stdout` is explicitly selected, use `-c` command flag. @@ -750,7 +757,11 @@ int main(int argc, const char** argv) } else { /* compression is default action */ if (legacy_format) { DISPLAYLEVEL(3, "! Generating LZ4 Legacy format (deprecated) ! \n"); - LZ4IO_compressFilename_Legacy(prefs, input_filename, output_filename, cLevel); + if(multiple_inputs){ + LZ4IO_compressMultipleFilenames_Legacy(prefs, inFileNames, (int)ifnIdx, !strcmp(output_filename,stdoutmark) ? stdoutmark : LZ4_EXTENSION, cLevel); + } else { + LZ4IO_compressFilename_Legacy(prefs, input_filename, output_filename, cLevel); + } } else { if (multiple_inputs) { assert(ifnIdx <= INT_MAX); diff --git a/programs/lz4io.c b/programs/lz4io.c index d818535..7926b20 100644 --- a/programs/lz4io.c +++ b/programs/lz4io.c @@ -90,6 +90,7 @@ * Macros **************************************/ #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) +#define DISPLAYOUT(...) fprintf(stdout, __VA_ARGS__) #define DISPLAYLEVEL(l, ...) if (g_displayLevel>=l) { DISPLAY(__VA_ARGS__); } static int g_displayLevel = 0; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */ @@ -469,11 +470,59 @@ int LZ4IO_compressFilename_Legacy(LZ4IO_prefs_t* const prefs, const char* input_ free(in_buff); free(out_buff); fclose(finput); - fclose(foutput); + if (strcmp(output_filename,stdoutmark)) fclose(foutput); /* do not close stdout */ return 0; } +#define FNSPACE 30 +/* LZ4IO_compressMultipleFilenames_Legacy : + * This function is intentionally "hidden" (not published in .h) + * It generates multiple compressed streams using the old 'legacy' format */ +int LZ4IO_compressMultipleFilenames_Legacy(LZ4IO_prefs_t* const prefs, + const char** inFileNamesTable, int ifntSize, + const char* suffix, + int compressionLevel) +{ + int i; + int missed_files = 0; + char* dstFileName = (char*)malloc(FNSPACE); + size_t ofnSize = FNSPACE; + const size_t suffixSize = strlen(suffix); + + if (dstFileName == NULL) return ifntSize; /* not enough memory */ + + /* loop on each file */ + for (i=0; i<ifntSize; i++) { + size_t const ifnSize = strlen(inFileNamesTable[i]); + if (!strcmp(suffix, stdoutmark)) { + missed_files += LZ4IO_compressFilename_Legacy(prefs, + inFileNamesTable[i], stdoutmark, + compressionLevel); + continue; + } + + if (ofnSize <= ifnSize+suffixSize+1) { + free(dstFileName); + ofnSize = ifnSize + 20; + dstFileName = (char*)malloc(ofnSize); + if (dstFileName==NULL) { + return ifntSize; + } } + strcpy(dstFileName, inFileNamesTable[i]); + strcat(dstFileName, suffix); + + missed_files += LZ4IO_compressFilename_Legacy(prefs, + inFileNamesTable[i], dstFileName, + compressionLevel); + } + + /* Close & Free */ + free(dstFileName); + + return missed_files; +} + /********************************************* * Compression using Frame format @@ -748,7 +797,6 @@ int LZ4IO_compressFilename(LZ4IO_prefs_t* const prefs, const char* srcFileName, } -#define FNSPACE 30 int LZ4IO_compressMultipleFilenames(LZ4IO_prefs_t* const prefs, const char** inFileNamesTable, int ifntSize, const char* suffix, @@ -1561,7 +1609,7 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx) int result = 0; size_t idx = 0; if (g_displayLevel < 3) { - DISPLAY("%10s %14s %5s %11s %13s %9s %s\n", + DISPLAYOUT("%10s %14s %5s %11s %13s %9s %s\n", "Frames", "Type", "Block", "Compressed", "Uncompressed", "Ratio", "Filename"); } for (; idx < ifnIdx; idx++) { @@ -1586,7 +1634,7 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx) if (g_displayLevel < 3) { /* Display Summary */ { char buffers[3][10]; - DISPLAY("%10llu %14s %5s %11s %13s ", + DISPLAYOUT("%10llu %14s %5s %11s %13s ", cfinfo.frameCount, cfinfo.eqFrameTypes ? LZ4IO_frameTypeNames[cfinfo.frameSummary.frameType] : "-" , cfinfo.eqBlockTypes ? LZ4IO_blockTypeID(cfinfo.frameSummary.lz4FrameInfo.blockSizeID, @@ -1595,9 +1643,9 @@ int LZ4IO_displayCompressedFilesInfo(const char** inFileNames, size_t ifnIdx) cfinfo.allContentSize ? LZ4IO_toHuman((long double)cfinfo.frameSummary.lz4FrameInfo.contentSize, buffers[2]) : "-"); if (cfinfo.allContentSize) { double const ratio = (double)cfinfo.fileSize / cfinfo.frameSummary.lz4FrameInfo.contentSize * 100; - DISPLAY("%9.2f%% %s \n", ratio, cfinfo.fileName); + DISPLAYOUT("%9.2f%% %s \n", ratio, cfinfo.fileName); } else { - DISPLAY("%9s %s\n", + DISPLAYOUT("%9s %s\n", "-", cfinfo.fileName); } diff --git a/programs/platform.h b/programs/platform.h index c0b3840..bdbcb3b 100644 --- a/programs/platform.h +++ b/programs/platform.h @@ -81,12 +81,13 @@ extern "C" { #if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) /* UNIX-like OS */ \ || defined(__midipix__) || defined(__VMS)) # if (defined(__APPLE__) && defined(__MACH__)) || defined(__SVR4) || defined(_AIX) || defined(__hpux) /* POSIX.1–2001 (SUSv3) conformant */ \ - || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__MidnightBSD__) /* BSD distros */ + || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__MidnightBSD__) /* BSD distros */ \ + || defined(__HAIKU__) # define PLATFORM_POSIX_VERSION 200112L # else # if defined(__linux__) || defined(__linux) # ifndef _POSIX_C_SOURCE -# define _POSIX_C_SOURCE 200112L /* use feature test macro */ +# define _POSIX_C_SOURCE 200809L /* use feature test macro */ # endif # endif # include <unistd.h> /* declares _POSIX_VERSION */ diff --git a/programs/util.h b/programs/util.h index 1dd515c..8e361ca 100644 --- a/programs/util.h +++ b/programs/util.h @@ -37,12 +37,17 @@ extern "C" { #include <assert.h> #include <sys/types.h> /* stat, utime */ #include <sys/stat.h> /* stat */ -#if defined(_MSC_VER) +#if defined(_WIN32) # include <sys/utime.h> /* utime */ # include <io.h> /* _chmod */ #else # include <unistd.h> /* chown, stat */ +# if PLATFORM_POSIX_VERSION < 200809L # include <utime.h> /* utime */ +# else +# include <fcntl.h> /* AT_FDCWD */ +# include <sys/stat.h> /* for utimensat */ +# endif #endif #include <time.h> /* time */ #include <limits.h> /* INT_MAX */ @@ -287,14 +292,23 @@ UTIL_STATIC int UTIL_isRegFile(const char* infilename); UTIL_STATIC int UTIL_setFileStat(const char *filename, stat_t *statbuf) { int res = 0; - struct utimbuf timebuf; if (!UTIL_isRegFile(filename)) return -1; - timebuf.actime = time(NULL); - timebuf.modtime = statbuf->st_mtime; - res += utime(filename, &timebuf); /* set access and modification times */ + { +#if defined(_WIN32) || (PLATFORM_POSIX_VERSION < 200809L) + struct utimbuf timebuf; + timebuf.actime = time(NULL); + timebuf.modtime = statbuf->st_mtime; + res += utime(filename, &timebuf); /* set access and modification times */ +#else + struct timespec timebuf[2] = {}; + timebuf[0].tv_nsec = UTIME_NOW; + timebuf[1].tv_sec = statbuf->st_mtime; + res += utimensat(AT_FDCWD, filename, timebuf, 0); /* set access and modification times */ +#endif + } #if !defined(_WIN32) res += chown(filename, statbuf->st_uid, statbuf->st_gid); /* Copy ownership */ diff --git a/tests/Makefile b/tests/Makefile index 422baba..1f8321c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -259,6 +259,44 @@ test-lz4-multiple: lz4 datagen ! $(LZ4) -f -m tmp-tlm-concat1 notHere tmp-tlm-concat2 # must fail : notHere not present @$(RM) tmp-tlm* +test-lz4-multiple-legacy: lz4 datagen + @echo "\n ---- test multiple files (Legacy format) ----" + @./datagen -s1 > tmp-tlm1 2> $(VOID) + @./datagen -s2 -g100K > tmp-tlm2 2> $(VOID) + @./datagen -s3 -g200K > tmp-tlm3 2> $(VOID) + # compress multiple files using legacy format: one .lz4 per source file + $(LZ4) -f -l -m tmp-tlm* + test -f tmp-tlm1.lz4 + test -f tmp-tlm2.lz4 + test -f tmp-tlm3.lz4 + # decompress multiple files compressed using legacy format: one output file per .lz4 + mv tmp-tlm1 tmp-tlm1-orig + mv tmp-tlm2 tmp-tlm2-orig + mv tmp-tlm3 tmp-tlm3-orig + $(LZ4) -d -f -m tmp-tlm*.lz4 + $(LZ4) -l -d -f -m tmp-tlm*.lz4 # -l mustn't impact -d option + $(CMP) tmp-tlm1 tmp-tlm1-orig # must be identical + $(CMP) tmp-tlm2 tmp-tlm2-orig + $(CMP) tmp-tlm3 tmp-tlm3-orig + # compress multiple files into stdout using legacy format + cat tmp-tlm1.lz4 tmp-tlm2.lz4 tmp-tlm3.lz4 > tmp-tlm-concat1 + $(RM) *.lz4 + $(LZ4) -l -m tmp-tlm1 tmp-tlm2 tmp-tlm3 -c > tmp-tlm-concat2 + test ! -f tmp-tlm1.lz4 # must not create .lz4 artefact + $(CMP) tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent + # # # decompress multiple files into stdout using legacy format + $(RM) tmp-tlm-concat1 tmp-tlm-concat2 + $(LZ4) -l -f -m tmp-tlm1 tmp-tlm2 tmp-tlm3 # generate .lz4 to decompress + cat tmp-tlm1 tmp-tlm2 tmp-tlm3 > tmp-tlm-concat1 # create concatenated reference + $(RM) tmp-tlm1 tmp-tlm2 tmp-tlm3 + $(LZ4) -d -m tmp-tlm1.lz4 tmp-tlm2.lz4 tmp-tlm3.lz4 -c > tmp-tlm-concat2 + $(LZ4) -d -l -m tmp-tlm1.lz4 tmp-tlm2.lz4 tmp-tlm3.lz4 -c > tmp-tlm-concat2 # -l mustn't impact option -d + test ! -f tmp-tlm1 # must not create file artefact + $(CMP) tmp-tlm-concat1 tmp-tlm-concat2 # must be equivalent + # # # compress multiple files, one of which is absent (must fail) + ! $(LZ4) -f -l -m tmp-tlm-concat1 notHere-legacy tmp-tlm-concat2 # must fail : notHere-legacy not present + @$(RM) tmp-tlm* + test-lz4-basic: lz4 datagen unlz4 lz4cat @echo "\n ---- test lz4 basic compression/decompression ----" ./datagen -g0 | $(LZ4) -v | $(LZ4) -t @@ -393,7 +431,7 @@ test-lz4-opt-parser: lz4 datagen ./datagen -g16M -P90 | $(LZ4) -11B5 | $(LZ4) -t ./datagen -g32M -P10 | $(LZ4) -11B5D | $(LZ4) -t -test-lz4-essentials : lz4 datagen test-lz4-basic test-lz4-multiple \ +test-lz4-essentials : lz4 datagen test-lz4-basic test-lz4-multiple test-lz4-multiple-legacy \ test-lz4-frame-concatenation test-lz4-testmode \ test-lz4-contentSize test-lz4-dict @$(RM) tmp* diff --git a/tests/frametest.c b/tests/frametest.c index 1b932e4..f891530 100644 --- a/tests/frametest.c +++ b/tests/frametest.c @@ -200,6 +200,24 @@ int basicTests(U32 seed, double compressibility) DISPLAYLEVEL(3, " %u \n", (U32)cBound); } + /* LZ4F_compressBound() : special case : automatic flushing enabled */ + DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=1) = "); + { size_t cBound; + LZ4F_preferences_t autoFlushPrefs; + memset(&autoFlushPrefs, 0, sizeof(autoFlushPrefs)); + autoFlushPrefs.autoFlush = 1; + cBound = LZ4F_compressBound(1 KB, &autoFlushPrefs); + if (cBound > 64 KB) goto _output_error; + DISPLAYLEVEL(3, " %u \n", (U32)cBound); + } + + /* LZ4F_compressBound() : special case : automatic flushing disabled */ + DISPLAYLEVEL(3, "LZ4F_compressBound(1 KB, autoFlush=0) = "); + { size_t const cBound = LZ4F_compressBound(1 KB, &prefs); + if (cBound < 64 KB) goto _output_error; + DISPLAYLEVEL(3, " %u \n", (U32)cBound); + } + /* Special case : null-content frame */ testSize = 0; DISPLAYLEVEL(3, "LZ4F_compressFrame, compress null content : "); diff --git a/tests/test_install.sh b/tests/test_install.sh index f9de402..122bac5 100755 --- a/tests/test_install.sh +++ b/tests/test_install.sh @@ -1,7 +1,15 @@ #/usr/bin/env sh set -e + make="make -C $lz4_root" +unamestr=$(uname) +if [ "$unamestr" = 'Linux' ]; then + make="make -C $lz4_root" +elif [ "$unamestr" = 'FreeBSD' -o "$unamestr" = 'OpenBSD' ]; then + make="gmake -C $lz4_root" +fi + for cmd in install uninstall; do for upper in DUMMY PREFIX EXEC_PREFIX LIBDIR INCLUDEDIR PKGCONFIGDIR BINDIR MANDIR MAN1DIR ; do lower=$(echo $upper | tr '[:upper:]' '[:lower:]') diff --git a/visual/.gitignore b/visual/.gitignore index 276f8f5..69e1111 100644 --- a/visual/.gitignore +++ b/visual/.gitignore @@ -8,3 +8,9 @@ *.user ver*/ VS2010/bin/ +VS2017/bin/ +ipch + +# Fixup for lz4 project directories +!VS2010/lz4 +!VS2017/lz4 diff --git a/visual/VS2017/lz4.sln b/visual/VS2017/lz4.sln index 72e98fc..6a2779f 100644 --- a/visual/VS2017/lz4.sln +++ b/visual/VS2017/lz4.sln @@ -19,6 +19,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fullbench-dll", "fullbench- {9800039D-4AAA-43A4-BB78-FEF6F4836927} = {9800039D-4AAA-43A4-BB78-FEF6F4836927} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lz4", "lz4\lz4.vcxproj", "{60A3115E-B988-41EE-8815-F4D4F253D866}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -83,6 +85,14 @@ Global {13992FD2-077E-4954-B065-A428198201A9}.Release|Win32.Build.0 = Release|Win32 {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.ActiveCfg = Release|x64 {13992FD2-077E-4954-B065-A428198201A9}.Release|x64.Build.0 = Release|x64 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Debug|Win32.ActiveCfg = Debug|Win32 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Debug|Win32.Build.0 = Debug|Win32 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Debug|x64.ActiveCfg = Debug|x64 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Debug|x64.Build.0 = Debug|x64 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Release|Win32.ActiveCfg = Release|Win32 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Release|Win32.Build.0 = Release|Win32 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Release|x64.ActiveCfg = Release|x64 + {60A3115E-B988-41EE-8815-F4D4F253D866}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/visual/VS2017/lz4/lz4.rc b/visual/VS2017/lz4/lz4.rc new file mode 100644 index 0000000..c593edf --- /dev/null +++ b/visual/VS2017/lz4/lz4.rc @@ -0,0 +1,51 @@ +// Microsoft Visual C++ generated resource script. +// + +#include "lz4.h" /* LZ4_VERSION_STRING */ +#define APSTUDIO_READONLY_SYMBOLS +#include "verrsrc.h" +#undef APSTUDIO_READONLY_SYMBOLS + + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE 9, 1 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION LZ4_VERSION_MAJOR,LZ4_VERSION_MINOR,LZ4_VERSION_RELEASE,0 + PRODUCTVERSION LZ4_VERSION_MAJOR,LZ4_VERSION_MINOR,LZ4_VERSION_RELEASE,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Yann Collet" + VALUE "FileDescription", "Extremely fast compression" + VALUE "FileVersion", LZ4_VERSION_STRING + VALUE "InternalName", "lz4.exe" + VALUE "LegalCopyright", "Copyright (C) 2013-2016, Yann Collet" + VALUE "OriginalFilename", "lz4.exe" + VALUE "ProductName", "LZ4" + VALUE "ProductVersion", LZ4_VERSION_STRING + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1200 + END +END + +#endif diff --git a/visual/VS2017/lz4/lz4.vcxproj b/visual/VS2017/lz4/lz4.vcxproj new file mode 100644 index 0000000..b4fed24 --- /dev/null +++ b/visual/VS2017/lz4/lz4.vcxproj @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{60A3115E-B988-41EE-8815-F4D4F253D866}</ProjectGuid> + <RootNamespace>lz4</RootNamespace> + <WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>false</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <OutDir>$(SolutionDir)bin\$(Platform)_$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <OutDir>$(SolutionDir)bin\$(Platform)_$(Configuration)\</OutDir> + <IntDir>$(SolutionDir)bin\obj\$(RootNamespace)_$(Platform)_$(Configuration)\</IntDir> + <IncludePath>$(IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)..\..\lib;$(SolutionDir)..\..\programs;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);</IncludePath> + <LinkIncremental>false</LinkIncremental> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + <TreatWarningAsError>true</TreatWarningAsError> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + <OptimizeReferences>false</OptimizeReferences> + <EnableCOMDATFolding>false</EnableCOMDATFolding> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <SubSystem>Console</SubSystem> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="..\..\..\lib\lz4.c" /> + <ClCompile Include="..\..\..\lib\lz4frame.c" /> + <ClCompile Include="..\..\..\lib\lz4hc.c" /> + <ClCompile Include="..\..\..\lib\xxhash.c" /> + <ClCompile Include="..\..\..\programs\bench.c" /> + <ClCompile Include="..\..\..\programs\datagen.c" /> + <ClCompile Include="..\..\..\programs\lz4cli.c" /> + <ClCompile Include="..\..\..\programs\lz4io.c" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="..\..\..\lib\lz4.h" /> + <ClInclude Include="..\..\..\lib\lz4frame.h" /> + <ClInclude Include="..\..\..\lib\lz4frame_static.h" /> + <ClInclude Include="..\..\..\lib\lz4hc.h" /> + <ClInclude Include="..\..\..\lib\xxhash.h" /> + <ClInclude Include="..\..\..\programs\bench.h" /> + <ClInclude Include="..\..\..\programs\datagen.h" /> + <ClInclude Include="..\..\..\programs\lz4io.h" /> + </ItemGroup> + <ItemGroup> + <ResourceCompile Include="lz4.rc" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file |