Squashed 'src/lz4/' content from commit e25b51d
git-subtree-dir: src/lz4 git-subtree-split: e25b51de7b51101e04ceea194dd557fcc23c03ca
10
.gitattributes
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Set the default behavior
|
||||
* text eol=lf
|
||||
|
||||
# Explicitly declare source files
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
|
||||
# Denote files that should not be modified.
|
||||
*.odt binary
|
||||
*.png binary
|
||||
26
.travis.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
language: c
|
||||
compiler: gcc
|
||||
script: make test-travis
|
||||
before_install:
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq gcc-multilib
|
||||
- sudo apt-get install -qq valgrind
|
||||
|
||||
env:
|
||||
- LZ4_TRAVIS_CI_ENV=travis-install
|
||||
- LZ4_TRAVIS_CI_ENV=streaming-examples
|
||||
- LZ4_TRAVIS_CI_ENV=cmake
|
||||
- LZ4_TRAVIS_CI_ENV=dist
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4c
|
||||
- LZ4_TRAVIS_CI_ENV=test-lz4c32
|
||||
- LZ4_TRAVIS_CI_ENV=test-fullbench
|
||||
- LZ4_TRAVIS_CI_ENV=test-fullbench32
|
||||
- LZ4_TRAVIS_CI_ENV=test-fuzzer
|
||||
- LZ4_TRAVIS_CI_ENV=test-fuzzer32
|
||||
- LZ4_TRAVIS_CI_ENV=test-frametest
|
||||
- LZ4_TRAVIS_CI_ENV=test-frametest32
|
||||
- LZ4_TRAVIS_CI_ENV=test-mem
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
1
LZ4_Frame_Format.html
Normal file
136
Makefile
Normal file
@@ -0,0 +1,136 @@
|
||||
# ################################################################
|
||||
# LZ4 - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
# All rights reserved.
|
||||
#
|
||||
# BSD license
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ################################################################
|
||||
|
||||
# Version number
|
||||
export VERSION=126
|
||||
export RELEASE=r$(VERSION)
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
|
||||
LIBDIR ?= $(PREFIX)/lib
|
||||
INCLUDEDIR=$(PREFIX)/include
|
||||
PRGDIR = programs
|
||||
LZ4DIR = lib
|
||||
DISTRIBNAME=lz4-$(RELEASE).tar.gz
|
||||
|
||||
TEXT = $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4.h $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4hc.h \
|
||||
$(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4frame.h $(LZ4DIR)/lz4frame_static.h \
|
||||
$(LZ4DIR)/xxhash.c $(LZ4DIR)/xxhash.h \
|
||||
$(LZ4DIR)/liblz4.pc.in $(LZ4DIR)/Makefile $(LZ4DIR)/LICENSE \
|
||||
Makefile lz4_block_format.txt LZ4_Frame_Format.html NEWS README.md \
|
||||
cmake_unofficial/CMakeLists.txt \
|
||||
$(PRGDIR)/fullbench.c $(PRGDIR)/lz4cli.c \
|
||||
$(PRGDIR)/datagen.c $(PRGDIR)/fuzzer.c \
|
||||
$(PRGDIR)/lz4io.c $(PRGDIR)/lz4io.h \
|
||||
$(PRGDIR)/bench.c $(PRGDIR)/bench.h \
|
||||
$(PRGDIR)/lz4.1 $(PRGDIR)/lz4c.1 $(PRGDIR)/lz4cat.1 \
|
||||
$(PRGDIR)/Makefile $(PRGDIR)/COPYING
|
||||
NONTEXT = images/image00.png images/image01.png images/image02.png \
|
||||
images/image03.png images/image04.png images/image05.png \
|
||||
images/image06.png
|
||||
SOURCES = $(TEXT) $(NONTEXT)
|
||||
|
||||
|
||||
# Select test target for Travis CI's Build Matrix
|
||||
ifneq (,$(filter test-%,$(LZ4_TRAVIS_CI_ENV)))
|
||||
TRAVIS_TARGET=prg-travis
|
||||
else
|
||||
TRAVIS_TARGET=$(LZ4_TRAVIS_CI_ENV)
|
||||
endif
|
||||
|
||||
|
||||
default: lz4programs
|
||||
|
||||
all:
|
||||
@cd $(LZ4DIR); $(MAKE) -e all
|
||||
@cd $(PRGDIR); $(MAKE) -e all
|
||||
|
||||
lz4programs:
|
||||
@cd $(PRGDIR); $(MAKE) -e
|
||||
|
||||
clean:
|
||||
@rm -f $(DISTRIBNAME) *.sha1
|
||||
@cd $(PRGDIR); $(MAKE) clean
|
||||
@cd $(LZ4DIR); $(MAKE) clean
|
||||
@cd examples; $(MAKE) clean
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
install:
|
||||
@cd $(LZ4DIR); $(MAKE) -e install
|
||||
@cd $(PRGDIR); $(MAKE) -e install
|
||||
|
||||
uninstall:
|
||||
@cd $(LZ4DIR); $(MAKE) uninstall
|
||||
@cd $(PRGDIR); $(MAKE) uninstall
|
||||
|
||||
travis-install:
|
||||
sudo $(MAKE) install
|
||||
|
||||
dist: clean
|
||||
@install -dD -m 700 lz4-$(RELEASE)/lib/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/programs/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/cmake_unofficial/
|
||||
@install -dD -m 700 lz4-$(RELEASE)/images/
|
||||
@for f in $(TEXT); do \
|
||||
tr -d '\r' < $$f > .tmp; \
|
||||
install -m 600 .tmp lz4-$(RELEASE)/$$f; \
|
||||
done
|
||||
@rm .tmp
|
||||
@for f in $(NONTEXT); do \
|
||||
install -m 600 $$f lz4-$(RELEASE)/$$f; \
|
||||
done
|
||||
@tar -czf $(DISTRIBNAME) lz4-$(RELEASE)/
|
||||
@rm -rf lz4-$(RELEASE)
|
||||
@sha1sum $(DISTRIBNAME) > $(DISTRIBNAME).sha1
|
||||
@echo Distribution $(DISTRIBNAME) built
|
||||
|
||||
test:
|
||||
@cd $(PRGDIR); $(MAKE) -e test
|
||||
|
||||
test-travis: $(TRAVIS_TARGET)
|
||||
|
||||
cmake:
|
||||
@cd cmake_unofficial; cmake CMakeLists.txt; $(MAKE)
|
||||
|
||||
streaming-examples:
|
||||
cd examples; $(MAKE) -e test
|
||||
|
||||
prg-travis:
|
||||
@cd $(PRGDIR); $(MAKE) -e test-travis
|
||||
|
||||
endif
|
||||
133
NEWS
Normal file
@@ -0,0 +1,133 @@
|
||||
r126:
|
||||
New : lz4frame API is now integrated into liblz4
|
||||
Fixed : GCC 4.9 bug on highest performance settings, reported by Greg Slazinski
|
||||
Fixed : bug within LZ4 HC streaming mode, reported by James Boyle
|
||||
Fixed : older compiler don't like nameless unions, reported by Cheyi Lin
|
||||
Changed : lz4 is C90 compatible
|
||||
Changed : added -pedantic option, fixed a few mminor warnings
|
||||
|
||||
r125:
|
||||
Changed : endian and alignment code
|
||||
Changed : directory structure : new "lib" directory
|
||||
Updated : lz4io, now uses lz4frame
|
||||
Improved: slightly improved decoding speed
|
||||
Fixed : LZ4_compress_limitedOutput(); Special thanks to Christopher Speller !
|
||||
Fixed : some alignment warnings under clang
|
||||
Fixed : deprecated function LZ4_slideInputBufferHC()
|
||||
|
||||
r124:
|
||||
New : LZ4 HC streaming mode
|
||||
Fixed : LZ4F_compressBound() using null preferencesPtr
|
||||
Updated : xxHash to r38
|
||||
Updated library number, to 1.4.0
|
||||
|
||||
r123:
|
||||
Added : experimental lz4frame API, thanks to Takayuki Matsuoka and Christopher Jackson for testings
|
||||
Fix : s390x support, thanks to Nobuhiro Iwamatsu
|
||||
Fix : test mode (-t) no longer requires confirmation, thanks to Thary Nguyen
|
||||
|
||||
r122:
|
||||
Fix : AIX & AIX64 support (SamG)
|
||||
Fix : mips 64-bits support (lew van)
|
||||
Added : Examples directory, using code examples from Takayuki Matsuoka
|
||||
Updated : Framing specification, to v1.4.1
|
||||
Updated : xxHash, to r36
|
||||
|
||||
r121:
|
||||
Added : Makefile : install for kFreeBSD and Hurd (Nobuhiro Iwamatsu)
|
||||
Fix : Makefile : install for OS-X and BSD, thanks to Takayuki Matsuoka
|
||||
|
||||
r120:
|
||||
Modified : Streaming API, using strong types
|
||||
Added : LZ4_versionNumber(), thanks to Takayuki Matsuoka
|
||||
Fix : OS-X : library install name, thanks to Clemens Lang
|
||||
Updated : Makefile : synchronize library version number with lz4.h, thanks to Takayuki Matsuoka
|
||||
Updated : Makefile : stricter compilation flags
|
||||
Added : pkg-config, thanks to Zbigniew Jędrzejewski-Szmek (issue 135)
|
||||
Makefile : lz4-test only test native binaries, as suggested by Michał Górny (issue 136)
|
||||
Updated : xxHash to r35
|
||||
|
||||
r119:
|
||||
Fix : Issue 134 : extended malicious address space overflow in 32-bits mode for some specific configurations
|
||||
|
||||
r118:
|
||||
New : LZ4 Streaming API (Fast version), special thanks to Takayuki Matsuoka
|
||||
New : datagen : parametrable synthetic data generator for tests
|
||||
Improved : fuzzer, support more test cases, more parameters, ability to jump to specific test
|
||||
fix : support ppc64le platform (issue 131)
|
||||
fix : Issue 52 (malicious address space overflow in 32-bits mode when using large custom format)
|
||||
fix : Makefile : minor issue 130 : header files permissions
|
||||
|
||||
r117:
|
||||
Added : man pages for lz4c and lz4cat
|
||||
Added : automated tests on Travis, thanks to Takayuki Matsuoka !
|
||||
fix : block-dependency command line (issue 127)
|
||||
fix : lz4fullbench (issue 128)
|
||||
|
||||
r116:
|
||||
hotfix (issue 124 & 125)
|
||||
|
||||
r115:
|
||||
Added : lz4cat utility, installed on POSX systems (issue 118)
|
||||
OS-X compatible compilation of dynamic library (issue 115)
|
||||
|
||||
r114:
|
||||
Makefile : library correctly compiled with -O3 switch (issue 114)
|
||||
Makefile : library compilation compatible with clang
|
||||
Makefile : library is versioned and linked (issue 119)
|
||||
lz4.h : no more static inline prototypes (issue 116)
|
||||
man : improved header/footer (issue 111)
|
||||
Makefile : Use system default $(CC) & $(MAKE) variables (issue 112)
|
||||
xxhash : updated to r34
|
||||
|
||||
r113:
|
||||
Large decompression speed improvement for GCC 32-bits. Thanks to Valery Croizier !
|
||||
LZ4HC : Compression Level is now a programmable parameter (CLI from 4 to 9)
|
||||
Separated IO routines from command line (lz4io.c)
|
||||
Version number into lz4.h (suggested by Francesc Alted)
|
||||
|
||||
r112:
|
||||
quickfix
|
||||
|
||||
r111 :
|
||||
Makefile : added capability to install libraries
|
||||
Modified Directory tree, to better separate libraries from programs.
|
||||
|
||||
r110 :
|
||||
lz4 & lz4hc : added capability to allocate state & stream state with custom allocator (issue 99)
|
||||
fuzzer & fullbench : updated to test new functions
|
||||
man : documented -l command (Legacy format, for Linux kernel compression) (issue 102)
|
||||
cmake : improved version by Mika Attila, building programs and libraries (issue 100)
|
||||
xxHash : updated to r33
|
||||
Makefile : clean also delete local package .tar.gz
|
||||
|
||||
r109 :
|
||||
lz4.c : corrected issue 98 (LZ4_compress_limitedOutput())
|
||||
Makefile : can specify version number from makefile
|
||||
|
||||
r108 :
|
||||
lz4.c : corrected compression efficiency issue 97 in 64-bits chained mode (-BD) for streams > 4 GB (thanks Roman Strashkin for reporting)
|
||||
|
||||
r107 :
|
||||
Makefile : support DESTDIR for staged installs. Thanks Jorge Aparicio.
|
||||
Makefile : make install installs both lz4 and lz4c (Jorge Aparicio)
|
||||
Makefile : removed -Wno-implicit-declaration compilation switch
|
||||
lz4cli.c : include <stduni.h> for isatty() (Luca Barbato)
|
||||
lz4.h : introduced LZ4_MAX_INPUT_SIZE constant (Shay Green)
|
||||
lz4.h : LZ4_compressBound() : unified macro and inline definitions (Shay Green)
|
||||
lz4.h : LZ4_decompressSafe_partial() : clarify comments (Shay Green)
|
||||
lz4.c : LZ4_compress() verify input size condition (Shay Green)
|
||||
bench.c : corrected a bug in free memory size evaluation
|
||||
cmake : install into bin/ directory (Richard Yao)
|
||||
cmake : check for just C compiler (Elan Ruusamae)
|
||||
|
||||
r106 :
|
||||
Makefile : make dist modify text files in the package to respect Unix EoL convention
|
||||
lz4cli.c : corrected small display bug in HC mode
|
||||
|
||||
r105 :
|
||||
Makefile : New install script and man page, contributed by Prasad Pandit
|
||||
lz4cli.c : Minor modifications, for easier extensibility
|
||||
COPYING : added license file
|
||||
LZ4_Streaming_Format.odt : modified file name to remove white space characters
|
||||
Makefile : .exe suffix now properly added only for Windows target
|
||||
56
README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
LZ4 - Extremely fast compression
|
||||
================================
|
||||
|
||||
LZ4 is lossless compression algorithm, providing compression speed at 400 MB/s per core, scalable with multi-cores CPU. It also features an extremely fast decoder, with speed in multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.
|
||||
A high compression derivative, called LZ4_HC, is also provided. It trades CPU time for compression ratio.
|
||||
|
||||
|Branch |Status |
|
||||
|------------|---------|
|
||||
|master | [](https://travis-ci.org/Cyan4973/lz4) |
|
||||
|dev | [](https://travis-ci.org/Cyan4973/lz4) |
|
||||
|
||||
This is an official mirror of LZ4 project, [hosted on Google Code](http://code.google.com/p/lz4/).
|
||||
The intention is to offer github's capabilities to lz4 users, such as cloning, branch, pull requests or source download.
|
||||
|
||||
The "master" branch will reflect, the status of lz4 at its official homepage.
|
||||
The "dev" branch is the one where all contributions will be merged. If you plan to propose a patch, please commit into the "dev" branch. Direct commit to "master" are not permitted.
|
||||
Feature branches will also exist, typically to introduce new requirements, and be temporarily available for testing before merge into "dev" branch.
|
||||
|
||||
|
||||
Benchmarks
|
||||
-------------------------
|
||||
|
||||
The benchmark uses the [Open-Source Benchmark program by m^2 (v0.14.2)](http://encode.ru/threads/1371-Filesystem-benchmark?p=33548&viewfull=1#post33548) compiled with GCC v4.6.1 on Linux Ubuntu 64-bits v11.10,
|
||||
The reference system uses a Core i5-3340M @2.7GHz.
|
||||
Benchmark evaluates the compression of reference [Silesia Corpus](http://sun.aei.polsl.pl/~sdeor/index.php?page=silesia) in single-thread mode.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Compressor</th><th>Ratio</th><th>Compression</th><th>Decompression</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZ4 (r101)</th><th>2.084</th><th>422 MB/s</th><th>1820 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZO 2.06</th><th>2.106</th><th>414 MB/s</th><th>600 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>QuickLZ 1.5.1b6</th><th>2.237</th><th>373 MB/s</th><th>420 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Snappy 1.1.0</th><th>2.091</th><th>323 MB/s</th><th>1070 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZF</th><th>2.077</th><th>270 MB/s</th><th>570 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>zlib 1.2.8 -1</th><th>2.730</th><th>65 MB/s</th><th>280 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>LZ4 HC (r101)</th><th>2.720</th><th>25 MB/s</th><th>2080 MB/s</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>zlib 1.2.8 -6</th><th>3.099</th><th>21 MB/s</th><th>300 MB/s</th>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
82
cmake_unofficial/CMakeLists.txt
Normal file
@@ -0,0 +1,82 @@
|
||||
PROJECT(LZ4 C)
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LZ4 compression library")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 1)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH r126)
|
||||
set(VERSION_STRING " \"${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}\" ")
|
||||
include(CPack)
|
||||
|
||||
cmake_minimum_required (VERSION 2.6)
|
||||
INCLUDE (CheckTypeSize)
|
||||
check_type_size("void *" SIZEOF_VOID_P)
|
||||
IF( ${SIZEOF_VOID_P} STREQUAL "8" )
|
||||
set (CMAKE_SYSTEM_PROCESSOR "64bit")
|
||||
MESSAGE( STATUS "64 bit architecture detected size of void * is " ${SIZEOF_VOID_P})
|
||||
ENDIF()
|
||||
|
||||
option(BUILD_TOOLS "Build the command line tools" ON)
|
||||
option(BUILD_LIBS "Build the libraries in addition to the tools" OFF)
|
||||
|
||||
if(UNIX AND BUILD_LIBS)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
add_definitions(-fPIC)
|
||||
endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
|
||||
endif()
|
||||
|
||||
set(LZ4_DIR ../lib/)
|
||||
set(PRG_DIR ../programs/)
|
||||
set(LZ4_SRCS_LIB ${LZ4_DIR}lz4.c ${LZ4_DIR}lz4hc.c ${LZ4_DIR}lz4.h ${LZ4_DIR}lz4hc.h)
|
||||
set(LZ4_SRCS ${LZ4_DIR}lz4frame.c ${LZ4_DIR}xxhash.c ${PRG_DIR}bench.c ${PRG_DIR}lz4cli.c ${PRG_DIR}lz4io.c)
|
||||
|
||||
if(BUILD_TOOLS AND NOT BUILD_LIBS)
|
||||
set(LZ4_SRCS ${LZ4_SRCS} ${LZ4_SRCS_LIB})
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_executable(lz4 ${LZ4_SRCS})
|
||||
set_target_properties(lz4 PROPERTIES COMPILE_DEFINITIONS DISABLE_LZ4C_LEGACY_OPTIONS)
|
||||
install(TARGETS lz4 RUNTIME DESTINATION "bin/")
|
||||
add_executable(lz4c ${LZ4_SRCS})
|
||||
install(TARGETS lz4c RUNTIME DESTINATION "bin/")
|
||||
endif()
|
||||
|
||||
if(BUILD_LIBS)
|
||||
add_library(liblz4 ${LZ4_SRCS_LIB})
|
||||
|
||||
set_target_properties(liblz4 PROPERTIES
|
||||
OUTPUT_NAME lz4
|
||||
SOVERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
install(TARGETS liblz4
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${LZ4_DIR}/lz4.h
|
||||
${LZ4_DIR}/lz4hc.h
|
||||
DESTINATION include
|
||||
)
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
target_link_libraries(lz4 liblz4)
|
||||
target_link_libraries(lz4c liblz4)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
#warnings
|
||||
|
||||
ADD_DEFINITIONS("-Wall")
|
||||
ADD_DEFINITIONS("-Wextra")
|
||||
ADD_DEFINITIONS("-Wundef")
|
||||
ADD_DEFINITIONS("-Wshadow")
|
||||
ADD_DEFINITIONS("-Wcast-align")
|
||||
ADD_DEFINITIONS("-Wstrict-prototypes")
|
||||
ADD_DEFINITIONS("-std=c99")
|
||||
ADD_DEFINITIONS("-DLZ4_VERSION=\"${CPACK_PACKAGE_VERSION_PATCH}\"")
|
||||
INCLUDE_DIRECTORIES (${LZ4_DIR})
|
||||
|
||||
|
||||
|
||||
239
examples/HCStreaming_ringBuffer.c
Executable file
@@ -0,0 +1,239 @@
|
||||
// LZ4 HC streaming API example : ring buffer
|
||||
// Based on previous work from Takayuki Matsuoka
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
**************************************/
|
||||
#include "lz4hc.h"
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 8 + MESSAGE_MAX_BYTES,
|
||||
DEC_BUFFER_BYTES = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES // Intentionally larger to test unsynchronized ring buffers
|
||||
};
|
||||
|
||||
|
||||
size_t write_int32(FILE* fp, int32_t i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int32(FILE* fp, int32_t* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, int arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_streamHC_t lz4Stream_body = { 0 };
|
||||
LZ4_streamHC_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
static char inpBuf[RING_BUFFER_BYTES];
|
||||
int inpOffset = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
// Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
const int cmpBytes = LZ4_compressHC_continue(lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
|
||||
if(cmpBytes <= 0) break;
|
||||
write_int32(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
inpOffset += inpBytes;
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES)
|
||||
inpOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
write_int32(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
static char decBuf[DEC_BUFFER_BYTES];
|
||||
int decOffset = 0;
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int cmpBytes = 0;
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
|
||||
{
|
||||
const size_t r0 = read_int32(inpFp, &cmpBytes);
|
||||
size_t r1;
|
||||
if(r0 != 1 || cmpBytes <= 0)
|
||||
break;
|
||||
|
||||
r1 = read_bin(inpFp, cmpBuf, cmpBytes);
|
||||
if(r1 != (size_t) cmpBytes)
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
|
||||
if(decBytes <= 0)
|
||||
break;
|
||||
|
||||
decOffset += decBytes;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(decOffset >= DEC_BUFFER_BYTES - MESSAGE_MAX_BYTES)
|
||||
decOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Compare 2 files content
|
||||
// return 0 if identical
|
||||
// return ByteNb>0 if different
|
||||
size_t compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
size_t result = 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = fread(b0, 1, sizeof(b0), f0);
|
||||
const size_t r1 = fread(b1, 1, sizeof(b1), f1);
|
||||
|
||||
if ((r0==0) && (r1==0)) return 0; // success
|
||||
|
||||
if (r0 != r1)
|
||||
{
|
||||
size_t smallest = r0;
|
||||
if (r1<r0) smallest = r1;
|
||||
result += smallest;
|
||||
break;
|
||||
}
|
||||
|
||||
if (memcmp(b0, b1, r0))
|
||||
{
|
||||
unsigned errorPos = 0;
|
||||
while ((errorPos < r0) && (b0[errorPos]==b1[errorPos])) errorPos++;
|
||||
result += errorPos;
|
||||
break;
|
||||
}
|
||||
|
||||
result += sizeof(b0);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
unsigned fileID = 1;
|
||||
unsigned pause = 0;
|
||||
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "-p")) pause = 1, fileID = 2;
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[fileID]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[fileID], 9);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[fileID], 9);
|
||||
|
||||
printf("input = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("decoded = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const size_t cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("Verify : OK\n");
|
||||
} else {
|
||||
printf("Verify : NG : error at pos %u\n", (unsigned)cmp-1);
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
if (pause)
|
||||
{
|
||||
printf("Press enter to continue ...\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
examples/Makefile
Normal file
@@ -0,0 +1,89 @@
|
||||
# ##########################################################################
|
||||
# LZ4 examples - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2014
|
||||
# GPL v2 License
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ##########################################################################
|
||||
# lz4 : Command Line Utility, supporting gzip-like arguments
|
||||
# lz4c : CLU, supporting also legacy lz4demo arguments
|
||||
# lz4c32: Same as lz4c, but forced to compile in 32-bits mode
|
||||
# fuzzer : Test tool, to check lz4 integrity on target platform
|
||||
# fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode
|
||||
# fullbench : Precisely measure speed for each LZ4 function variant
|
||||
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
|
||||
# ##########################################################################
|
||||
|
||||
CC := $(CC)
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -Wno-missing-braces # Wno-missing-braces required due to GCC <4.8.3 bug
|
||||
FLAGS = -I../lib $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
TESTFILE= Makefile
|
||||
LZ4DIR = ../lib
|
||||
|
||||
|
||||
# Minimize test target for Travis CI's Build Matrix
|
||||
ifeq ($(LZ4_TRAVIS_CI_ENV),-m32)
|
||||
CFLAGS += -m32
|
||||
else ifeq ($(LZ4_TRAVIS_CI_ENV),-m64)
|
||||
endif
|
||||
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
EXT =.exe
|
||||
VOID = nul
|
||||
else
|
||||
EXT =
|
||||
VOID = /dev/null
|
||||
endif
|
||||
|
||||
|
||||
default: all
|
||||
|
||||
all: printVersion doubleBuffer ringBuffer ringBufferHC lineCompress
|
||||
|
||||
printVersion: $(LZ4DIR)/lz4.c printVersion.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
doubleBuffer: $(LZ4DIR)/lz4.c blockStreaming_doubleBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
ringBuffer : $(LZ4DIR)/lz4.c blockStreaming_ringBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
ringBufferHC: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c HCStreaming_ringBuffer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
lineCompress: $(LZ4DIR)/lz4.c blockStreaming_lineByLine.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
test : all
|
||||
./printVersion$(EXT)
|
||||
./doubleBuffer$(EXT) $(TESTFILE)
|
||||
./ringBuffer$(EXT) $(TESTFILE)
|
||||
./ringBufferHC$(EXT) $(TESTFILE)
|
||||
./lineCompress$(EXT) $(TESTFILE)
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.dec *-0 *-9 *-8192 *.lz4s \
|
||||
printVersion$(EXT) doubleBuffer$(EXT) ringBuffer$(EXT) ringBufferHC$(EXT) lineCompress$(EXT)
|
||||
@echo Cleaning completed
|
||||
|
||||
195
examples/blockStreaming_doubleBuffer.c
Normal file
@@ -0,0 +1,195 @@
|
||||
// LZ4 streaming API example : double buffer
|
||||
// Copyright : Takayuki Matsuoka
|
||||
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum {
|
||||
BLOCK_BYTES = 1024 * 8,
|
||||
// BLOCK_BYTES = 1024 * 64,
|
||||
};
|
||||
|
||||
|
||||
size_t write_int(FILE* fp, int i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, size_t arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int(FILE* fp, int* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, size_t arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_stream_t lz4Stream_body = { 0 };
|
||||
LZ4_stream_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
char inpBuf[2][BLOCK_BYTES];
|
||||
int inpBufIndex = 0;
|
||||
|
||||
for(;;) {
|
||||
char* const inpPtr = inpBuf[inpBufIndex];
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, BLOCK_BYTES);
|
||||
if(0 == inpBytes) {
|
||||
break;
|
||||
}
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
|
||||
const int cmpBytes = LZ4_compress_continue(
|
||||
lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if(cmpBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
write_int(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, (size_t) cmpBytes);
|
||||
}
|
||||
|
||||
inpBufIndex = (inpBufIndex + 1) % 2;
|
||||
}
|
||||
|
||||
write_int(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
char decBuf[2][BLOCK_BYTES];
|
||||
int decBufIndex = 0;
|
||||
|
||||
for(;;) {
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(BLOCK_BYTES)];
|
||||
int cmpBytes = 0;
|
||||
|
||||
{
|
||||
const size_t readCount0 = read_int(inpFp, &cmpBytes);
|
||||
if(readCount0 != 1 || cmpBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
const size_t readCount1 = read_bin(inpFp, cmpBuf, (size_t) cmpBytes);
|
||||
if(readCount1 != (size_t) cmpBytes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = decBuf[decBufIndex];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, BLOCK_BYTES);
|
||||
if(decBytes <= 0) {
|
||||
break;
|
||||
}
|
||||
write_bin(outFp, decPtr, (size_t) decBytes);
|
||||
}
|
||||
|
||||
decBufIndex = (decBufIndex + 1) % 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int compare(FILE* fp0, FILE* fp1)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while(0 == result) {
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = read_bin(fp0, b0, sizeof(b0));
|
||||
const size_t r1 = read_bin(fp1, b1, sizeof(b1));
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if(0 == r0 || 0 == r1) {
|
||||
break;
|
||||
}
|
||||
if(0 == result) {
|
||||
result = memcmp(b0, b1, r0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], BLOCK_BYTES);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], BLOCK_BYTES);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
printf("compress : %s -> %s\n", inpFilename, lz4Filename);
|
||||
test_compress(outFp, inpFp);
|
||||
printf("compress : done\n");
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
printf("decompress : %s -> %s\n", lz4Filename, decFilename);
|
||||
test_decompress(outFp, inpFp);
|
||||
printf("decompress : done\n");
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
printf("verify : %s <-> %s\n", inpFilename, decFilename);
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("verify : OK\n");
|
||||
} else {
|
||||
printf("verify : NG\n");
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
207
examples/blockStreaming_lineByLine.c
Normal file
@@ -0,0 +1,207 @@
|
||||
// LZ4 streaming API example : line-by-line logfile compression
|
||||
// Copyright : Takayuki Matsuoka
|
||||
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
#include "lz4.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static size_t write_uint16(FILE* fp, uint16_t i)
|
||||
{
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
static size_t write_bin(FILE* fp, const void* array, int arrayBytes)
|
||||
{
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
static size_t read_uint16(FILE* fp, uint16_t* i)
|
||||
{
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
static size_t read_bin(FILE* fp, void* array, int arrayBytes)
|
||||
{
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
static void test_compress(
|
||||
FILE* outFp,
|
||||
FILE* inpFp,
|
||||
size_t messageMaxBytes,
|
||||
size_t ringBufferBytes)
|
||||
{
|
||||
LZ4_stream_t* const lz4Stream = LZ4_createStream();
|
||||
char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
|
||||
char* const inpBuf = malloc(ringBufferBytes);
|
||||
int inpOffset = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
|
||||
#if 0
|
||||
// Read random length data to the ring buffer.
|
||||
const int randomLength = (rand() % messageMaxBytes) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
#else
|
||||
// Read line to the ring buffer.
|
||||
int inpBytes = 0;
|
||||
if (!fgets(inpPtr, (int) messageMaxBytes, inpFp))
|
||||
break;
|
||||
inpBytes = (int) strlen(inpPtr);
|
||||
#endif
|
||||
|
||||
{
|
||||
const int cmpBytes = LZ4_compress_continue(
|
||||
lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if (cmpBytes <= 0) break;
|
||||
write_uint16(outFp, (uint16_t) cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
// Add and wraparound the ringbuffer offset
|
||||
inpOffset += inpBytes;
|
||||
if ((size_t)inpOffset >= ringBufferBytes - messageMaxBytes) inpOffset = 0;
|
||||
}
|
||||
}
|
||||
write_uint16(outFp, 0);
|
||||
|
||||
free(inpBuf);
|
||||
free(cmpBuf);
|
||||
LZ4_freeStream(lz4Stream);
|
||||
}
|
||||
|
||||
|
||||
static void test_decompress(
|
||||
FILE* outFp,
|
||||
FILE* inpFp,
|
||||
size_t messageMaxBytes,
|
||||
size_t ringBufferBytes)
|
||||
{
|
||||
LZ4_streamDecode_t* const lz4StreamDecode = LZ4_createStreamDecode();
|
||||
char* const cmpBuf = malloc(LZ4_COMPRESSBOUND(messageMaxBytes));
|
||||
char* const decBuf = malloc(ringBufferBytes);
|
||||
int decOffset = 0;
|
||||
|
||||
for ( ; ; )
|
||||
{
|
||||
uint16_t cmpBytes = 0;
|
||||
|
||||
if (read_uint16(inpFp, &cmpBytes) != 1) break;
|
||||
if (cmpBytes <= 0) break;
|
||||
if (read_bin(inpFp, cmpBuf, cmpBytes) != cmpBytes) break;
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, (int) messageMaxBytes);
|
||||
if (decBytes <= 0) break;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Add and wraparound the ringbuffer offset
|
||||
decOffset += decBytes;
|
||||
if ((size_t)decOffset >= ringBufferBytes - messageMaxBytes) decOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free(decBuf);
|
||||
free(cmpBuf);
|
||||
LZ4_freeStreamDecode(lz4StreamDecode);
|
||||
}
|
||||
|
||||
|
||||
static int compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
int result = 0;
|
||||
const size_t tempBufferBytes = 65536;
|
||||
char* const b0 = malloc(tempBufferBytes);
|
||||
char* const b1 = malloc(tempBufferBytes);
|
||||
|
||||
while(0 == result)
|
||||
{
|
||||
const size_t r0 = fread(b0, 1, tempBufferBytes, f0);
|
||||
const size_t r1 = fread(b1, 1, tempBufferBytes, f1);
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if (0 == r0 || 0 == r1) break;
|
||||
if (0 == result) result = memcmp(b0, b1, r0);
|
||||
}
|
||||
|
||||
free(b1);
|
||||
free(b0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 256 + MESSAGE_MAX_BYTES,
|
||||
};
|
||||
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s", argv[1]);
|
||||
snprintf(decFilename, 256, "%s.lz4s.dec", argv[1]);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp, MESSAGE_MAX_BYTES, RING_BUFFER_BYTES);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if (0 == cmp)
|
||||
printf("Verify : OK\n");
|
||||
else
|
||||
printf("Verify : NG\n");
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
200
examples/blockStreaming_ringBuffer.c
Normal file
@@ -0,0 +1,200 @@
|
||||
// LZ4 streaming API example : ring buffer
|
||||
// Based on sample code from Takayuki Matsuoka
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
**************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS // for MSVC
|
||||
# define snprintf sprintf_s
|
||||
#endif
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
**************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "lz4.h"
|
||||
|
||||
|
||||
enum {
|
||||
MESSAGE_MAX_BYTES = 1024,
|
||||
RING_BUFFER_BYTES = 1024 * 8 + MESSAGE_MAX_BYTES,
|
||||
DECODE_RING_BUFFER = RING_BUFFER_BYTES + MESSAGE_MAX_BYTES // Intentionally larger, to test unsynchronized ring buffers
|
||||
};
|
||||
|
||||
|
||||
size_t write_int32(FILE* fp, int32_t i) {
|
||||
return fwrite(&i, sizeof(i), 1, fp);
|
||||
}
|
||||
|
||||
size_t write_bin(FILE* fp, const void* array, int arrayBytes) {
|
||||
return fwrite(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
size_t read_int32(FILE* fp, int32_t* i) {
|
||||
return fread(i, sizeof(*i), 1, fp);
|
||||
}
|
||||
|
||||
size_t read_bin(FILE* fp, void* array, int arrayBytes) {
|
||||
return fread(array, 1, arrayBytes, fp);
|
||||
}
|
||||
|
||||
|
||||
void test_compress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
LZ4_stream_t lz4Stream_body = { 0 };
|
||||
LZ4_stream_t* lz4Stream = &lz4Stream_body;
|
||||
|
||||
static char inpBuf[RING_BUFFER_BYTES];
|
||||
int inpOffset = 0;
|
||||
|
||||
for(;;) {
|
||||
// Read random length ([1,MESSAGE_MAX_BYTES]) data to the ring buffer.
|
||||
char* const inpPtr = &inpBuf[inpOffset];
|
||||
const int randomLength = (rand() % MESSAGE_MAX_BYTES) + 1;
|
||||
const int inpBytes = (int) read_bin(inpFp, inpPtr, randomLength);
|
||||
if (0 == inpBytes) break;
|
||||
|
||||
{
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
const int cmpBytes = LZ4_compress_continue(lz4Stream, inpPtr, cmpBuf, inpBytes);
|
||||
if(cmpBytes <= 0) break;
|
||||
write_int32(outFp, cmpBytes);
|
||||
write_bin(outFp, cmpBuf, cmpBytes);
|
||||
|
||||
inpOffset += inpBytes;
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(inpOffset >= RING_BUFFER_BYTES - MESSAGE_MAX_BYTES) inpOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
write_int32(outFp, 0);
|
||||
}
|
||||
|
||||
|
||||
void test_decompress(FILE* outFp, FILE* inpFp)
|
||||
{
|
||||
static char decBuf[DECODE_RING_BUFFER];
|
||||
int decOffset = 0;
|
||||
LZ4_streamDecode_t lz4StreamDecode_body = { 0 };
|
||||
LZ4_streamDecode_t* lz4StreamDecode = &lz4StreamDecode_body;
|
||||
|
||||
for(;;) {
|
||||
int cmpBytes = 0;
|
||||
char cmpBuf[LZ4_COMPRESSBOUND(MESSAGE_MAX_BYTES)];
|
||||
|
||||
{
|
||||
const size_t r0 = read_int32(inpFp, &cmpBytes);
|
||||
if(r0 != 1 || cmpBytes <= 0) break;
|
||||
|
||||
const size_t r1 = read_bin(inpFp, cmpBuf, cmpBytes);
|
||||
if(r1 != (size_t) cmpBytes) break;
|
||||
}
|
||||
|
||||
{
|
||||
char* const decPtr = &decBuf[decOffset];
|
||||
const int decBytes = LZ4_decompress_safe_continue(
|
||||
lz4StreamDecode, cmpBuf, decPtr, cmpBytes, MESSAGE_MAX_BYTES);
|
||||
if(decBytes <= 0) break;
|
||||
decOffset += decBytes;
|
||||
write_bin(outFp, decPtr, decBytes);
|
||||
|
||||
// Wraparound the ringbuffer offset
|
||||
if(decOffset >= DECODE_RING_BUFFER - MESSAGE_MAX_BYTES) decOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int compare(FILE* f0, FILE* f1)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
while(0 == result) {
|
||||
char b0[65536];
|
||||
char b1[65536];
|
||||
const size_t r0 = fread(b0, 1, sizeof(b0), f0);
|
||||
const size_t r1 = fread(b1, 1, sizeof(b1), f1);
|
||||
|
||||
result = (int) r0 - (int) r1;
|
||||
|
||||
if(0 == r0 || 0 == r1) {
|
||||
break;
|
||||
}
|
||||
if(0 == result) {
|
||||
result = memcmp(b0, b1, r0);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char inpFilename[256] = { 0 };
|
||||
char lz4Filename[256] = { 0 };
|
||||
char decFilename[256] = { 0 };
|
||||
|
||||
if(argc < 2) {
|
||||
printf("Please specify input filename\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(inpFilename, 256, "%s", argv[1]);
|
||||
snprintf(lz4Filename, 256, "%s.lz4s-%d", argv[1], 0);
|
||||
snprintf(decFilename, 256, "%s.lz4s-%d.dec", argv[1], 0);
|
||||
|
||||
printf("inp = [%s]\n", inpFilename);
|
||||
printf("lz4 = [%s]\n", lz4Filename);
|
||||
printf("dec = [%s]\n", decFilename);
|
||||
|
||||
// compress
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* outFp = fopen(lz4Filename, "wb");
|
||||
|
||||
test_compress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// decompress
|
||||
{
|
||||
FILE* inpFp = fopen(lz4Filename, "rb");
|
||||
FILE* outFp = fopen(decFilename, "wb");
|
||||
|
||||
test_decompress(outFp, inpFp);
|
||||
|
||||
fclose(outFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
// verify
|
||||
{
|
||||
FILE* inpFp = fopen(inpFilename, "rb");
|
||||
FILE* decFp = fopen(decFilename, "rb");
|
||||
|
||||
const int cmp = compare(inpFp, decFp);
|
||||
if(0 == cmp) {
|
||||
printf("Verify : OK\n");
|
||||
} else {
|
||||
printf("Verify : NG\n");
|
||||
}
|
||||
|
||||
fclose(decFp);
|
||||
fclose(inpFp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
examples/printVersion.c
Normal file
@@ -0,0 +1,13 @@
|
||||
// LZ4 trivial example : print Library version number
|
||||
// Copyright : Takayuki Matsuoka & Yann Collet
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include "lz4.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
(void)argc; (void)argv;
|
||||
printf("Hello World ! LZ4 Library version = %d\n", LZ4_versionNumber());
|
||||
return 0;
|
||||
}
|
||||
BIN
images/image00.png
Executable file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
images/image01.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
images/image02.png
Executable file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
images/image03.png
Executable file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
images/image04.png
Executable file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
images/image05.png
Executable file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
images/image06.png
Executable file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
lib/LICENSE
Normal file
117
lib/Makefile
Normal file
@@ -0,0 +1,117 @@
|
||||
# ################################################################
|
||||
# LZ4 library - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
# All rights reserved.
|
||||
#
|
||||
# BSD license
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice, this
|
||||
# list of conditions and the following disclaimer in the documentation and/or
|
||||
# other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ################################################################
|
||||
|
||||
# Version numbers
|
||||
VERSION ?= 126
|
||||
LIBVER_MAJOR=`sed -n '/define LZ4_VERSION_MAJOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER_MINOR=`sed -n '/define LZ4_VERSION_MINOR/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER_PATCH=`sed -n '/define LZ4_VERSION_RELEASE/s/.*[[:blank:]]\([0-9][0-9]*\).*/\1/p' < lz4.h`
|
||||
LIBVER=$(LIBVER_MAJOR).$(LIBVER_MINOR).$(LIBVER_PATCH)
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -I. -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -pedantic
|
||||
|
||||
LIBDIR?= $(PREFIX)/lib
|
||||
INCLUDEDIR=$(PREFIX)/include
|
||||
|
||||
|
||||
# OS X linker doesn't support -soname, and use different extension
|
||||
# see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
|
||||
ifeq ($(shell uname), Darwin)
|
||||
SHARED_EXT = dylib
|
||||
SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT)
|
||||
SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT)
|
||||
SONAME_FLAGS = -install_name $(PREFIX)/lib/liblz4.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER)
|
||||
else
|
||||
SONAME_FLAGS = -Wl,-soname=liblz4.$(SHARED_EXT).$(LIBVER_MAJOR)
|
||||
SHARED_EXT = so
|
||||
SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR)
|
||||
SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER)
|
||||
endif
|
||||
|
||||
default: liblz4
|
||||
|
||||
all: liblz4
|
||||
|
||||
liblz4: lz4.c lz4hc.c lz4frame.c xxhash.c
|
||||
@echo compiling static library
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) -c $^
|
||||
@$(AR) rcs liblz4.a lz4.o lz4hc.o lz4frame.o xxhash.o
|
||||
@echo compiling dynamic library $(LIBVER)
|
||||
@$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared $^ -fPIC $(SONAME_FLAGS) -o $@.$(SHARED_EXT_VER)
|
||||
@echo creating versioned links
|
||||
@ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT_MAJOR)
|
||||
@ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT)
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.a *.$(SHARED_EXT) *.$(SHARED_EXT).* liblz4.pc
|
||||
@echo Cleaning library completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
liblz4.pc: liblz4.pc.in Makefile
|
||||
@echo creating pkgconfig
|
||||
@sed -e 's|@PREFIX@|$(PREFIX)|' \
|
||||
-e 's|@LIBDIR@|$(LIBDIR)|' \
|
||||
-e 's|@INCLUDEDIR@|$(INCLUDEDIR)|' \
|
||||
-e 's|@VERSION@|$(VERSION)|' \
|
||||
$< >$@
|
||||
|
||||
install: liblz4 liblz4.pc
|
||||
@install -d -m 755 $(DESTDIR)$(LIBDIR)/pkgconfig/ $(DESTDIR)$(INCLUDEDIR)/
|
||||
@install -m 755 liblz4.$(SHARED_EXT_VER) $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER)
|
||||
@cp -a liblz4.$(SHARED_EXT_MAJOR) $(DESTDIR)$(LIBDIR)
|
||||
@cp -a liblz4.$(SHARED_EXT) $(DESTDIR)$(LIBDIR)
|
||||
@cp -a liblz4.pc $(DESTDIR)$(LIBDIR)/pkgconfig/
|
||||
@install -m 644 liblz4.a $(DESTDIR)$(LIBDIR)/liblz4.a
|
||||
@install -m 644 lz4.h $(DESTDIR)$(INCLUDEDIR)/lz4.h
|
||||
@install -m 644 lz4hc.h $(DESTDIR)$(INCLUDEDIR)/lz4hc.h
|
||||
@install -m 644 lz4frame.h $(DESTDIR)$(INCLUDEDIR)/lz4frame.h
|
||||
@echo lz4 static and shared library installed
|
||||
|
||||
uninstall:
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT)
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_MAJOR)
|
||||
@rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/liblz4.pc
|
||||
@[ -x $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER) ] && rm -f $(DESTDIR)$(LIBDIR)/liblz4.$(SHARED_EXT_VER)
|
||||
@[ -f $(DESTDIR)$(LIBDIR)/liblz4.a ] && rm -f $(DESTDIR)$(LIBDIR)/liblz4.a
|
||||
@[ -f $(DESTDIR)$(INCLUDEDIR)/lz4.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/lz4.h
|
||||
@[ -f $(DESTDIR)$(INCLUDEDIR)/lz4hc.h ] && rm -f $(DESTDIR)$(INCLUDEDIR)/lz4hc.h
|
||||
@echo lz4 libraries successfully uninstalled
|
||||
|
||||
endif
|
||||
14
lib/liblz4.pc.in
Normal file
@@ -0,0 +1,14 @@
|
||||
# LZ4 - Fast LZ compression algorithm
|
||||
# Copyright (C) 2011-2014, Yann Collet.
|
||||
# BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
prefix=@PREFIX@
|
||||
libdir=@LIBDIR@
|
||||
includedir=@INCLUDEDIR@
|
||||
|
||||
Name: lz4
|
||||
Description: fast lossless compression algorithm library
|
||||
URL: http://code.google.com/p/lz4/
|
||||
Version: @VERSION@
|
||||
Libs: -L@LIBDIR@ -llz4
|
||||
Cflags: -I@INCLUDEDIR@
|
||||
315
lib/lz4.h
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Header File
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* lz4.h provides raw compression format functions, for optimal performance and integration into programs.
|
||||
* If you need to generate data using an inter-operable format (respecting the framing specification),
|
||||
* please use lz4frame.h instead.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Version
|
||||
**************************************/
|
||||
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
|
||||
#define LZ4_VERSION_MINOR 5 /* for new (non-breaking) interface capabilities */
|
||||
#define LZ4_VERSION_RELEASE 0 /* for tweaks, bug-fixes, or development */
|
||||
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
|
||||
int LZ4_versionNumber (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
|
||||
* Reduced memory usage can improve speed, due to cache effect
|
||||
* Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
|
||||
*/
|
||||
#define LZ4_MEMORY_USAGE 14
|
||||
|
||||
|
||||
/**************************************
|
||||
Simple Functions
|
||||
**************************************/
|
||||
|
||||
int LZ4_compress (const char* source, char* dest, int sourceSize);
|
||||
int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize);
|
||||
|
||||
/*
|
||||
LZ4_compress() :
|
||||
Compresses 'sourceSize' bytes from 'source' into 'dest'.
|
||||
Destination buffer must be already allocated,
|
||||
and must be sized to handle worst cases situations (input data not compressible)
|
||||
Worst case size evaluation is provided by function LZ4_compressBound()
|
||||
inputSize : Max supported value is LZ4_MAX_INPUT_SIZE
|
||||
return : the number of bytes written in buffer dest
|
||||
or 0 if the compression fails
|
||||
|
||||
LZ4_decompress_safe() :
|
||||
compressedSize : is obviously the source size
|
||||
maxDecompressedSize : is the size of the destination buffer, which must be already allocated.
|
||||
return : the number of bytes decompressed into the destination buffer (necessarily <= maxDecompressedSize)
|
||||
If the 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,
|
||||
and never writes outside of output buffer, nor reads outside of input buffer.
|
||||
It is also protected against malicious data packets.
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
Advanced Functions
|
||||
**************************************/
|
||||
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
|
||||
#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
|
||||
|
||||
/*
|
||||
LZ4_compressBound() :
|
||||
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 (output buffer size).
|
||||
Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).
|
||||
|
||||
isize : is the input size. 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)
|
||||
*/
|
||||
int LZ4_compressBound(int isize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_compress_limitedOutput() :
|
||||
Compress 'sourceSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
|
||||
If it cannot achieve it, compression will stop, and result of the function will be zero.
|
||||
This saves time and memory on detecting non-compressible (or barely compressible) data.
|
||||
This function never writes outside of provided output buffer.
|
||||
|
||||
sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE
|
||||
maxOutputSize : is the size of the destination buffer (which must be already allocated)
|
||||
return : the number of bytes written in buffer 'dest'
|
||||
or 0 if compression fails
|
||||
*/
|
||||
int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_compress_withState() :
|
||||
Same compression functions, but using an externally allocated memory space to store compression state.
|
||||
Use LZ4_sizeofState() to know how much memory must be allocated,
|
||||
and then, provide it as 'void* state' to compression functions.
|
||||
*/
|
||||
int LZ4_sizeofState(void);
|
||||
int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_decompress_fast() :
|
||||
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).
|
||||
*/
|
||||
int LZ4_decompress_fast (const char* source, char* dest, int originalSize);
|
||||
|
||||
|
||||
/*
|
||||
LZ4_decompress_safe_partial() :
|
||||
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
|
||||
*/
|
||||
int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize);
|
||||
|
||||
|
||||
/***********************************************
|
||||
Streaming Compression Functions
|
||||
***********************************************/
|
||||
|
||||
#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 !
|
||||
* 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.
|
||||
*/
|
||||
typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t;
|
||||
|
||||
/*
|
||||
* LZ4_resetStream
|
||||
* Use this function to init an allocated LZ4_stream_t structure
|
||||
*/
|
||||
void LZ4_resetStream (LZ4_stream_t* LZ4_streamPtr);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
LZ4_stream_t* LZ4_createStream(void);
|
||||
int LZ4_freeStream (LZ4_stream_t* LZ4_streamPtr);
|
||||
|
||||
/*
|
||||
* LZ4_loadDict
|
||||
* 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)
|
||||
*/
|
||||
int LZ4_loadDict (LZ4_stream_t* LZ4_streamPtr, const char* dictionary, int dictSize);
|
||||
|
||||
/*
|
||||
* LZ4_compress_continue
|
||||
* Compress data block 'source', using blocks compressed before as dictionary to improve compression ratio
|
||||
* Previous data blocks are assumed to still be present at their previous location.
|
||||
*/
|
||||
int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);
|
||||
|
||||
/*
|
||||
* LZ4_compress_limitedOutput_continue
|
||||
* Same as before, but also specify a maximum target compressed size (maxOutputSize)
|
||||
* If objective cannot be met, compression exits, and returns a zero.
|
||||
*/
|
||||
int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
/*
|
||||
* LZ4_saveDict
|
||||
* 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 again LZ4_compress_continue()
|
||||
* Return : dictionary size in bytes, or 0 if error
|
||||
* Note : any dictSize > 64 KB will be interpreted as 64KB.
|
||||
*/
|
||||
int LZ4_saveDict (LZ4_stream_t* LZ4_streamPtr, char* safeBuffer, int dictSize);
|
||||
|
||||
|
||||
/************************************************
|
||||
Streaming Decompression Functions
|
||||
************************************************/
|
||||
|
||||
#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 !
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
LZ4_streamDecode_t* LZ4_createStreamDecode(void);
|
||||
int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);
|
||||
|
||||
/*
|
||||
* LZ4_setStreamDecode
|
||||
* 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
|
||||
*/
|
||||
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)
|
||||
If this condition is not possible, save the relevant part of decoded data into a safe buffer,
|
||||
and indicate where is its new address using LZ4_setStreamDecode()
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
Advanced decoding functions :
|
||||
*_usingDict() :
|
||||
These decoding functions work the same as
|
||||
a combination of LZ4_setDictDecode() followed by LZ4_decompress_x_continue()
|
||||
They are stand-alone and don't use nor update an LZ4_streamDecode_t structure.
|
||||
*/
|
||||
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);
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Obsolete Functions
|
||||
**************************************/
|
||||
/*
|
||||
Obsolete decompression functions
|
||||
These function names are deprecated and should no longer be used.
|
||||
They are only provided here for compatibility with older user programs.
|
||||
- LZ4_uncompress is the same as LZ4_decompress_fast
|
||||
- LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe
|
||||
These function prototypes are now disabled; uncomment them if you really need them.
|
||||
It is highly recommended to stop using these functions and migrate to newer ones */
|
||||
/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */
|
||||
/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */
|
||||
|
||||
|
||||
/* Obsolete streaming functions; use new streaming interface whenever possible */
|
||||
void* LZ4_create (const char* inputBuffer);
|
||||
int LZ4_sizeofStreamState(void);
|
||||
int LZ4_resetStreamState(void* state, const char* inputBuffer);
|
||||
char* LZ4_slideInputBuffer (void* state);
|
||||
|
||||
/* Obsolete streaming decoding functions */
|
||||
int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int compressedSize, int maxOutputSize);
|
||||
int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int originalSize);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
1330
lib/lz4frame.c
Normal file
252
lib/lz4frame.h
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File
|
||||
Copyright (C) 2011-2015, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/* LZ4F is a stand-alone API to create LZ4-compressed frames
|
||||
* fully conformant to specification v1.4.1.
|
||||
* All related operations, including memory management, are handled by the library.
|
||||
* You don't need lz4.h when using lz4frame.h.
|
||||
* */
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Error management
|
||||
* ************************************/
|
||||
typedef size_t LZ4F_errorCode_t;
|
||||
|
||||
unsigned LZ4F_isError(LZ4F_errorCode_t code);
|
||||
const char* LZ4F_getErrorName(LZ4F_errorCode_t code); /* return error code string; useful for debugging */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Frame compression types
|
||||
* ************************************/
|
||||
typedef enum { LZ4F_default=0, max64KB=4, max256KB=5, max1MB=6, max4MB=7 } blockSizeID_t;
|
||||
typedef enum { blockLinked=0, blockIndependent} blockMode_t;
|
||||
typedef enum { noContentChecksum=0, contentChecksumEnabled } contentChecksum_t;
|
||||
|
||||
typedef struct {
|
||||
blockSizeID_t blockSizeID; /* max64KB, max256KB, max1MB, max4MB ; 0 == default */
|
||||
blockMode_t blockMode; /* blockLinked, blockIndependent ; 0 == default */
|
||||
contentChecksum_t contentChecksumFlag; /* noContentChecksum, contentChecksumEnabled ; 0 == default */
|
||||
unsigned reserved[5];
|
||||
} LZ4F_frameInfo_t;
|
||||
|
||||
typedef struct {
|
||||
LZ4F_frameInfo_t frameInfo;
|
||||
unsigned compressionLevel; /* 0 == default (fast mode); values above 16 count as 16 */
|
||||
unsigned autoFlush; /* 1 == always flush : reduce need for tmp buffer */
|
||||
unsigned reserved[4];
|
||||
} LZ4F_preferences_t;
|
||||
|
||||
|
||||
/***********************************
|
||||
* Simple compression function
|
||||
* *********************************/
|
||||
size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
|
||||
size_t LZ4F_compressFrame(void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressFrame()
|
||||
* Compress an entire srcBuffer into a valid LZ4 frame, as defined by specification v1.4.1.
|
||||
* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
|
||||
* You can get the minimum value of dstMaxSize by using LZ4F_compressFrameBound()
|
||||
* If this condition is not respected, LZ4F_compressFrame() will fail (result is an errorCode)
|
||||
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.
|
||||
* The result of the function is the number of bytes written into dstBuffer.
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**********************************
|
||||
* Advanced compression functions
|
||||
* ********************************/
|
||||
typedef void* LZ4F_compressionContext_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned stableSrc; /* 1 == src content will remain available on future calls to LZ4F_compress(); avoid saving src content within tmp buffer as future dictionary */
|
||||
unsigned reserved[3];
|
||||
} LZ4F_compressOptions_t;
|
||||
|
||||
/* Resource Management */
|
||||
|
||||
#define LZ4F_VERSION 100
|
||||
LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_compressionContext_t* LZ4F_compressionContextPtr, unsigned version);
|
||||
LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_compressionContext_t LZ4F_compressionContext);
|
||||
/* LZ4F_createCompressionContext() :
|
||||
* The first thing to do is to create a compressionContext object, which will be used in all compression operations.
|
||||
* This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.
|
||||
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
|
||||
* The function will provide a pointer to a fully allocated LZ4F_compressionContext_t object.
|
||||
* If the result LZ4F_errorCode_t is not zero, there was an error during context creation.
|
||||
* Object can release its memory using LZ4F_freeCompressionContext();
|
||||
*/
|
||||
|
||||
|
||||
/* Compression */
|
||||
|
||||
size_t LZ4F_compressBegin(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressBegin() :
|
||||
* will write the frame header into dstBuffer.
|
||||
* dstBuffer must be large enough to accommodate a header (dstMaxSize). Maximum header size is 19 bytes.
|
||||
* The LZ4F_preferences_t structure is optional : you can provide NULL as argument, all preferences will then be set to default.
|
||||
* The result of the function is the number of bytes written into dstBuffer for the header
|
||||
* or an error code (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);
|
||||
/* LZ4F_compressBound() :
|
||||
* Provides the minimum size of Dst buffer given srcSize to handle worst case situations.
|
||||
* preferencesPtr is optional : you can provide NULL as argument, all preferences will then be set to default.
|
||||
* Note that different preferences will produce in different results.
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressUpdate(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const void* srcBuffer, size_t srcSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_compressUpdate()
|
||||
* LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.
|
||||
* The most important rule is that dstBuffer MUST be large enough (dstMaxSize) to ensure compression completion even in worst case.
|
||||
* If this condition is not respected, LZ4F_compress() will fail (result is an errorCode)
|
||||
* You can get the minimum value of dstMaxSize by using LZ4F_compressBound()
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* The result of the function is the number of bytes written into dstBuffer : it can be zero, meaning input data was just buffered.
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_flush(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_flush()
|
||||
* Should you need to create compressed data immediately, without waiting for a block to be filled,
|
||||
* you can call LZ4_flush(), which will immediately compress any remaining data buffered within compressionContext.
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* The result of the function is the number of bytes written into dstBuffer
|
||||
* (it can be zero, this means there was no data left within compressionContext)
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
*/
|
||||
|
||||
size_t LZ4F_compressEnd(LZ4F_compressionContext_t compressionContext, void* dstBuffer, size_t dstMaxSize, const LZ4F_compressOptions_t* compressOptionsPtr);
|
||||
/* LZ4F_compressEnd()
|
||||
* When you want to properly finish the compressed frame, just call LZ4F_compressEnd().
|
||||
* It will flush whatever data remained within compressionContext (like LZ4_flush())
|
||||
* but also properly finalize the frame, with an endMark and a checksum.
|
||||
* The result of the function is the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))
|
||||
* The function outputs an error code if it fails (can be tested using LZ4F_isError())
|
||||
* The LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.
|
||||
* compressionContext can then be used again, starting with LZ4F_compressBegin().
|
||||
*/
|
||||
|
||||
|
||||
/***********************************
|
||||
* Decompression functions
|
||||
* *********************************/
|
||||
|
||||
typedef void* LZ4F_decompressionContext_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned stableDst; /* guarantee that decompressed data will still be there on next function calls (avoid storage into tmp buffers) */
|
||||
unsigned reserved[3];
|
||||
} LZ4F_decompressOptions_t;
|
||||
|
||||
|
||||
/* Resource management */
|
||||
|
||||
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t* ctxPtr, unsigned version);
|
||||
LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t ctx);
|
||||
/* LZ4F_createDecompressionContext() :
|
||||
* The first thing to do is to create a decompressionContext object, which will be used in all decompression operations.
|
||||
* This is achieved using LZ4F_createDecompressionContext().
|
||||
* The version provided MUST be LZ4F_VERSION. It is intended to track potential version differences between different binaries.
|
||||
* The function will provide a pointer to a fully allocated and initialized LZ4F_decompressionContext_t object.
|
||||
* If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.
|
||||
* Object can release its memory using LZ4F_freeDecompressionContext();
|
||||
*/
|
||||
|
||||
|
||||
/* Decompression */
|
||||
|
||||
size_t LZ4F_getFrameInfo(LZ4F_decompressionContext_t ctx,
|
||||
LZ4F_frameInfo_t* frameInfoPtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr);
|
||||
/* LZ4F_getFrameInfo()
|
||||
* This function decodes frame header information, such as blockSize.
|
||||
* It is optional : you could start by calling directly LZ4F_decompress() instead.
|
||||
* The objective is to extract header information without starting decompression, typically for allocation purposes.
|
||||
* LZ4F_getFrameInfo() can also be used *after* starting decompression, on a valid LZ4F_decompressionContext_t.
|
||||
* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
|
||||
* You are expected to resume decompression from where it stopped (srcBuffer + *srcSizePtr)
|
||||
* The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for next call,
|
||||
* or an error code which can be tested using LZ4F_isError().
|
||||
*/
|
||||
|
||||
size_t LZ4F_decompress(LZ4F_decompressionContext_t ctx,
|
||||
void* dstBuffer, size_t* dstSizePtr,
|
||||
const void* srcBuffer, size_t* srcSizePtr,
|
||||
const LZ4F_decompressOptions_t* optionsPtr);
|
||||
/* LZ4F_decompress()
|
||||
* Call this function repetitively to regenerate data compressed within srcBuffer.
|
||||
* The function will attempt to decode *srcSizePtr bytes from srcBuffer, into dstBuffer of maximum size *dstSizePtr.
|
||||
*
|
||||
* The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).
|
||||
*
|
||||
* The number of bytes read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).
|
||||
* If number of bytes read is < number of bytes provided, then decompression operation is not completed.
|
||||
* It typically happens when dstBuffer is not large enough to contain all decoded data.
|
||||
* LZ4F_decompress() must be called again, starting from where it stopped (srcBuffer + *srcSizePtr)
|
||||
* The function will check this condition, and refuse to continue if it is not respected.
|
||||
*
|
||||
* dstBuffer is supposed to be flushed between each call to the function, since its content will be overwritten.
|
||||
* dst arguments can be changed at will with each consecutive call to the function.
|
||||
*
|
||||
* The function result is an hint of how many srcSize bytes LZ4F_decompress() expects for next call.
|
||||
* Schematically, it's the size of the current (or remaining) compressed block + header of next block.
|
||||
* Respecting the hint provides some boost to performance, since it does skip intermediate buffers.
|
||||
* This is just a hint, you can always provide any srcSize you want.
|
||||
* When a frame is fully decoded, the function result will be 0. (no more data expected)
|
||||
* If decompression failed, function result is an error code, which can be tested using LZ4F_isError().
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
72
lib/lz4frame_static.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
LZ4 auto-framing library
|
||||
Header File for static linking only
|
||||
Copyright (C) 2011-2015, Yann Collet.
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* lz4frame_static.h should be used solely in the context of static linking.
|
||||
* */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Error management
|
||||
* ************************************/
|
||||
#define LZ4F_LIST_ERRORS(ITEM) \
|
||||
ITEM(OK_NoError) ITEM(ERROR_GENERIC) \
|
||||
ITEM(ERROR_maxBlockSize_invalid) ITEM(ERROR_blockMode_invalid) ITEM(ERROR_contentChecksumFlag_invalid) \
|
||||
ITEM(ERROR_compressionLevel_invalid) \
|
||||
ITEM(ERROR_allocation_failed) \
|
||||
ITEM(ERROR_srcSize_tooLarge) ITEM(ERROR_dstMaxSize_tooSmall) \
|
||||
ITEM(ERROR_decompressionFailed) \
|
||||
ITEM(ERROR_checksum_invalid) \
|
||||
ITEM(ERROR_maxCode)
|
||||
|
||||
#define LZ4F_GENERATE_ENUM(ENUM) ENUM,
|
||||
typedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM) } LZ4F_errorCodes; /* enum is exposed, to handle specific errors; compare function result to -enum value */
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include "lz4frame.h"
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
751
lib/lz4hc.c
Normal file
@@ -0,0 +1,751 @@
|
||||
/*
|
||||
LZ4 HC - High Compression Mode of LZ4
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Tuning Parameter
|
||||
**************************************/
|
||||
static const int LZ4HC_compressionLevel_default = 8;
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include "lz4hc.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Compiler Options
|
||||
**************************************/
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
#if defined (__clang__)
|
||||
# pragma clang diagnostic ignored "-Wunused-function"
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Common LZ4 definition
|
||||
**************************************/
|
||||
#define LZ4_COMMONDEFS_ONLY
|
||||
#include "lz4.c"
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Constants
|
||||
**************************************/
|
||||
#define DICTIONARY_LOGSIZE 16
|
||||
#define MAXD (1<<DICTIONARY_LOGSIZE)
|
||||
#define MAXD_MASK ((U32)(MAXD - 1))
|
||||
|
||||
#define HASH_LOG (DICTIONARY_LOGSIZE-1)
|
||||
#define HASHTABLESIZE (1 << HASH_LOG)
|
||||
#define HASH_MASK (HASHTABLESIZE - 1)
|
||||
|
||||
#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)
|
||||
|
||||
static const int g_maxCompressionLevel = 16;
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Types
|
||||
**************************************/
|
||||
typedef struct
|
||||
{
|
||||
U32 hashTable[HASHTABLESIZE];
|
||||
U16 chainTable[MAXD];
|
||||
const BYTE* end; /* next block here to continue on current prefix */
|
||||
const BYTE* base; /* All index relative to this position */
|
||||
const BYTE* dictBase; /* alternate base for extDict */
|
||||
const BYTE* inputBuffer;/* deprecated */
|
||||
U32 dictLimit; /* below that point, need extDict */
|
||||
U32 lowLimit; /* below that point, no more dict */
|
||||
U32 nextToUpdate;
|
||||
U32 compressionLevel;
|
||||
} LZ4HC_Data_Structure;
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Macros
|
||||
**************************************/
|
||||
#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-HASH_LOG))
|
||||
#define DELTANEXT(p) chainTable[(size_t)(p) & MAXD_MASK]
|
||||
#define GETNEXT(p) ((p) - (size_t)DELTANEXT(p))
|
||||
|
||||
static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
HC Compression
|
||||
**************************************/
|
||||
static void LZ4HC_init (LZ4HC_Data_Structure* hc4, const BYTE* start)
|
||||
{
|
||||
MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));
|
||||
MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));
|
||||
hc4->nextToUpdate = 64 KB;
|
||||
hc4->base = start - 64 KB;
|
||||
hc4->inputBuffer = start;
|
||||
hc4->end = start;
|
||||
hc4->dictBase = start - 64 KB;
|
||||
hc4->dictLimit = 64 KB;
|
||||
hc4->lowLimit = 64 KB;
|
||||
}
|
||||
|
||||
|
||||
/* Update chains up to ip (excluded) */
|
||||
FORCE_INLINE void LZ4HC_Insert (LZ4HC_Data_Structure* hc4, const BYTE* ip)
|
||||
{
|
||||
U16* chainTable = hc4->chainTable;
|
||||
U32* HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const U32 target = (U32)(ip - base);
|
||||
U32 idx = hc4->nextToUpdate;
|
||||
|
||||
while(idx < target)
|
||||
{
|
||||
U32 h = LZ4HC_hashPtr(base+idx);
|
||||
size_t delta = idx - HashTable[h];
|
||||
if (delta>MAX_DISTANCE) delta = MAX_DISTANCE;
|
||||
chainTable[idx & 0xFFFF] = (U16)delta;
|
||||
HashTable[h] = idx;
|
||||
idx++;
|
||||
}
|
||||
|
||||
hc4->nextToUpdate = target;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE int LZ4HC_InsertAndFindBestMatch (LZ4HC_Data_Structure* hc4, /* Index table will be updated */
|
||||
const BYTE* ip, const BYTE* const iLimit,
|
||||
const BYTE** matchpos,
|
||||
const int maxNbAttempts)
|
||||
{
|
||||
U16* const chainTable = hc4->chainTable;
|
||||
U32* const HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const BYTE* const dictBase = hc4->dictBase;
|
||||
const U32 dictLimit = hc4->dictLimit;
|
||||
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
|
||||
U32 matchIndex;
|
||||
const BYTE* match;
|
||||
int nbAttempts=maxNbAttempts;
|
||||
size_t ml=0;
|
||||
|
||||
/* HC4 match finder */
|
||||
LZ4HC_Insert(hc4, ip);
|
||||
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
||||
|
||||
while ((matchIndex>=lowLimit) && (nbAttempts))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (matchIndex >= dictLimit)
|
||||
{
|
||||
match = base + matchIndex;
|
||||
if (*(match+ml) == *(ip+ml)
|
||||
&& (LZ4_read32(match) == LZ4_read32(ip)))
|
||||
{
|
||||
size_t mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
|
||||
if (mlt > ml) { ml = mlt; *matchpos = match; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = dictBase + matchIndex;
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
size_t mlt;
|
||||
const BYTE* vLimit = ip + (dictLimit - matchIndex);
|
||||
if (vLimit > iLimit) vLimit = iLimit;
|
||||
mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
|
||||
if ((ip+mlt == vLimit) && (vLimit < iLimit))
|
||||
mlt += LZ4_count(ip+mlt, base+dictLimit, iLimit);
|
||||
if (mlt > ml) { ml = mlt; *matchpos = base + matchIndex; } /* virtual matchpos */
|
||||
}
|
||||
}
|
||||
matchIndex -= chainTable[matchIndex & 0xFFFF];
|
||||
}
|
||||
|
||||
return (int)ml;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE int LZ4HC_InsertAndGetWiderMatch (
|
||||
LZ4HC_Data_Structure* hc4,
|
||||
const BYTE* ip,
|
||||
const BYTE* iLowLimit,
|
||||
const BYTE* iHighLimit,
|
||||
int longest,
|
||||
const BYTE** matchpos,
|
||||
const BYTE** startpos,
|
||||
const int maxNbAttempts)
|
||||
{
|
||||
U16* const chainTable = hc4->chainTable;
|
||||
U32* const HashTable = hc4->hashTable;
|
||||
const BYTE* const base = hc4->base;
|
||||
const U32 dictLimit = hc4->dictLimit;
|
||||
const U32 lowLimit = (hc4->lowLimit + 64 KB > (U32)(ip-base)) ? hc4->lowLimit : (U32)(ip - base) - (64 KB - 1);
|
||||
const BYTE* const dictBase = hc4->dictBase;
|
||||
const BYTE* match;
|
||||
U32 matchIndex;
|
||||
int nbAttempts = maxNbAttempts;
|
||||
int delta = (int)(ip-iLowLimit);
|
||||
|
||||
|
||||
/* First Match */
|
||||
LZ4HC_Insert(hc4, ip);
|
||||
matchIndex = HashTable[LZ4HC_hashPtr(ip)];
|
||||
|
||||
while ((matchIndex>=lowLimit) && (nbAttempts))
|
||||
{
|
||||
nbAttempts--;
|
||||
if (matchIndex >= dictLimit)
|
||||
{
|
||||
match = base + matchIndex;
|
||||
if (*(iLowLimit + longest) == *(match - delta + longest))
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
const BYTE* startt = ip;
|
||||
const BYTE* tmpMatch = match;
|
||||
const BYTE* const matchEnd = ip + MINMATCH + LZ4_count(ip+MINMATCH, match+MINMATCH, iHighLimit);
|
||||
|
||||
while ((startt>iLowLimit) && (tmpMatch > iLowLimit) && (startt[-1] == tmpMatch[-1])) {startt--; tmpMatch--;}
|
||||
|
||||
if ((matchEnd-startt) > longest)
|
||||
{
|
||||
longest = (int)(matchEnd-startt);
|
||||
*matchpos = tmpMatch;
|
||||
*startpos = startt;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
match = dictBase + matchIndex;
|
||||
if (LZ4_read32(match) == LZ4_read32(ip))
|
||||
{
|
||||
size_t mlt;
|
||||
int back=0;
|
||||
const BYTE* vLimit = ip + (dictLimit - matchIndex);
|
||||
if (vLimit > iHighLimit) vLimit = iHighLimit;
|
||||
mlt = LZ4_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
|
||||
if ((ip+mlt == vLimit) && (vLimit < iHighLimit))
|
||||
mlt += LZ4_count(ip+mlt, base+dictLimit, iHighLimit);
|
||||
while ((ip+back > iLowLimit) && (matchIndex+back > lowLimit) && (ip[back-1] == match[back-1])) back--;
|
||||
mlt -= back;
|
||||
if ((int)mlt > longest) { longest = (int)mlt; *matchpos = base + matchIndex + back; *startpos = ip+back; }
|
||||
}
|
||||
}
|
||||
matchIndex -= chainTable[matchIndex & 0xFFFF];
|
||||
}
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
|
||||
typedef enum { noLimit = 0, limitedOutput = 1 } limitedOutput_directive;
|
||||
|
||||
#define LZ4HC_DEBUG 0
|
||||
#if LZ4HC_DEBUG
|
||||
static unsigned debug = 0;
|
||||
#endif
|
||||
|
||||
FORCE_INLINE int LZ4HC_encodeSequence (
|
||||
const BYTE** ip,
|
||||
BYTE** op,
|
||||
const BYTE** anchor,
|
||||
int matchLength,
|
||||
const BYTE* const match,
|
||||
limitedOutput_directive limitedOutputBuffer,
|
||||
BYTE* oend)
|
||||
{
|
||||
int length;
|
||||
BYTE* token;
|
||||
|
||||
#if LZ4HC_DEBUG
|
||||
if (debug) printf("literal : %u -- match : %u -- offset : %u\n", (U32)(*ip - *anchor), (U32)matchLength, (U32)(*ip-match));
|
||||
#endif
|
||||
|
||||
/* Encode Literal length */
|
||||
length = (int)(*ip - *anchor);
|
||||
token = (*op)++;
|
||||
if ((limitedOutputBuffer) && ((*op + (length>>8) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
|
||||
if (length>=(int)RUN_MASK) { int len; *token=(RUN_MASK<<ML_BITS); len = length-RUN_MASK; for(; len > 254 ; len-=255) *(*op)++ = 255; *(*op)++ = (BYTE)len; }
|
||||
else *token = (BYTE)(length<<ML_BITS);
|
||||
|
||||
/* Copy Literals */
|
||||
LZ4_wildCopy(*op, *anchor, (*op) + length);
|
||||
*op += length;
|
||||
|
||||
/* Encode Offset */
|
||||
LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;
|
||||
|
||||
/* Encode MatchLength */
|
||||
length = (int)(matchLength-MINMATCH);
|
||||
if ((limitedOutputBuffer) && (*op + (length>>8) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
|
||||
if (length>=(int)ML_MASK) { *token+=ML_MASK; length-=ML_MASK; for(; length > 509 ; length-=510) { *(*op)++ = 255; *(*op)++ = 255; } if (length > 254) { length-=255; *(*op)++ = 255; } *(*op)++ = (BYTE)length; }
|
||||
else *token += (BYTE)(length);
|
||||
|
||||
/* Prepare next loop */
|
||||
*ip += matchLength;
|
||||
*anchor = *ip;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int LZ4HC_compress_generic (
|
||||
void* ctxvoid,
|
||||
const char* source,
|
||||
char* dest,
|
||||
int inputSize,
|
||||
int maxOutputSize,
|
||||
int compressionLevel,
|
||||
limitedOutput_directive limit
|
||||
)
|
||||
{
|
||||
LZ4HC_Data_Structure* ctx = (LZ4HC_Data_Structure*) ctxvoid;
|
||||
const BYTE* ip = (const BYTE*) source;
|
||||
const BYTE* anchor = ip;
|
||||
const BYTE* const iend = ip + inputSize;
|
||||
const BYTE* const mflimit = iend - MFLIMIT;
|
||||
const BYTE* const matchlimit = (iend - LASTLITERALS);
|
||||
|
||||
BYTE* op = (BYTE*) dest;
|
||||
BYTE* const oend = op + maxOutputSize;
|
||||
|
||||
unsigned maxNbAttempts;
|
||||
int ml, ml2, ml3, ml0;
|
||||
const BYTE* ref=NULL;
|
||||
const BYTE* start2=NULL;
|
||||
const BYTE* ref2=NULL;
|
||||
const BYTE* start3=NULL;
|
||||
const BYTE* ref3=NULL;
|
||||
const BYTE* start0;
|
||||
const BYTE* ref0;
|
||||
|
||||
|
||||
/* init */
|
||||
if (compressionLevel > g_maxCompressionLevel) compressionLevel = g_maxCompressionLevel;
|
||||
if (compressionLevel < 1) compressionLevel = LZ4HC_compressionLevel_default;
|
||||
maxNbAttempts = 1 << (compressionLevel-1);
|
||||
ctx->end += inputSize;
|
||||
|
||||
ip++;
|
||||
|
||||
/* Main Loop */
|
||||
while (ip < mflimit)
|
||||
{
|
||||
ml = LZ4HC_InsertAndFindBestMatch (ctx, ip, matchlimit, (&ref), maxNbAttempts);
|
||||
if (!ml) { ip++; continue; }
|
||||
|
||||
/* saved, in case we would skip too much */
|
||||
start0 = ip;
|
||||
ref0 = ref;
|
||||
ml0 = ml;
|
||||
|
||||
_Search2:
|
||||
if (ip+ml < mflimit)
|
||||
ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2, maxNbAttempts);
|
||||
else ml2 = ml;
|
||||
|
||||
if (ml2 == ml) /* No better match */
|
||||
{
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start0 < ip)
|
||||
{
|
||||
if (start2 < ip + ml0) /* empirical */
|
||||
{
|
||||
ip = start0;
|
||||
ref = ref0;
|
||||
ml = ml0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Here, start0==ip */
|
||||
if ((start2 - ip) < 3) /* First Match too small : removed */
|
||||
{
|
||||
ml = ml2;
|
||||
ip = start2;
|
||||
ref =ref2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
_Search3:
|
||||
/*
|
||||
* Currently we have :
|
||||
* ml2 > ml1, and
|
||||
* ip1+3 <= ip2 (usually < ip1+ml1)
|
||||
*/
|
||||
if ((start2 - ip) < OPTIMAL_ML)
|
||||
{
|
||||
int correction;
|
||||
int new_ml = ml;
|
||||
if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;
|
||||
if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
||||
correction = new_ml - (int)(start2 - ip);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */
|
||||
|
||||
if (start2 + ml2 < mflimit)
|
||||
ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, maxNbAttempts);
|
||||
else ml3 = ml2;
|
||||
|
||||
if (ml3 == ml2) /* No better match : 2 sequences to encode */
|
||||
{
|
||||
/* ip & ref are known; Now for ml */
|
||||
if (start2 < ip+ml) ml = (int)(start2 - ip);
|
||||
/* Now, encode 2 sequences */
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
ip = start2;
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml2, ref2, limit, oend)) return 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (start3 < ip+ml+3) /* Not enough space for match 2 : remove it */
|
||||
{
|
||||
if (start3 >= (ip+ml)) /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */
|
||||
{
|
||||
if (start2 < ip+ml)
|
||||
{
|
||||
int correction = (int)(ip+ml - start2);
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
if (ml2 < MINMATCH)
|
||||
{
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
}
|
||||
}
|
||||
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
ip = start3;
|
||||
ref = ref3;
|
||||
ml = ml3;
|
||||
|
||||
start0 = start2;
|
||||
ref0 = ref2;
|
||||
ml0 = ml2;
|
||||
goto _Search2;
|
||||
}
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, now we have 3 ascending matches; let's write at least the first one
|
||||
* ip & ref are known; Now for ml
|
||||
*/
|
||||
if (start2 < ip+ml)
|
||||
{
|
||||
if ((start2 - ip) < (int)ML_MASK)
|
||||
{
|
||||
int correction;
|
||||
if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;
|
||||
if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;
|
||||
correction = ml - (int)(start2 - ip);
|
||||
if (correction > 0)
|
||||
{
|
||||
start2 += correction;
|
||||
ref2 += correction;
|
||||
ml2 -= correction;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ml = (int)(start2 - ip);
|
||||
}
|
||||
}
|
||||
if (LZ4HC_encodeSequence(&ip, &op, &anchor, ml, ref, limit, oend)) return 0;
|
||||
|
||||
ip = start2;
|
||||
ref = ref2;
|
||||
ml = ml2;
|
||||
|
||||
start2 = start3;
|
||||
ref2 = ref3;
|
||||
ml2 = ml3;
|
||||
|
||||
goto _Search3;
|
||||
}
|
||||
|
||||
/* Encode Last Literals */
|
||||
{
|
||||
int lastRun = (int)(iend - anchor);
|
||||
if ((limit) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; /* Check output limit */
|
||||
if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun > 254 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
|
||||
else *op++ = (BYTE)(lastRun<<ML_BITS);
|
||||
memcpy(op, anchor, iend - anchor);
|
||||
op += iend-anchor;
|
||||
}
|
||||
|
||||
/* End */
|
||||
return (int) (((char*)op)-dest);
|
||||
}
|
||||
|
||||
|
||||
int LZ4_compressHC2(const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
LZ4HC_Data_Structure ctx;
|
||||
LZ4HC_init(&ctx, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (&ctx, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC(const char* source, char* dest, int inputSize) { return LZ4_compressHC2(source, dest, inputSize, 0); }
|
||||
|
||||
int LZ4_compressHC2_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
LZ4HC_Data_Structure ctx;
|
||||
LZ4HC_init(&ctx, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (&ctx, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4_compressHC2_limitedOutput(source, dest, inputSize, maxOutputSize, 0);
|
||||
}
|
||||
|
||||
|
||||
/*****************************
|
||||
* Using external allocation
|
||||
* ***************************/
|
||||
int LZ4_sizeofStateHC(void) { return sizeof(LZ4HC_Data_Structure); }
|
||||
|
||||
|
||||
int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (state, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize)
|
||||
{ return LZ4_compressHC2_withStateHC (state, source, dest, inputSize, 0); }
|
||||
|
||||
|
||||
int LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)state, (const BYTE*)source);
|
||||
return LZ4HC_compress_generic (state, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{ return LZ4_compressHC2_limitedOutput_withStateHC (state, source, dest, inputSize, maxOutputSize, 0); }
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
* Streaming Functions
|
||||
* ************************************/
|
||||
/* allocation */
|
||||
LZ4_streamHC_t* LZ4_createStreamHC(void) { return (LZ4_streamHC_t*)malloc(sizeof(LZ4_streamHC_t)); }
|
||||
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) { free(LZ4_streamHCPtr); return 0; }
|
||||
|
||||
|
||||
/* initialization */
|
||||
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)
|
||||
{
|
||||
LZ4_STATIC_ASSERT(sizeof(LZ4HC_Data_Structure) <= LZ4_STREAMHCSIZE); /* if compilation fails here, LZ4_STREAMHCSIZE must be increased */
|
||||
((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->base = NULL;
|
||||
((LZ4HC_Data_Structure*)LZ4_streamHCPtr)->compressionLevel = (unsigned)compressionLevel;
|
||||
}
|
||||
|
||||
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize)
|
||||
{
|
||||
LZ4HC_Data_Structure* ctxPtr = (LZ4HC_Data_Structure*) LZ4_streamHCPtr;
|
||||
if (dictSize > 64 KB)
|
||||
{
|
||||
dictionary += dictSize - 64 KB;
|
||||
dictSize = 64 KB;
|
||||
}
|
||||
LZ4HC_init (ctxPtr, (const BYTE*)dictionary);
|
||||
if (dictSize >= 4) LZ4HC_Insert (ctxPtr, (const BYTE*)dictionary +(dictSize-3));
|
||||
ctxPtr->end = (const BYTE*)dictionary + dictSize;
|
||||
return dictSize;
|
||||
}
|
||||
|
||||
|
||||
/* compression */
|
||||
|
||||
static void LZ4HC_setExternalDict(LZ4HC_Data_Structure* ctxPtr, const BYTE* newBlock)
|
||||
{
|
||||
if (ctxPtr->end >= ctxPtr->base + 4)
|
||||
LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */
|
||||
/* Only one memory segment for extDict, so any previous extDict is lost at this stage */
|
||||
ctxPtr->lowLimit = ctxPtr->dictLimit;
|
||||
ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);
|
||||
ctxPtr->dictBase = ctxPtr->base;
|
||||
ctxPtr->base = newBlock - ctxPtr->dictLimit;
|
||||
ctxPtr->end = newBlock;
|
||||
ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */
|
||||
}
|
||||
|
||||
static int LZ4_compressHC_continue_generic (LZ4HC_Data_Structure* ctxPtr,
|
||||
const char* source, char* dest,
|
||||
int inputSize, int maxOutputSize, limitedOutput_directive limit)
|
||||
{
|
||||
/* auto-init if forgotten */
|
||||
if (ctxPtr->base == NULL)
|
||||
LZ4HC_init (ctxPtr, (const BYTE*) source);
|
||||
|
||||
/* Check overflow */
|
||||
if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB)
|
||||
{
|
||||
size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;
|
||||
if (dictSize > 64 KB) dictSize = 64 KB;
|
||||
|
||||
LZ4_loadDictHC((LZ4_streamHC_t*)ctxPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);
|
||||
}
|
||||
|
||||
/* Check if blocks follow each other */
|
||||
if ((const BYTE*)source != ctxPtr->end) LZ4HC_setExternalDict(ctxPtr, (const BYTE*)source);
|
||||
|
||||
/* Check overlapping input/dictionary space */
|
||||
{
|
||||
const BYTE* sourceEnd = (const BYTE*) source + inputSize;
|
||||
const BYTE* dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;
|
||||
const BYTE* dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;
|
||||
if ((sourceEnd > dictBegin) && ((BYTE*)source < dictEnd))
|
||||
{
|
||||
if (sourceEnd > dictEnd) sourceEnd = dictEnd;
|
||||
ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);
|
||||
if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;
|
||||
}
|
||||
}
|
||||
|
||||
return LZ4HC_compress_generic (ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr->compressionLevel, limit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize)
|
||||
{
|
||||
return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, 0, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4_compressHC_continue_generic ((LZ4HC_Data_Structure*)LZ4_streamHCPtr, source, dest, inputSize, maxOutputSize, limitedOutput);
|
||||
}
|
||||
|
||||
|
||||
/* dictionary saving */
|
||||
|
||||
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)
|
||||
{
|
||||
LZ4HC_Data_Structure* streamPtr = (LZ4HC_Data_Structure*)LZ4_streamHCPtr;
|
||||
int prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));
|
||||
if (dictSize > 64 KB) dictSize = 64 KB;
|
||||
if (dictSize < 4) dictSize = 0;
|
||||
if (dictSize > prefixSize) dictSize = prefixSize;
|
||||
memcpy(safeBuffer, streamPtr->end - dictSize, dictSize);
|
||||
{
|
||||
U32 endIndex = (U32)(streamPtr->end - streamPtr->base);
|
||||
streamPtr->end = (const BYTE*)safeBuffer + dictSize;
|
||||
streamPtr->base = streamPtr->end - endIndex;
|
||||
streamPtr->dictLimit = endIndex - dictSize;
|
||||
streamPtr->lowLimit = endIndex - dictSize;
|
||||
if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;
|
||||
}
|
||||
return dictSize;
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Deprecated Functions
|
||||
***********************************/
|
||||
int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }
|
||||
|
||||
int LZ4_resetStreamStateHC(void* state, const char* inputBuffer)
|
||||
{
|
||||
if ((((size_t)state) & (sizeof(void*)-1)) != 0) return 1; /* Error : pointer is not aligned for pointer (32 or 64 bits) */
|
||||
LZ4HC_init((LZ4HC_Data_Structure*)state, (const BYTE*)inputBuffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* LZ4_createHC (const char* inputBuffer)
|
||||
{
|
||||
void* hc4 = ALLOCATOR(1, sizeof(LZ4HC_Data_Structure));
|
||||
LZ4HC_init ((LZ4HC_Data_Structure*)hc4, (const BYTE*)inputBuffer);
|
||||
return hc4;
|
||||
}
|
||||
|
||||
int LZ4_freeHC (void* LZ4HC_Data)
|
||||
{
|
||||
FREEMEM(LZ4HC_Data);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
int LZ4_compressHC_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, 0, noLimit);
|
||||
}
|
||||
int LZ4_compressHC_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, 0, limitedOutput);
|
||||
}
|
||||
*/
|
||||
|
||||
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, 0, compressionLevel, noLimit);
|
||||
}
|
||||
|
||||
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel)
|
||||
{
|
||||
return LZ4HC_compress_generic (LZ4HC_Data, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput);
|
||||
}
|
||||
|
||||
char* LZ4_slideInputBufferHC(void* LZ4HC_Data)
|
||||
{
|
||||
LZ4HC_Data_Structure* hc4 = (LZ4HC_Data_Structure*)LZ4HC_Data;
|
||||
int dictSize = LZ4_saveDictHC((LZ4_streamHC_t*)LZ4HC_Data, (char*)(hc4->inputBuffer), 64 KB);
|
||||
return (char*)(hc4->inputBuffer + dictSize);
|
||||
}
|
||||
174
lib/lz4hc.h
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
LZ4 HC - High Compression Mode of LZ4
|
||||
Header File
|
||||
Copyright (C) 2011-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
int LZ4_compressHC (const char* source, char* dest, int inputSize);
|
||||
/*
|
||||
LZ4_compressHC :
|
||||
return : the number of bytes in compressed buffer dest
|
||||
or 0 if compression fails.
|
||||
note : destination buffer must be already allocated.
|
||||
To avoid any problem, size it to handle worst cases situations (input data not compressible)
|
||||
Worst case size evaluation is provided by function LZ4_compressBound() (see "lz4.h")
|
||||
*/
|
||||
|
||||
int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
/*
|
||||
LZ4_compress_limitedOutput() :
|
||||
Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
|
||||
If it cannot achieve it, compression will stop, and result of the function will be zero.
|
||||
This function never writes outside of provided output buffer.
|
||||
|
||||
inputSize : Max supported value is 1 GB
|
||||
maxOutputSize : is maximum allowed size into the destination buffer (which must be already allocated)
|
||||
return : the number of output bytes written in buffer 'dest'
|
||||
or 0 if compression fails.
|
||||
*/
|
||||
|
||||
|
||||
int LZ4_compressHC2 (const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
/*
|
||||
Same functions as above, but with programmable 'compressionLevel'.
|
||||
Recommended values are between 4 and 9, although any value between 0 and 16 will work.
|
||||
'compressionLevel'==0 means use default 'compressionLevel' value.
|
||||
Values above 16 behave the same as 16.
|
||||
Equivalent variants exist for all other compression functions below.
|
||||
*/
|
||||
|
||||
/* Note :
|
||||
Decompression functions are provided within LZ4 source code (see "lz4.h") (BSD license)
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
Using an external allocation
|
||||
**************************************/
|
||||
int LZ4_sizeofStateHC(void);
|
||||
int LZ4_compressHC_withStateHC (void* state, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
int LZ4_compressHC2_withStateHC (void* state, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
|
||||
/*
|
||||
These functions are provided should you prefer to allocate memory for compression tables with your own allocation methods.
|
||||
To know how much memory must be allocated for the compression tables, use :
|
||||
int LZ4_sizeofStateHC();
|
||||
|
||||
Note that tables must be aligned for pointer (32 or 64 bits), otherwise compression will fail (return code 0).
|
||||
|
||||
The allocated memory can be provided to the compression functions using 'void* state' parameter.
|
||||
LZ4_compress_withStateHC() and LZ4_compress_limitedOutput_withStateHC() are equivalent to previously described functions.
|
||||
They just use the externally allocated memory for state instead of allocating their own (on stack, or on heap).
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Experimental Streaming Functions
|
||||
**************************************/
|
||||
#define LZ4_STREAMHCSIZE_U64 32774
|
||||
#define LZ4_STREAMHCSIZE (LZ4_STREAMHCSIZE_U64 * sizeof(unsigned long long))
|
||||
typedef struct { unsigned long long table[LZ4_STREAMHCSIZE_U64]; } LZ4_streamHC_t;
|
||||
/*
|
||||
LZ4_streamHC_t
|
||||
This structure allows static allocation of LZ4 HC streaming state.
|
||||
State must then be initialized using LZ4_resetStreamHC() before first use.
|
||||
|
||||
Static allocation should only be used with statically linked library.
|
||||
If you want to use LZ4 as a DLL, please use construction functions below, which are more future-proof.
|
||||
*/
|
||||
|
||||
|
||||
LZ4_streamHC_t* LZ4_createStreamHC(void);
|
||||
int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr);
|
||||
/*
|
||||
These functions create and release memory for LZ4 HC streaming state.
|
||||
Newly created states are already initialized.
|
||||
Existing state space can be re-used anytime using LZ4_resetStreamHC().
|
||||
If you use LZ4 as a DLL, please use these functions instead of direct struct allocation,
|
||||
to avoid size mismatch between different versions.
|
||||
*/
|
||||
|
||||
void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);
|
||||
int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, const char* dictionary, int dictSize);
|
||||
|
||||
int LZ4_compressHC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);
|
||||
int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);
|
||||
|
||||
int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int maxDictSize);
|
||||
|
||||
/*
|
||||
These functions compress data in successive blocks of any size, using previous blocks as dictionary.
|
||||
One key assumption is that each previous block will remain read-accessible while compressing next block.
|
||||
|
||||
Before starting compression, state must be properly initialized, using LZ4_resetStreamHC().
|
||||
A first "fictional block" can then be designated as initial dictionary, using LZ4_loadDictHC() (Optional).
|
||||
|
||||
Then, use LZ4_compressHC_continue() or LZ4_compressHC_limitedOutput_continue() to compress each successive block.
|
||||
They work like usual LZ4_compressHC() or LZ4_compressHC_limitedOutput(), but use previous memory blocks to improve compression.
|
||||
Previous memory blocks (including initial dictionary when present) must remain accessible and unmodified during compression.
|
||||
|
||||
If, for any reason, previous data block can't be preserved in memory during next compression block,
|
||||
you must save it to a safer memory space,
|
||||
using LZ4_saveDictHC().
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
* Deprecated Streaming Functions
|
||||
* ************************************/
|
||||
/* Note : these streaming functions follows the older model, and should no longer be used */
|
||||
void* LZ4_createHC (const char* inputBuffer);
|
||||
char* LZ4_slideInputBufferHC (void* LZ4HC_Data);
|
||||
int LZ4_freeHC (void* LZ4HC_Data);
|
||||
|
||||
int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);
|
||||
int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);
|
||||
|
||||
int LZ4_sizeofStreamStateHC(void);
|
||||
int LZ4_resetStreamStateHC(void* state, const char* inputBuffer);
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
935
lib/xxhash.c
Normal file
@@ -0,0 +1,935 @@
|
||||
/*
|
||||
xxHash - Fast Hash algorithm
|
||||
Copyright (C) 2012-2015, Yann Collet
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : http://code.google.com/p/xxhash/
|
||||
- xxHash source mirror : https://github.com/Cyan4973/xxHash
|
||||
- public discussion board : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
|
||||
/**************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/* Unaligned memory access is automatically enabled for "common" CPU, such as x86.
|
||||
* For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.
|
||||
* If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.
|
||||
* You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).
|
||||
*/
|
||||
#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
|
||||
# define XXH_USE_UNALIGNED_ACCESS 1
|
||||
#endif
|
||||
|
||||
/* XXH_ACCEPT_NULL_INPUT_POINTER :
|
||||
* If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
|
||||
* When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
|
||||
* By default, this option is disabled. To enable it, uncomment below define :
|
||||
*/
|
||||
/* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
|
||||
|
||||
/* XXH_FORCE_NATIVE_FORMAT :
|
||||
* By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
|
||||
* Results are therefore identical for little-endian and big-endian CPU.
|
||||
* This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
|
||||
* Should endian-independance be of no importance for your application, you may set the #define below to 1.
|
||||
* It will improve speed for Big-endian CPU.
|
||||
* This option has no impact on Little_Endian CPU.
|
||||
*/
|
||||
#define XXH_FORCE_NATIVE_FORMAT 0
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Specific Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# define FORCE_INLINE static __forceinline
|
||||
#else
|
||||
# if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# ifdef __GNUC__
|
||||
# define FORCE_INLINE static inline __attribute__((always_inline))
|
||||
# else
|
||||
# define FORCE_INLINE static inline
|
||||
# endif
|
||||
# else
|
||||
# define FORCE_INLINE static
|
||||
# endif /* __STDC_VERSION__ */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
#include "xxhash.h"
|
||||
/* Modify the local functions below should you wish to use some other memory routines */
|
||||
/* for malloc(), free() */
|
||||
#include <stdlib.h>
|
||||
static void* XXH_malloc(size_t s) { return malloc(s); }
|
||||
static void XXH_free (void* p) { free(p); }
|
||||
/* for memcpy() */
|
||||
#include <string.h>
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size)
|
||||
{
|
||||
return memcpy(dest,src,size);
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
# define _PACKED __attribute__ ((packed))
|
||||
#else
|
||||
# define _PACKED
|
||||
#endif
|
||||
|
||||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
|
||||
# ifdef __IBMC__
|
||||
# pragma pack(1)
|
||||
# else
|
||||
# pragma pack(push, 1)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct _U32_S
|
||||
{
|
||||
U32 v;
|
||||
} _PACKED U32_S;
|
||||
typedef struct _U64_S
|
||||
{
|
||||
U64 v;
|
||||
} _PACKED U64_S;
|
||||
|
||||
#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
|
||||
# pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#define A32(x) (((U32_S *)(x))->v)
|
||||
#define A64(x) (((U64_S *)(x))->v)
|
||||
|
||||
|
||||
/*****************************************
|
||||
* Compiler-specific Functions and Macros
|
||||
******************************************/
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
|
||||
/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
|
||||
#if defined(_MSC_VER)
|
||||
# define XXH_rotl32(x,r) _rotl(x,r)
|
||||
# define XXH_rotl64(x,r) _rotl64(x,r)
|
||||
#else
|
||||
# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
# define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) /* Visual Studio */
|
||||
# define XXH_swap32 _byteswap_ulong
|
||||
# define XXH_swap64 _byteswap_uint64
|
||||
#elif GCC_VERSION >= 403
|
||||
# define XXH_swap32 __builtin_bswap32
|
||||
# define XXH_swap64 __builtin_bswap64
|
||||
#else
|
||||
static U32 XXH_swap32 (U32 x)
|
||||
{
|
||||
return ((x << 24) & 0xff000000 ) |
|
||||
((x << 8) & 0x00ff0000 ) |
|
||||
((x >> 8) & 0x0000ff00 ) |
|
||||
((x >> 24) & 0x000000ff );
|
||||
}
|
||||
static U64 XXH_swap64 (U64 x)
|
||||
{
|
||||
return ((x << 56) & 0xff00000000000000ULL) |
|
||||
((x << 40) & 0x00ff000000000000ULL) |
|
||||
((x << 24) & 0x0000ff0000000000ULL) |
|
||||
((x << 8) & 0x000000ff00000000ULL) |
|
||||
((x >> 8) & 0x00000000ff000000ULL) |
|
||||
((x >> 24) & 0x0000000000ff0000ULL) |
|
||||
((x >> 40) & 0x000000000000ff00ULL) |
|
||||
((x >> 56) & 0x00000000000000ffULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
#define PRIME32_1 2654435761U
|
||||
#define PRIME32_2 2246822519U
|
||||
#define PRIME32_3 3266489917U
|
||||
#define PRIME32_4 668265263U
|
||||
#define PRIME32_5 374761393U
|
||||
|
||||
#define PRIME64_1 11400714785074694791ULL
|
||||
#define PRIME64_2 14029467366897019727ULL
|
||||
#define PRIME64_3 1609587929392839161ULL
|
||||
#define PRIME64_4 9650029242287828579ULL
|
||||
#define PRIME64_5 2870177450012600261ULL
|
||||
|
||||
|
||||
/***************************************
|
||||
* Architecture Macros
|
||||
****************************************/
|
||||
typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
|
||||
#ifndef XXH_CPU_LITTLE_ENDIAN /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example using a compiler switch */
|
||||
static const int one = 1;
|
||||
# define XXH_CPU_LITTLE_ENDIAN (*(char*)(&one))
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */
|
||||
|
||||
|
||||
/****************************
|
||||
* Memory reads
|
||||
*****************************/
|
||||
typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(U32*)ptr : XXH_swap32(*(U32*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE32_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
if (align==XXH_unaligned)
|
||||
return endian==XXH_littleEndian ? A64(ptr) : XXH_swap64(A64(ptr));
|
||||
else
|
||||
return endian==XXH_littleEndian ? *(U64*)ptr : XXH_swap64(*(U64*)ptr);
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)
|
||||
{
|
||||
return XXH_readLE64_align(ptr, endian, XXH_unaligned);
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
* Simple Hash Functions
|
||||
*****************************/
|
||||
FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U32 h32;
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL)
|
||||
{
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)16;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=16)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
U32 v2 = seed + PRIME32_2;
|
||||
U32 v3 = seed + 0;
|
||||
U32 v4 = seed - PRIME32_1;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_get32bits(p) * PRIME32_2;
|
||||
v1 = XXH_rotl32(v1, 13);
|
||||
v1 *= PRIME32_1;
|
||||
p+=4;
|
||||
v2 += XXH_get32bits(p) * PRIME32_2;
|
||||
v2 = XXH_rotl32(v2, 13);
|
||||
v2 *= PRIME32_1;
|
||||
p+=4;
|
||||
v3 += XXH_get32bits(p) * PRIME32_2;
|
||||
v3 = XXH_rotl32(v3, 13);
|
||||
v3 *= PRIME32_1;
|
||||
p+=4;
|
||||
v4 += XXH_get32bits(p) * PRIME32_2;
|
||||
v4 = XXH_rotl32(v4, 13);
|
||||
v4 *= PRIME32_1;
|
||||
p+=4;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
h32 = seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) len;
|
||||
|
||||
while (p+4<=bEnd)
|
||||
{
|
||||
h32 += XXH_get32bits(p) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
unsigned int XXH32 (const void* input, size_t len, unsigned seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_state_t state;
|
||||
XXH32_reset(&state, seed);
|
||||
XXH32_update(&state, input, len);
|
||||
return XXH32_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
# if !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
if ((((size_t)input) & 3) == 0) /* Input is aligned, let's leverage the speed advantage */
|
||||
{
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
}
|
||||
# endif
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
|
||||
{
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* bEnd = p + len;
|
||||
U64 h64;
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (p==NULL)
|
||||
{
|
||||
len=0;
|
||||
bEnd=p=(const BYTE*)(size_t)32;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len>=32)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
U64 v2 = seed + PRIME64_2;
|
||||
U64 v3 = seed + 0;
|
||||
U64 v4 = seed - PRIME64_1;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
v2 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
v3 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
v4 += XXH_get64bits(p) * PRIME64_2;
|
||||
p+=8;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
|
||||
v1 *= PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
h64 ^= v1;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v2 *= PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
h64 ^= v2;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v3 *= PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
h64 ^= v3;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
|
||||
v4 *= PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
h64 ^= v4;
|
||||
h64 = h64 * PRIME64_1 + PRIME64_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
h64 = seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) len;
|
||||
|
||||
while (p+8<=bEnd)
|
||||
{
|
||||
U64 k1 = XXH_get64bits(p);
|
||||
k1 *= PRIME64_2;
|
||||
k1 = XXH_rotl64(k1,31);
|
||||
k1 *= PRIME64_1;
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd)
|
||||
{
|
||||
h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
|
||||
{
|
||||
#if 0
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_state_t state;
|
||||
XXH64_reset(&state, seed);
|
||||
XXH64_update(&state, input, len);
|
||||
return XXH64_digest(&state);
|
||||
#else
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
# if !defined(XXH_USE_UNALIGNED_ACCESS)
|
||||
if ((((size_t)input) & 7)==0) /* Input is aligned, let's leverage the speed advantage */
|
||||
{
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
|
||||
}
|
||||
# endif
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
|
||||
else
|
||||
return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
* Advanced Hash Functions
|
||||
****************************************************/
|
||||
|
||||
/*** Allocation ***/
|
||||
typedef struct
|
||||
{
|
||||
U64 total_len;
|
||||
U32 seed;
|
||||
U32 v1;
|
||||
U32 v2;
|
||||
U32 v3;
|
||||
U32 v4;
|
||||
U32 mem32[4]; /* defined as U32 for alignment */
|
||||
U32 memsize;
|
||||
} XXH_istate32_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
U64 total_len;
|
||||
U64 seed;
|
||||
U64 v1;
|
||||
U64 v2;
|
||||
U64 v3;
|
||||
U64 v4;
|
||||
U64 mem64[4]; /* defined as U64 for alignment */
|
||||
U32 memsize;
|
||||
} XXH_istate64_t;
|
||||
|
||||
|
||||
XXH32_state_t* XXH32_createState(void)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_state_t) >= sizeof(XXH_istate32_t)); /* A compilation error here means XXH32_state_t is not large enough */
|
||||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
|
||||
}
|
||||
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH64_state_t* XXH64_createState(void)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_state_t) >= sizeof(XXH_istate64_t)); /* A compilation error here means XXH64_state_t is not large enough */
|
||||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
|
||||
}
|
||||
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
/*** Hash feed ***/
|
||||
|
||||
XXH_errorcode XXH32_reset(XXH32_state_t* state_in, U32 seed)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t*) state_in;
|
||||
state->seed = seed;
|
||||
state->v1 = seed + PRIME32_1 + PRIME32_2;
|
||||
state->v2 = seed + PRIME32_2;
|
||||
state->v3 = seed + 0;
|
||||
state->v4 = seed - PRIME32_1;
|
||||
state->total_len = 0;
|
||||
state->memsize = 0;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH64_reset(XXH64_state_t* state_in, unsigned long long seed)
|
||||
{
|
||||
XXH_istate64_t* state = (XXH_istate64_t*) state_in;
|
||||
state->seed = seed;
|
||||
state->v1 = seed + PRIME64_1 + PRIME64_2;
|
||||
state->v2 = seed + PRIME64_2;
|
||||
state->v3 = seed + 0;
|
||||
state->v4 = seed - PRIME64_1;
|
||||
state->total_len = 0;
|
||||
state->memsize = 0;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH32_update_endian (XXH32_state_t* state_in, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t *) state_in;
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 16) /* fill in tmp buffer */
|
||||
{
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) /* some data left from previous update */
|
||||
{
|
||||
XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);
|
||||
{
|
||||
const U32* p32 = state->mem32;
|
||||
state->v1 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v1 = XXH_rotl32(state->v1, 13);
|
||||
state->v1 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v2 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v2 = XXH_rotl32(state->v2, 13);
|
||||
state->v2 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v3 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v3 = XXH_rotl32(state->v3, 13);
|
||||
state->v3 *= PRIME32_1;
|
||||
p32++;
|
||||
state->v4 += XXH_readLE32(p32, endian) * PRIME32_2;
|
||||
state->v4 = XXH_rotl32(state->v4, 13);
|
||||
state->v4 *= PRIME32_1;
|
||||
p32++;
|
||||
}
|
||||
p += 16-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p <= bEnd-16)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 16;
|
||||
U32 v1 = state->v1;
|
||||
U32 v2 = state->v2;
|
||||
U32 v3 = state->v3;
|
||||
U32 v4 = state->v4;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v1 = XXH_rotl32(v1, 13);
|
||||
v1 *= PRIME32_1;
|
||||
p+=4;
|
||||
v2 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v2 = XXH_rotl32(v2, 13);
|
||||
v2 *= PRIME32_1;
|
||||
p+=4;
|
||||
v3 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v3 = XXH_rotl32(v3, 13);
|
||||
v3 *= PRIME32_1;
|
||||
p+=4;
|
||||
v4 += XXH_readLE32(p, endian) * PRIME32_2;
|
||||
v4 = XXH_rotl32(v4, 13);
|
||||
v4 *= PRIME32_1;
|
||||
p+=4;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd)
|
||||
{
|
||||
XXH_memcpy(state->mem32, p, bEnd-p);
|
||||
state->memsize = (int)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U32 XXH32_digest_endian (const XXH32_state_t* state_in, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate32_t* state = (XXH_istate32_t*) state_in;
|
||||
const BYTE * p = (const BYTE*)state->mem32;
|
||||
BYTE* bEnd = (BYTE*)(state->mem32) + state->memsize;
|
||||
U32 h32;
|
||||
|
||||
if (state->total_len >= 16)
|
||||
{
|
||||
h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
|
||||
}
|
||||
else
|
||||
{
|
||||
h32 = state->seed + PRIME32_5;
|
||||
}
|
||||
|
||||
h32 += (U32) state->total_len;
|
||||
|
||||
while (p+4<=bEnd)
|
||||
{
|
||||
h32 += XXH_readLE32(p, endian) * PRIME32_3;
|
||||
h32 = XXH_rotl32(h32, 17) * PRIME32_4;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h32 += (*p) * PRIME32_5;
|
||||
h32 = XXH_rotl32(h32, 11) * PRIME32_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
|
||||
return h32;
|
||||
}
|
||||
|
||||
|
||||
U32 XXH32_digest (const XXH32_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH32_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH32_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
FORCE_INLINE XXH_errorcode XXH64_update_endian (XXH64_state_t* state_in, const void* input, size_t len, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate64_t * state = (XXH_istate64_t *) state_in;
|
||||
const BYTE* p = (const BYTE*)input;
|
||||
const BYTE* const bEnd = p + len;
|
||||
|
||||
#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
|
||||
if (input==NULL) return XXH_ERROR;
|
||||
#endif
|
||||
|
||||
state->total_len += len;
|
||||
|
||||
if (state->memsize + len < 32) /* fill in tmp buffer */
|
||||
{
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);
|
||||
state->memsize += (U32)len;
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
if (state->memsize) /* some data left from previous update */
|
||||
{
|
||||
XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);
|
||||
{
|
||||
const U64* p64 = state->mem64;
|
||||
state->v1 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v1 = XXH_rotl64(state->v1, 31);
|
||||
state->v1 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v2 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v2 = XXH_rotl64(state->v2, 31);
|
||||
state->v2 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v3 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v3 = XXH_rotl64(state->v3, 31);
|
||||
state->v3 *= PRIME64_1;
|
||||
p64++;
|
||||
state->v4 += XXH_readLE64(p64, endian) * PRIME64_2;
|
||||
state->v4 = XXH_rotl64(state->v4, 31);
|
||||
state->v4 *= PRIME64_1;
|
||||
p64++;
|
||||
}
|
||||
p += 32-state->memsize;
|
||||
state->memsize = 0;
|
||||
}
|
||||
|
||||
if (p+32 <= bEnd)
|
||||
{
|
||||
const BYTE* const limit = bEnd - 32;
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
do
|
||||
{
|
||||
v1 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
p+=8;
|
||||
v2 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
p+=8;
|
||||
v3 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
p+=8;
|
||||
v4 += XXH_readLE64(p, endian) * PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
p+=8;
|
||||
}
|
||||
while (p<=limit);
|
||||
|
||||
state->v1 = v1;
|
||||
state->v2 = v2;
|
||||
state->v3 = v3;
|
||||
state->v4 = v4;
|
||||
}
|
||||
|
||||
if (p < bEnd)
|
||||
{
|
||||
XXH_memcpy(state->mem64, p, bEnd-p);
|
||||
state->memsize = (int)(bEnd-p);
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_update_endian(state_in, input, len, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_update_endian(state_in, input, len, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
|
||||
FORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state_in, XXH_endianess endian)
|
||||
{
|
||||
XXH_istate64_t * state = (XXH_istate64_t *) state_in;
|
||||
const BYTE * p = (const BYTE*)state->mem64;
|
||||
BYTE* bEnd = (BYTE*)state->mem64 + state->memsize;
|
||||
U64 h64;
|
||||
|
||||
if (state->total_len >= 32)
|
||||
{
|
||||
U64 v1 = state->v1;
|
||||
U64 v2 = state->v2;
|
||||
U64 v3 = state->v3;
|
||||
U64 v4 = state->v4;
|
||||
|
||||
h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
|
||||
|
||||
v1 *= PRIME64_2;
|
||||
v1 = XXH_rotl64(v1, 31);
|
||||
v1 *= PRIME64_1;
|
||||
h64 ^= v1;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v2 *= PRIME64_2;
|
||||
v2 = XXH_rotl64(v2, 31);
|
||||
v2 *= PRIME64_1;
|
||||
h64 ^= v2;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v3 *= PRIME64_2;
|
||||
v3 = XXH_rotl64(v3, 31);
|
||||
v3 *= PRIME64_1;
|
||||
h64 ^= v3;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
|
||||
v4 *= PRIME64_2;
|
||||
v4 = XXH_rotl64(v4, 31);
|
||||
v4 *= PRIME64_1;
|
||||
h64 ^= v4;
|
||||
h64 = h64*PRIME64_1 + PRIME64_4;
|
||||
}
|
||||
else
|
||||
{
|
||||
h64 = state->seed + PRIME64_5;
|
||||
}
|
||||
|
||||
h64 += (U64) state->total_len;
|
||||
|
||||
while (p+8<=bEnd)
|
||||
{
|
||||
U64 k1 = XXH_readLE64(p, endian);
|
||||
k1 *= PRIME64_2;
|
||||
k1 = XXH_rotl64(k1,31);
|
||||
k1 *= PRIME64_1;
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
|
||||
p+=8;
|
||||
}
|
||||
|
||||
if (p+4<=bEnd)
|
||||
{
|
||||
h64 ^= (U64)(XXH_readLE32(p, endian)) * PRIME64_1;
|
||||
h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
|
||||
p+=4;
|
||||
}
|
||||
|
||||
while (p<bEnd)
|
||||
{
|
||||
h64 ^= (*p) * PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * PRIME64_1;
|
||||
p++;
|
||||
}
|
||||
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
|
||||
return h64;
|
||||
}
|
||||
|
||||
|
||||
unsigned long long XXH64_digest (const XXH64_state_t* state_in)
|
||||
{
|
||||
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
|
||||
|
||||
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
|
||||
return XXH64_digest_endian(state_in, XXH_littleEndian);
|
||||
else
|
||||
return XXH64_digest_endian(state_in, XXH_bigEndian);
|
||||
}
|
||||
|
||||
|
||||
156
lib/xxhash.h
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
xxHash - Extremely Fast Hash algorithm
|
||||
Header File
|
||||
Copyright (C) 2012-2014, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash source repository : http://code.google.com/p/xxhash/
|
||||
*/
|
||||
|
||||
/* Notice extracted from xxHash homepage :
|
||||
|
||||
xxHash is an extremely fast Hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MumurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************
|
||||
Includes
|
||||
*****************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
|
||||
/*****************************
|
||||
Type
|
||||
*****************************/
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
Simple Hash Functions
|
||||
*****************************/
|
||||
|
||||
unsigned int XXH32 (const void* input, size_t length, unsigned seed);
|
||||
unsigned long long XXH64 (const void* input, size_t length, unsigned long long seed);
|
||||
|
||||
/*
|
||||
XXH32() :
|
||||
Calculate the 32-bits hash of sequence "length" bytes stored at memory address "input".
|
||||
The memory between input & input+length must be valid (allocated and read-accessible).
|
||||
"seed" can be used to alter the result predictably.
|
||||
This function successfully passes all SMHasher tests.
|
||||
Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s
|
||||
XXH64() :
|
||||
Calculate the 64-bits hash of sequence of length "len" stored at memory address "input".
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*****************************
|
||||
Advanced Hash Functions
|
||||
*****************************/
|
||||
typedef struct { long long ll[ 6]; } XXH32_state_t;
|
||||
typedef struct { long long ll[11]; } XXH64_state_t;
|
||||
|
||||
/*
|
||||
These structures allow static allocation of XXH states.
|
||||
States must then be initialized using XXHnn_reset() before first use.
|
||||
|
||||
If you prefer dynamic allocation, please refer to functions below.
|
||||
*/
|
||||
|
||||
XXH32_state_t* XXH32_createState(void);
|
||||
XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
|
||||
XXH64_state_t* XXH64_createState(void);
|
||||
XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions create and release memory for XXH state.
|
||||
States must then be initialized using XXHnn_reset() before first use.
|
||||
*/
|
||||
|
||||
|
||||
XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, unsigned seed);
|
||||
XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
unsigned int XXH32_digest (const XXH32_state_t* statePtr);
|
||||
|
||||
XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, unsigned long long seed);
|
||||
XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
unsigned long long XXH64_digest (const XXH64_state_t* statePtr);
|
||||
|
||||
/*
|
||||
These functions calculate the xxHash of an input provided in multiple smaller packets,
|
||||
as opposed to an input provided as a single block.
|
||||
|
||||
XXH state space must first be allocated, using either static or dynamic method provided above.
|
||||
|
||||
Start a new hash by initializing state with a seed, using XXHnn_reset().
|
||||
|
||||
Then, feed the hash state by calling XXHnn_update() as many times as necessary.
|
||||
Obviously, input must be valid, meaning allocated and read accessible.
|
||||
The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.
|
||||
|
||||
Finally, you can produce a hash anytime, by using XXHnn_digest().
|
||||
This function returns the final nn-bits hash.
|
||||
You can nonetheless continue feeding the hash state with more input,
|
||||
and therefore get some new hashes, by calling again XXHnn_digest().
|
||||
|
||||
When you are done, don't forget to free XXH state space, using typically XXHnn_freeState().
|
||||
*/
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
120
lz4_block_format.txt
Normal file
@@ -0,0 +1,120 @@
|
||||
LZ4 Format Description
|
||||
Last revised: 2012-02-27
|
||||
Author : Y. Collet
|
||||
|
||||
|
||||
|
||||
This small specification intents to provide enough information
|
||||
to anyone willing to produce LZ4-compatible compressed data blocks
|
||||
using any programming language.
|
||||
|
||||
LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding.
|
||||
The most important design principle behind LZ4 is simplicity.
|
||||
It helps to create an easy to read and maintain source code.
|
||||
It also helps later on for optimisations, compactness, and speed.
|
||||
There is no entropy encoder backend nor framing layer.
|
||||
The latter is assumed to be handled by other parts of the system.
|
||||
|
||||
This document only describes the format,
|
||||
not how the LZ4 compressor nor decompressor actually work.
|
||||
The correctness of the decompressor should not depend
|
||||
on implementation details of the compressor, and vice versa.
|
||||
|
||||
|
||||
|
||||
-- Compressed block format --
|
||||
|
||||
An LZ4 compressed block is composed of sequences.
|
||||
Schematically, a sequence is a suite of literals, followed by a match copy.
|
||||
|
||||
Each sequence starts with a token.
|
||||
The token is a one byte value, separated into two 4-bits fields.
|
||||
Therefore each field ranges from 0 to 15.
|
||||
|
||||
|
||||
The first field uses the 4 high-bits of the token.
|
||||
It provides the length of literals to follow.
|
||||
(Note : a literal is a not-compressed byte).
|
||||
If the field value is 0, then there is no literal.
|
||||
If it is 15, then we need to add some more bytes to indicate the full length.
|
||||
Each additionnal byte then represent a value from 0 to 255,
|
||||
which is added to the previous value to produce a total length.
|
||||
When the byte value is 255, another byte is output.
|
||||
There can be any number of bytes following the token. There is no "size limit".
|
||||
(Sidenote this is why a not-compressible input block is expanded by 0.4%).
|
||||
|
||||
Example 1 : A length of 48 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 33 : (=48-15) remaining length to reach 48
|
||||
|
||||
Example 2 : A length of 280 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 255 : following byte is maxed, since 280-15 >= 255
|
||||
- 10 : (=280 - 15 - 255) ) remaining length to reach 280
|
||||
|
||||
Example 3 : A length of 15 will be represented as :
|
||||
- 15 : value for the 4-bits High field
|
||||
- 0 : (=15-15) yes, the zero must be output
|
||||
|
||||
Following the token and optional length bytes, are the literals themselves.
|
||||
They are exactly as numerous as previously decoded (length of literals).
|
||||
It's possible that there are zero literal.
|
||||
|
||||
|
||||
Following the literals is the match copy operation.
|
||||
|
||||
It starts by the offset.
|
||||
This is a 2 bytes value, in little endian format.
|
||||
|
||||
The offset represents the position of the match to be copied from.
|
||||
1 means "current position - 1 byte".
|
||||
The maximum offset value is 65535, 65536 cannot be coded.
|
||||
Note that 0 is an invalid value, not used.
|
||||
|
||||
Then we need to extract the match length.
|
||||
For this, we use the second token field, the low 4-bits.
|
||||
Value, obviously, ranges from 0 to 15.
|
||||
However here, 0 means that the copy operation will be minimal.
|
||||
The minimum length of a match, called minmatch, is 4.
|
||||
As a consequence, a 0 value means 4 bytes, and a value of 15 means 19+ bytes.
|
||||
Similar to literal length, on reaching the highest possible value (15),
|
||||
we output additional bytes, one at a time, with values ranging from 0 to 255.
|
||||
They are added to total to provide the final match length.
|
||||
A 255 value means there is another byte to read and add.
|
||||
There is no limit to the number of optional bytes that can be output this way.
|
||||
(This points towards a maximum achievable compression ratio of ~250).
|
||||
|
||||
With the offset and the matchlength,
|
||||
the decoder can now proceed to copy the data from the already decoded buffer.
|
||||
On decoding the matchlength, we reach the end of the compressed sequence,
|
||||
and therefore start another one.
|
||||
|
||||
|
||||
-- Parsing restrictions --
|
||||
|
||||
There are specific parsing rules to respect in order to remain compatible
|
||||
with assumptions made by the decoder :
|
||||
1) The last 5 bytes are always literals
|
||||
2) The last match must start at least 12 bytes before end of block
|
||||
Consequently, a block with less than 13 bytes cannot be compressed.
|
||||
These rules are in place to ensure that the decoder
|
||||
will never read beyond the input buffer, nor write beyond the output buffer.
|
||||
|
||||
Note that the last sequence is also incomplete,
|
||||
and stops right after literals.
|
||||
|
||||
|
||||
-- Additional notes --
|
||||
|
||||
There is no assumption nor limits to the way the compressor
|
||||
searches and selects matches within the source data block.
|
||||
It could be a fast scan, a multi-probe, a full search using BST,
|
||||
standard hash chains or MMC, well whatever.
|
||||
|
||||
Advanced parsing strategies can also be implemented, such as lazy match,
|
||||
or full optimal parsing.
|
||||
|
||||
All these trade-off offer distinctive speed/memory/compression advantages.
|
||||
Whatever the method used by the compressor, its result will be decodable
|
||||
by any LZ4 decoder if it follows the format specification described above.
|
||||
|
||||
339
programs/COPYING
Normal file
@@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
206
programs/Makefile
Normal file
@@ -0,0 +1,206 @@
|
||||
# ##########################################################################
|
||||
# LZ4 programs - Makefile
|
||||
# Copyright (C) Yann Collet 2011-2015
|
||||
#
|
||||
# GPL v2 License
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# You can contact the author at :
|
||||
# - LZ4 source repository : http://code.google.com/p/lz4/
|
||||
# - LZ4 forum froup : https://groups.google.com/forum/#!forum/lz4c
|
||||
# ##########################################################################
|
||||
# lz4 : Command Line Utility, supporting gzip-like arguments
|
||||
# lz4c : CLU, supporting also legacy lz4demo arguments
|
||||
# lz4c32: Same as lz4c, but forced to compile in 32-bits mode
|
||||
# fuzzer : Test tool, to check lz4 integrity on target platform
|
||||
# fuzzer32: Same as fuzzer, but forced to compile in 32-bits mode
|
||||
# fullbench : Precisely measure speed for each LZ4 function variant
|
||||
# fullbench32: Same as fullbench, but forced to compile in 32-bits mode
|
||||
# ##########################################################################
|
||||
|
||||
RELEASE?= r126
|
||||
|
||||
DESTDIR?=
|
||||
PREFIX ?= /usr
|
||||
CFLAGS ?= -O3
|
||||
CFLAGS += -std=c99 -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes -pedantic -DLZ4_VERSION=\"$(RELEASE)\"
|
||||
FLAGS = -I../lib $(CPPFLAGS) $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
BINDIR=$(PREFIX)/bin
|
||||
MANDIR=$(PREFIX)/share/man/man1
|
||||
LZ4DIR=../lib
|
||||
|
||||
TEST_FILES = COPYING
|
||||
TEST_TARGETS=test-native
|
||||
|
||||
|
||||
# Define *.exe as extension for Windows systems
|
||||
ifneq (,$(filter Windows%,$(OS)))
|
||||
EXT =.exe
|
||||
VOID = nul
|
||||
else
|
||||
EXT =
|
||||
VOID = /dev/null
|
||||
endif
|
||||
|
||||
|
||||
# Select test target for Travis CI's Build Matrix
|
||||
TRAVIS_TARGET=$(LZ4_TRAVIS_CI_ENV)
|
||||
|
||||
|
||||
default: lz4 lz4c
|
||||
|
||||
all: lz4 lz4c lz4c32 fullbench fullbench32 fuzzer fuzzer32 frametest frametest32 datagen
|
||||
|
||||
lz4: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
lz4c : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) $(FLAGS) -DENABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
|
||||
|
||||
lz4c32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c bench.c lz4io.c lz4cli.c
|
||||
$(CC) -m32 $(FLAGS) -DENABLE_LZ4C_LEGACY_OPTIONS $^ -o $@$(EXT)
|
||||
|
||||
fullbench : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c fullbench.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fullbench32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/lz4frame.c $(LZ4DIR)/xxhash.c fullbench.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fuzzer : $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c fuzzer.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
fuzzer32: $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c fuzzer.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
frametest: $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c frametest.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
frametest32: $(LZ4DIR)/lz4frame.c $(LZ4DIR)/lz4.c $(LZ4DIR)/lz4hc.c $(LZ4DIR)/xxhash.c frametest.c
|
||||
$(CC) -m32 $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
datagen : datagen.c
|
||||
$(CC) $(FLAGS) $^ -o $@$(EXT)
|
||||
|
||||
|
||||
clean:
|
||||
@rm -f core *.o *.test \
|
||||
lz4$(EXT) lz4c$(EXT) lz4c32$(EXT) \
|
||||
fullbench$(EXT) fullbench32$(EXT) \
|
||||
fuzzer$(EXT) fuzzer32$(EXT) \
|
||||
frametest$(EXT) frametest32$(EXT) \
|
||||
datagen$(EXT)
|
||||
@echo Cleaning completed
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
#make install is validated only for Linux, OSX, kFreeBSD and Hurd targets
|
||||
ifneq (,$(filter $(shell uname),Linux Darwin GNU/kFreeBSD GNU))
|
||||
|
||||
install: lz4 lz4c
|
||||
@echo Installing binaries
|
||||
@install -d -m 755 $(DESTDIR)$(BINDIR)/ $(DESTDIR)$(MANDIR)/
|
||||
@install -m 755 lz4$(EXT) $(DESTDIR)$(BINDIR)/lz4$(EXT)
|
||||
@ln -sf lz4$(EXT) $(DESTDIR)$(BINDIR)/lz4cat
|
||||
@install -m 755 lz4c$(EXT) $(DESTDIR)$(BINDIR)/lz4c$(EXT)
|
||||
@echo Installing man pages
|
||||
@install -m 644 lz4.1 $(DESTDIR)$(MANDIR)/lz4.1
|
||||
@install -m 644 lz4c.1 $(DESTDIR)$(MANDIR)/lz4c.1
|
||||
@install -m 644 lz4cat.1 $(DESTDIR)$(MANDIR)/lz4cat.1
|
||||
@echo lz4 installation completed
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(BINDIR)/lz4cat
|
||||
[ -x $(DESTDIR)$(BINDIR)/lz4$(EXT) ] && rm -f $(DESTDIR)$(BINDIR)/lz4$(EXT)
|
||||
[ -x $(DESTDIR)$(BINDIR)/lz4c$(EXT) ] && rm -f $(DESTDIR)$(BINDIR)/lz4c$(EXT)
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4.1
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4c.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4c.1
|
||||
[ -f $(DESTDIR)$(MANDIR)/lz4cat.1 ] && rm -f $(DESTDIR)$(MANDIR)/lz4cat.1
|
||||
@echo lz4 programs successfully uninstalled
|
||||
|
||||
test: test-lz4 test-lz4c test-frametest test-fullbench test-fuzzer test-mem
|
||||
|
||||
test32: test-lz4c32 test-frametest32 test-fullbench32 test-fuzzer32 test-mem32
|
||||
|
||||
test-all: test test32
|
||||
|
||||
test-travis: $(TRAVIS_TARGET)
|
||||
|
||||
test-lz4: lz4 datagen
|
||||
./datagen -g16KB | ./lz4 -9 | ./lz4 -vdq > $(VOID)
|
||||
./datagen | ./lz4 | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6M -p100 | ./lz4 -9BD | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4 -vqB4D | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6GB | ./lz4 -vqB5D | ./lz4 -vdq > $(VOID)
|
||||
# test frame concatenation with null-length frame
|
||||
@echo -n > empty.test
|
||||
@echo hi > nonempty.test
|
||||
cat nonempty.test empty.test nonempty.test > orig.test
|
||||
@./lz4 -zq empty.test > empty.lz4.test
|
||||
@./lz4 -zq nonempty.test > nonempty.lz4.test
|
||||
cat nonempty.lz4.test empty.lz4.test nonempty.lz4.test > concat.lz4.test
|
||||
./lz4 -d concat.lz4.test > result.test
|
||||
sdiff orig.test result.test
|
||||
@rm *.test
|
||||
@echo frame concatenation test completed
|
||||
# test frame concatenation with null-length frame
|
||||
|
||||
|
||||
test-lz4c: lz4c datagen
|
||||
./datagen -g256MB | ./lz4c -l -v | ./lz4c -vdq > $(VOID)
|
||||
|
||||
test-lz4c32: lz4 lz4c32 lz4 datagen
|
||||
./datagen -g16KB | ./lz4c32 -9 | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen -g16KB | ./lz4c32 -9 | ./lz4 -vdq > $(VOID)
|
||||
./datagen | ./lz4c32 | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen | ./lz4c32 | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4c32 -vqB4D | ./lz4c32 -vdq > $(VOID)
|
||||
./datagen -g256MB | ./lz4c32 -vqB4D | ./lz4 -vdq > $(VOID)
|
||||
./datagen -g6GB | ./lz4c32 -vqB5D | ./lz4c32 -vdq > $(VOID)
|
||||
|
||||
test-fullbench: fullbench
|
||||
./fullbench --no-prompt $(TEST_FILES)
|
||||
|
||||
test-fullbench32: fullbench32
|
||||
./fullbench32 --no-prompt $(TEST_FILES)
|
||||
|
||||
test-fuzzer: fuzzer
|
||||
./fuzzer
|
||||
|
||||
test-fuzzer32: fuzzer32
|
||||
./fuzzer32
|
||||
|
||||
test-frametest: frametest
|
||||
./frametest
|
||||
|
||||
test-frametest32: frametest32
|
||||
./frametest32
|
||||
|
||||
test-mem: lz4 datagen fuzzer frametest
|
||||
./datagen -g16KB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -9 -BD -f tmp /dev/null
|
||||
./datagen -g16MB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -9 -B5D -f tmp /dev/null
|
||||
./datagen -g256MB > tmp
|
||||
valgrind --leak-check=yes ./lz4 -B4D -f -vq tmp /dev/null
|
||||
rm tmp
|
||||
valgrind --leak-check=yes ./fuzzer -i64 -t1
|
||||
valgrind --leak-check=yes ./frametest -i256
|
||||
|
||||
test-mem32: lz4c32 datagen
|
||||
# unfortunately, valgrind doesn't seem to work with non-native binary. If someone knows how to do a valgrind-test on a 32-bits exe with a 64-bits system...
|
||||
|
||||
endif
|
||||
435
programs/bench.c
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
bench.c - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
/* Disable some Visual warning messages */
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
|
||||
/* Unix Large Files support (>4GB) */
|
||||
#define _FILE_OFFSET_BITS 64
|
||||
#if (defined(__sun__) && (!defined(__LP64__))) /* Sun Solaris 32-bits requires specific definitions */
|
||||
# define _LARGEFILE_SOURCE
|
||||
#elif ! defined(__LP64__) /* No point defining Large file for 64 bit */
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
/* S_ISREG & gettimeofday() are not supported by MSVC */
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
# define BMK_LEGACY_TIMER 1
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Includes
|
||||
***************************************/
|
||||
#include <stdlib.h> /* malloc */
|
||||
#include <stdio.h> /* fprintf, fopen, ftello64 */
|
||||
#include <sys/types.h> /* stat64 */
|
||||
#include <sys/stat.h> /* stat64 */
|
||||
|
||||
/* Use ftime() if gettimeofday() is not available on your target */
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
# include <sys/timeb.h> /* timeb, ftime */
|
||||
#else
|
||||
# include <sys/time.h> /* gettimeofday */
|
||||
#endif
|
||||
|
||||
#include "lz4.h"
|
||||
#define COMPRESSOR0 LZ4_compress_local
|
||||
static int LZ4_compress_local(const char* src, char* dst, int size, int clevel) { (void)clevel; return LZ4_compress(src, dst, size); }
|
||||
#include "lz4hc.h"
|
||||
#define COMPRESSOR1 LZ4_compressHC2
|
||||
#define DEFAULTCOMPRESSOR COMPRESSOR0
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler specifics
|
||||
***************************************/
|
||||
#if !defined(S_ISREG)
|
||||
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
#define NBLOOPS 3
|
||||
#define TIMELOOP 2000
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define MAX_MEM (2 GB - 64 MB)
|
||||
#define DEFAULT_CHUNKSIZE (4 MB)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local structures
|
||||
***************************************/
|
||||
struct chunkParameters
|
||||
{
|
||||
U32 id;
|
||||
char* origBuffer;
|
||||
char* compressedBuffer;
|
||||
int origSize;
|
||||
int compressedSize;
|
||||
};
|
||||
|
||||
struct compressionParameters
|
||||
{
|
||||
int (*compressionFunction)(const char*, char*, int, int);
|
||||
int (*decompressionFunction)(const char*, char*, int);
|
||||
};
|
||||
|
||||
|
||||
/**************************************
|
||||
* MACRO
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Benchmark Parameters
|
||||
***************************************/
|
||||
static int chunkSize = DEFAULT_CHUNKSIZE;
|
||||
static int nbIterations = NBLOOPS;
|
||||
static int BMK_pause = 0;
|
||||
|
||||
void BMK_SetBlocksize(int bsize) { chunkSize = bsize; }
|
||||
|
||||
void BMK_SetNbIterations(int nbLoops)
|
||||
{
|
||||
nbIterations = nbLoops;
|
||||
DISPLAY("- %i iterations -\n", nbIterations);
|
||||
}
|
||||
|
||||
void BMK_SetPause(void) { BMK_pause = 1; }
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Private functions
|
||||
**********************************************************/
|
||||
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
/* Based on Legacy ftime()
|
||||
Rolls over every ~ 12.1 days (0x100000/24/60/60)
|
||||
Use GetMilliSpan to correct for rollover */
|
||||
struct timeb tb;
|
||||
int nCount;
|
||||
ftime( &tb );
|
||||
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
/* Based on newer gettimeofday()
|
||||
Use GetMilliSpan to correct for rollover */
|
||||
struct timeval tv;
|
||||
int nCount;
|
||||
gettimeofday(&tv, NULL);
|
||||
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static int BMK_GetMilliSpan( int nTimeStart )
|
||||
{
|
||||
int nSpan = BMK_GetMilliStart() - nTimeStart;
|
||||
if ( nSpan < 0 )
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
size_t step = 64 MB;
|
||||
BYTE* testmem=NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 26) + 1) << 26);
|
||||
requiredMem += 2*step;
|
||||
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
|
||||
|
||||
while (!testmem)
|
||||
{
|
||||
requiredMem -= step;
|
||||
testmem = (BYTE*) malloc ((size_t)requiredMem);
|
||||
}
|
||||
|
||||
free (testmem);
|
||||
return (size_t) (requiredMem - step);
|
||||
}
|
||||
|
||||
|
||||
static U64 BMK_GetFileSize(char* infilename)
|
||||
{
|
||||
int r;
|
||||
#if defined(_MSC_VER)
|
||||
struct _stat64 statbuf;
|
||||
r = _stat64(infilename, &statbuf);
|
||||
#else
|
||||
struct stat statbuf;
|
||||
r = stat(infilename, &statbuf);
|
||||
#endif
|
||||
if (r || !S_ISREG(statbuf.st_mode)) return 0; /* No good... */
|
||||
return (U64)statbuf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Public function
|
||||
**********************************************************/
|
||||
|
||||
int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel)
|
||||
{
|
||||
int fileIdx=0;
|
||||
char* orig_buff;
|
||||
struct compressionParameters compP;
|
||||
int cfunctionId;
|
||||
|
||||
U64 totals = 0;
|
||||
U64 totalz = 0;
|
||||
double totalc = 0.;
|
||||
double totald = 0.;
|
||||
|
||||
|
||||
/* Init */
|
||||
if (cLevel <= 3) 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;
|
||||
}
|
||||
compP.decompressionFunction = LZ4_decompress_fast;
|
||||
|
||||
/* Loop for each file */
|
||||
while (fileIdx<nbFiles)
|
||||
{
|
||||
FILE* inFile;
|
||||
char* inFileName;
|
||||
U64 inFileSize;
|
||||
size_t benchedSize;
|
||||
int nbChunks;
|
||||
int maxCompressedChunkSize;
|
||||
size_t readSize;
|
||||
char* compressedBuffer; int compressedBuffSize;
|
||||
struct chunkParameters* chunkP;
|
||||
U32 crcOrig;
|
||||
|
||||
/* Check file existence */
|
||||
inFileName = fileNamesTable[fileIdx++];
|
||||
inFile = fopen( inFileName, "rb" );
|
||||
if (inFile==NULL)
|
||||
{
|
||||
DISPLAY( "Pb opening %s\n", inFileName);
|
||||
return 11;
|
||||
}
|
||||
|
||||
/* Memory allocation & restrictions */
|
||||
inFileSize = BMK_GetFileSize(inFileName);
|
||||
benchedSize = (size_t) BMK_findMaxMem(inFileSize * 2) / 2;
|
||||
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
|
||||
if (benchedSize < inFileSize)
|
||||
{
|
||||
DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
|
||||
}
|
||||
|
||||
/* Alloc */
|
||||
chunkP = (struct chunkParameters*) malloc(((benchedSize / (size_t)chunkSize)+1) * sizeof(struct chunkParameters));
|
||||
orig_buff = (char*)malloc((size_t )benchedSize);
|
||||
nbChunks = (int) ((int)benchedSize / chunkSize) + 1;
|
||||
maxCompressedChunkSize = LZ4_compressBound(chunkSize);
|
||||
compressedBuffSize = nbChunks * maxCompressedChunkSize;
|
||||
compressedBuffer = (char*)malloc((size_t )compressedBuffSize);
|
||||
|
||||
|
||||
if (!orig_buff || !compressedBuffer)
|
||||
{
|
||||
DISPLAY("\nError: not enough memory!\n");
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
fclose(inFile);
|
||||
return 12;
|
||||
}
|
||||
|
||||
/* Init chunks data */
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressedBuffer;
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill input buffer */
|
||||
DISPLAY("Loading %s... \r", inFileName);
|
||||
readSize = fread(orig_buff, 1, benchedSize, inFile);
|
||||
fclose(inFile);
|
||||
|
||||
if (readSize != benchedSize)
|
||||
{
|
||||
DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
return 13;
|
||||
}
|
||||
|
||||
/* Calculating input Checksum */
|
||||
crcOrig = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
|
||||
|
||||
/* Bench */
|
||||
{
|
||||
int loopNb, chunkNb;
|
||||
size_t cSize=0;
|
||||
double fastestC = 100000000., fastestD = 100000000.;
|
||||
double ratio=0.;
|
||||
U32 crcCheck=0;
|
||||
|
||||
DISPLAY("\r%79s\r", "");
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
int nbLoops;
|
||||
int milliTime;
|
||||
|
||||
/* Compression */
|
||||
DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, inFileName, (int)benchedSize);
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) compressedBuffer[i]=(char)i; } /* warmimg up memory */
|
||||
|
||||
nbLoops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
chunkP[chunkNb].compressedSize = compP.compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize, cLevel);
|
||||
nbLoops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
if ((double)milliTime < fastestC*nbLoops) fastestC = (double)milliTime/nbLoops;
|
||||
cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;
|
||||
ratio = (double)cSize/(double)benchedSize*100.;
|
||||
|
||||
DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s\r", loopNb, inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000.);
|
||||
|
||||
/* Decompression */
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; } /* zeroing area, for CRC checking */
|
||||
|
||||
nbLoops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
chunkP[chunkNb].compressedSize = LZ4_decompress_fast(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].origSize);
|
||||
nbLoops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
if ((double)milliTime < fastestD*nbLoops) fastestD = (double)milliTime/nbLoops;
|
||||
DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\r", loopNb, inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
|
||||
/* CRC Checking */
|
||||
crcCheck = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
if (crcOrig!=crcCheck) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", inFileName, (unsigned)crcOrig, (unsigned)crcCheck); break; }
|
||||
}
|
||||
|
||||
if (crcOrig==crcCheck)
|
||||
{
|
||||
if (ratio<100.)
|
||||
DISPLAY("%-16.16s : %9i -> %9i (%5.2f%%),%7.1f MB/s ,%7.1f MB/s\n", inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
else
|
||||
DISPLAY("%-16.16s : %9i -> %9i (%5.1f%%),%7.1f MB/s ,%7.1f MB/s \n", inFileName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / fastestC / 1000., (double)benchedSize / fastestD / 1000.);
|
||||
}
|
||||
totals += benchedSize;
|
||||
totalz += cSize;
|
||||
totalc += fastestC;
|
||||
totald += fastestD;
|
||||
}
|
||||
|
||||
free(orig_buff);
|
||||
free(compressedBuffer);
|
||||
free(chunkP);
|
||||
}
|
||||
|
||||
if (nbFiles > 1)
|
||||
DISPLAY("%-16.16s :%10llu ->%10llu (%5.2f%%), %6.1f MB/s , %6.1f MB/s\n", " TOTAL", (long long unsigned int)totals, (long long unsigned int)totalz, (double)totalz/(double)totals*100., (double)totals/totalc/1000., (double)totals/totald/1000.);
|
||||
|
||||
if (BMK_pause) { DISPLAY("\npress enter...\n"); getchar(); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
42
programs/bench.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
bench.h - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2014
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://group.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Main function */
|
||||
int BMK_benchFile(char** fileNamesTable, int nbFiles, int cLevel);
|
||||
|
||||
/* Set Parameters */
|
||||
void BMK_SetBlocksize(int bsize);
|
||||
void BMK_SetNbIterations(int nbLoops);
|
||||
void BMK_SetPause(void);
|
||||
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
#endif
|
||||
286
programs/datagen.c
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
datagen.c - compressible data generator test tool
|
||||
Copyright (C) Yann Collet 2012-2015
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Remove Visual warning messages
|
||||
**************************************/
|
||||
#define _CRT_SECURE_NO_WARNINGS // fgets
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stdio.h> // fgets, sscanf
|
||||
#include <string.h> // strcmp
|
||||
|
||||
|
||||
/**************************************
|
||||
Basic Types
|
||||
**************************************/
|
||||
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Constants
|
||||
**************************************/
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION "r125"
|
||||
#endif
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define CDG_SIZE_DEFAULT (64 KB)
|
||||
#define CDG_SEED_DEFAULT 0
|
||||
#define CDG_COMPRESSIBILITY_DEFAULT 50
|
||||
#define PRIME1 2654435761U
|
||||
#define PRIME2 2246822519U
|
||||
|
||||
|
||||
/**************************************
|
||||
Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
|
||||
|
||||
/**************************************
|
||||
Local Parameters
|
||||
**************************************/
|
||||
static unsigned no_prompt = 0;
|
||||
static char* programName;
|
||||
static unsigned displayLevel = 2;
|
||||
|
||||
|
||||
/*********************************************************
|
||||
functions
|
||||
*********************************************************/
|
||||
|
||||
#define CDG_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
static unsigned int CDG_rand(U32* src)
|
||||
{
|
||||
U32 rand32 = *src;
|
||||
rand32 *= PRIME1;
|
||||
rand32 += PRIME2;
|
||||
rand32 = CDG_rotl32(rand32, 13);
|
||||
*src = rand32;
|
||||
return rand32;
|
||||
}
|
||||
|
||||
|
||||
#define CDG_RAND15BITS ((CDG_rand(seed) >> 3) & 32767)
|
||||
#define CDG_RANDLENGTH ( ((CDG_rand(seed) >> 7) & 3) ? (CDG_rand(seed) % 14) : (CDG_rand(seed) & 511) + 15)
|
||||
#define CDG_RANDCHAR (((CDG_rand(seed) >> 9) & 63) + '0')
|
||||
static void CDG_generate(U64 size, U32* seed, double proba)
|
||||
{
|
||||
BYTE fullbuff[32 KB + 128 KB + 1];
|
||||
BYTE* buff = fullbuff + 32 KB;
|
||||
U64 total=0;
|
||||
U32 P32 = (U32)(32768 * proba);
|
||||
U32 pos=1;
|
||||
U32 genBlockSize = 128 KB;
|
||||
|
||||
// Build initial prefix
|
||||
fullbuff[0] = CDG_RANDCHAR;
|
||||
while (pos<32 KB)
|
||||
{
|
||||
// Select : Literal (char) or Match (within 32K)
|
||||
if (CDG_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
U32 d;
|
||||
int ref;
|
||||
int length = CDG_RANDLENGTH + 4;
|
||||
U32 offset = CDG_RAND15BITS + 1;
|
||||
if (offset > pos) offset = pos;
|
||||
ref = pos - offset;
|
||||
d = pos + length;
|
||||
while (pos < d) fullbuff[pos++] = fullbuff[ref++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
U32 d = pos + CDG_RANDLENGTH;
|
||||
while (pos < d) fullbuff[pos++] = CDG_RANDCHAR;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate compressible data
|
||||
pos = 0;
|
||||
while (total < size)
|
||||
{
|
||||
if (size-total < 128 KB) genBlockSize = (U32)(size-total);
|
||||
total += genBlockSize;
|
||||
buff[genBlockSize] = 0;
|
||||
pos = 0;
|
||||
while (pos<genBlockSize)
|
||||
{
|
||||
// Select : Literal (char) or Match (within 32K)
|
||||
if (CDG_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
int ref;
|
||||
U32 d;
|
||||
int length = CDG_RANDLENGTH + 4;
|
||||
U32 offset = CDG_RAND15BITS + 1;
|
||||
if (pos + length > genBlockSize ) length = genBlockSize - pos;
|
||||
ref = pos - offset;
|
||||
d = pos + length;
|
||||
while (pos < d) buff[pos++] = buff[ref++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
U32 d;
|
||||
int length = CDG_RANDLENGTH;
|
||||
if (pos + length > genBlockSize) length = genBlockSize - pos;
|
||||
d = pos + length;
|
||||
while (pos < d) buff[pos++] = CDG_RANDCHAR;
|
||||
}
|
||||
}
|
||||
// output datagen
|
||||
pos=0;
|
||||
for (;pos+512<=genBlockSize;pos+=512)
|
||||
printf("%512.512s", buff+pos);
|
||||
for (;pos<genBlockSize;pos++) printf("%c", buff[pos]);
|
||||
// Regenerate prefix
|
||||
memcpy(fullbuff, buff + 96 KB, 32 KB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int CDG_usage(void)
|
||||
{
|
||||
DISPLAY( "Compressible data generator\n");
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [size] [args]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -g# : generate # data (default:%i)\n", CDG_SIZE_DEFAULT);
|
||||
DISPLAY( " -s# : Select seed (default:%i)\n", CDG_SEED_DEFAULT);
|
||||
DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", CDG_COMPRESSIBILITY_DEFAULT);
|
||||
DISPLAY( " -h : display help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int argNb;
|
||||
int proba = CDG_COMPRESSIBILITY_DEFAULT;
|
||||
U64 size = CDG_SIZE_DEFAULT;
|
||||
U32 seed = CDG_SEED_DEFAULT;
|
||||
|
||||
// Check command line
|
||||
programName = argv[0];
|
||||
for(argNb=1; argNb<argc; argNb++)
|
||||
{
|
||||
char* argument = argv[argNb];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (*argument=='-')
|
||||
{
|
||||
if (!strcmp(argument, "--no-prompt")) { no_prompt=1; continue; }
|
||||
|
||||
argument++;
|
||||
while (*argument!=0)
|
||||
{
|
||||
switch(*argument)
|
||||
{
|
||||
case 'h':
|
||||
return CDG_usage();
|
||||
case 'g':
|
||||
argument++;
|
||||
size=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
size *= 10;
|
||||
size += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (*argument=='K') { size <<= 10; argument++; }
|
||||
if (*argument=='M') { size <<= 20; argument++; }
|
||||
if (*argument=='G') { size <<= 30; argument++; }
|
||||
if (*argument=='B') { argument++; }
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
seed *= 10;
|
||||
seed += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
argument++;
|
||||
proba=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
proba *= 10;
|
||||
proba += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (proba<0) proba=0;
|
||||
if (proba>100) proba=100;
|
||||
break;
|
||||
case 'v':
|
||||
displayLevel = 4;
|
||||
argument++;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Get Seed
|
||||
DISPLAYLEVEL(4, "Data Generator %s \n", LZ4_VERSION);
|
||||
DISPLAYLEVEL(3, "Seed = %u \n", seed);
|
||||
if (proba!=CDG_COMPRESSIBILITY_DEFAULT) DISPLAYLEVEL(3, "Compressibility : %i%%\n", proba);
|
||||
|
||||
CDG_generate(size, &seed, ((double)proba) / 100);
|
||||
|
||||
return 0;
|
||||
}
|
||||
669
programs/frametest.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
frameTest - test tool for lz4frame
|
||||
Copyright (C) Yann Collet 2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
Compiler specific
|
||||
**************************************/
|
||||
#define _CRT_SECURE_NO_WARNINGS // fgets
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
# pragma warning(disable : 4146) /* disable: C4146: minus unsigned expression */
|
||||
#endif
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Includes
|
||||
**************************************/
|
||||
#include <stdlib.h> // free
|
||||
#include <stdio.h> // fgets, sscanf
|
||||
#include <sys/timeb.h> // timeb
|
||||
#include <string.h> // strcmp
|
||||
#include "lz4frame_static.h"
|
||||
#include "xxhash.h" // XXH64
|
||||
|
||||
|
||||
/**************************************
|
||||
Basic Types
|
||||
**************************************/
|
||||
#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
Constants
|
||||
**************************************/
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION ""
|
||||
#endif
|
||||
|
||||
#define KB *(1U<<10)
|
||||
#define MB *(1U<<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
static const U32 nbTestsDefault = 256 KB;
|
||||
#define COMPRESSIBLE_NOISE_LENGTH (2 MB)
|
||||
#define FUZ_COMPRESSIBILITY_DEFAULT 50
|
||||
static const U32 prime1 = 2654435761U;
|
||||
static const U32 prime2 = 2246822519U;
|
||||
|
||||
|
||||
|
||||
/**************************************
|
||||
Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
|
||||
if ((FUZ_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
|
||||
{ g_time = FUZ_GetMilliStart(); DISPLAY(__VA_ARGS__); \
|
||||
if (displayLevel>=4) fflush(stdout); } }
|
||||
static const U32 refreshRate = 150;
|
||||
static U32 g_time = 0;
|
||||
|
||||
|
||||
/*****************************************
|
||||
Local Parameters
|
||||
*****************************************/
|
||||
static U32 no_prompt = 0;
|
||||
static char* programName;
|
||||
static U32 displayLevel = 2;
|
||||
static U32 pause = 0;
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Fuzzer functions
|
||||
*********************************************************/
|
||||
static U32 FUZ_GetMilliStart(void)
|
||||
{
|
||||
struct timeb tb;
|
||||
U32 nCount;
|
||||
ftime( &tb );
|
||||
nCount = (U32) (((tb.time & 0xFFFFF) * 1000) + tb.millitm);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
|
||||
static U32 FUZ_GetMilliSpan(U32 nTimeStart)
|
||||
{
|
||||
U32 nCurrent = FUZ_GetMilliStart();
|
||||
U32 nSpan = nCurrent - nTimeStart;
|
||||
if (nTimeStart > nCurrent)
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
# define FUZ_rotl32(x,r) ((x << r) | (x >> (32 - r)))
|
||||
unsigned int FUZ_rand(unsigned int* src)
|
||||
{
|
||||
U32 rand32 = *src;
|
||||
rand32 *= prime1;
|
||||
rand32 += prime2;
|
||||
rand32 = FUZ_rotl32(rand32, 13);
|
||||
*src = rand32;
|
||||
return rand32 >> 5;
|
||||
}
|
||||
|
||||
|
||||
#define FUZ_RAND15BITS (FUZ_rand(seed) & 0x7FFF)
|
||||
#define FUZ_RANDLENGTH ( (FUZ_rand(seed) & 3) ? (FUZ_rand(seed) % 15) : (FUZ_rand(seed) % 510) + 15)
|
||||
static void FUZ_fillCompressibleNoiseBuffer(void* buffer, unsigned bufferSize, double proba, U32* seed)
|
||||
{
|
||||
BYTE* BBuffer = (BYTE*)buffer;
|
||||
unsigned pos = 0;
|
||||
U32 P32 = (U32)(32768 * proba);
|
||||
|
||||
// First Byte
|
||||
BBuffer[pos++] = (BYTE)(FUZ_rand(seed));
|
||||
|
||||
while (pos < bufferSize)
|
||||
{
|
||||
// Select : Literal (noise) or copy (within 64K)
|
||||
if (FUZ_RAND15BITS < P32)
|
||||
{
|
||||
// Copy (within 64K)
|
||||
unsigned match, end;
|
||||
unsigned length = FUZ_RANDLENGTH + 4;
|
||||
unsigned offset = FUZ_RAND15BITS + 1;
|
||||
if (offset > pos) offset = pos;
|
||||
if (pos + length > bufferSize) length = bufferSize - pos;
|
||||
match = pos - offset;
|
||||
end = pos + length;
|
||||
while (pos < end) BBuffer[pos++] = BBuffer[match++];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Literal (noise)
|
||||
unsigned end;
|
||||
unsigned length = FUZ_RANDLENGTH;
|
||||
if (pos + length > bufferSize) length = bufferSize - pos;
|
||||
end = pos + length;
|
||||
while (pos < end) BBuffer[pos++] = (BYTE)(FUZ_rand(seed) >> 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static unsigned FUZ_highbit(U32 v32)
|
||||
{
|
||||
unsigned nbBits = 0;
|
||||
if (v32==0) return 0;
|
||||
while (v32)
|
||||
{
|
||||
v32 >>= 1;
|
||||
nbBits ++;
|
||||
}
|
||||
return nbBits;
|
||||
}
|
||||
|
||||
|
||||
int basicTests(U32 seed, double compressibility)
|
||||
{
|
||||
int testResult = 0;
|
||||
void* CNBuffer;
|
||||
void* compressedBuffer;
|
||||
void* decodedBuffer;
|
||||
U32 randState = seed;
|
||||
size_t cSize, testSize;
|
||||
LZ4F_preferences_t prefs = { 0 };
|
||||
LZ4F_decompressionContext_t dCtx;
|
||||
U64 crcOrig;
|
||||
|
||||
// Create compressible test buffer
|
||||
CNBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
|
||||
compressedBuffer = malloc(LZ4F_compressFrameBound(COMPRESSIBLE_NOISE_LENGTH, NULL));
|
||||
decodedBuffer = malloc(COMPRESSIBLE_NOISE_LENGTH);
|
||||
FUZ_fillCompressibleNoiseBuffer(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, compressibility, &randState);
|
||||
crcOrig = XXH64(CNBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
|
||||
// Trivial tests : one-step frame
|
||||
testSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
DISPLAYLEVEL(3, "Using NULL preferences : \n");
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, NULL), CNBuffer, testSize, NULL);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Decompression test : \n");
|
||||
{
|
||||
size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
size_t compressedBufferSize = cSize;
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
|
||||
BYTE* ip = (BYTE*)compressedBuffer;
|
||||
BYTE* const iend = (BYTE*)compressedBuffer + cSize;
|
||||
U64 crcDest;
|
||||
|
||||
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
|
||||
DISPLAYLEVEL(3, "Single Block : \n");
|
||||
errorCode = LZ4F_decompress(dCtx, decodedBuffer, &decodedBufferSize, compressedBuffer, &compressedBufferSize, NULL);
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Byte after byte : \n");
|
||||
while (ip < iend)
|
||||
{
|
||||
size_t oSize = oend-op;
|
||||
size_t iSize = 1;
|
||||
//DISPLAY("%7i \n", (int)(ip-(BYTE*)compressedBuffer));
|
||||
errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
}
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
errorCode = LZ4F_freeDecompressionContext(dCtx);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "Using 64 KB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max64KB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 256 KB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max256KB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Decompression test : \n");
|
||||
{
|
||||
size_t decodedBufferSize = COMPRESSIBLE_NOISE_LENGTH;
|
||||
unsigned maxBits = FUZ_highbit((U32)decodedBufferSize);
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = (BYTE*)decodedBuffer + COMPRESSIBLE_NOISE_LENGTH;
|
||||
BYTE* ip = (BYTE*)compressedBuffer;
|
||||
BYTE* const iend = (BYTE*)compressedBuffer + cSize;
|
||||
U64 crcDest;
|
||||
|
||||
LZ4F_errorCode_t errorCode = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
|
||||
DISPLAYLEVEL(3, "random segment sizes : \n");
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBits = FUZ_rand(&randState) % maxBits;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
|
||||
size_t oSize = oend-op;
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
//DISPLAY("%7i : + %6i\n", (int)(ip-(BYTE*)compressedBuffer), (int)iSize);
|
||||
errorCode = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
}
|
||||
crcDest = XXH64(decodedBuffer, COMPRESSIBLE_NOISE_LENGTH, 1);
|
||||
if (crcDest != crcOrig) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Regenerated %i bytes \n", (int)decodedBufferSize);
|
||||
|
||||
errorCode = LZ4F_freeDecompressionContext(dCtx);
|
||||
if (LZ4F_isError(errorCode)) goto _output_error;
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 1 MB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max1MB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "Using 4 MB block : \n");
|
||||
prefs.frameInfo.blockSizeID = max4MB;
|
||||
prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAYLEVEL(3, "without checksum : \n");
|
||||
prefs.frameInfo.contentChecksumFlag = noContentChecksum;
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(testSize, &prefs), CNBuffer, testSize, &prefs);
|
||||
if (LZ4F_isError(cSize)) goto _output_error;
|
||||
DISPLAYLEVEL(3, "Compressed %i bytes into a %i bytes frame \n", (int)testSize, (int)cSize);
|
||||
|
||||
DISPLAY("Basic tests completed \n");
|
||||
_end:
|
||||
free(CNBuffer);
|
||||
free(compressedBuffer);
|
||||
free(decodedBuffer);
|
||||
return testResult;
|
||||
|
||||
_output_error:
|
||||
testResult = 1;
|
||||
DISPLAY("Error detected ! \n");
|
||||
goto _end;
|
||||
}
|
||||
|
||||
|
||||
static void locateBuffDiff(const void* buff1, const void* buff2, size_t size, unsigned nonContiguous)
|
||||
{
|
||||
int p=0;
|
||||
BYTE* b1=(BYTE*)buff1;
|
||||
BYTE* b2=(BYTE*)buff2;
|
||||
if (nonContiguous)
|
||||
{
|
||||
DISPLAY("Non-contiguous output test (%i bytes)\n", (int)size);
|
||||
return;
|
||||
}
|
||||
while (b1[p]==b2[p]) p++;
|
||||
DISPLAY("Error at pos %i/%i : %02X != %02X \n", p, (int)size, b1[p], b2[p]);
|
||||
}
|
||||
|
||||
|
||||
static const U32 srcDataLength = 9 MB; /* needs to be > 2x4MB to test large blocks */
|
||||
|
||||
int fuzzerTests(U32 seed, unsigned nbTests, unsigned startTest, double compressibility)
|
||||
{
|
||||
unsigned testResult = 0;
|
||||
unsigned testNb = 0;
|
||||
void* srcBuffer = NULL;
|
||||
void* compressedBuffer = NULL;
|
||||
void* decodedBuffer = NULL;
|
||||
U32 coreRand = seed;
|
||||
LZ4F_decompressionContext_t dCtx = NULL;
|
||||
LZ4F_compressionContext_t cCtx = NULL;
|
||||
size_t result;
|
||||
XXH64_state_t xxh64;
|
||||
# define CHECK(cond, ...) if (cond) { DISPLAY("Error => "); DISPLAY(__VA_ARGS__); \
|
||||
DISPLAY(" (seed %u, test nb %u) \n", seed, testNb); goto _output_error; }
|
||||
|
||||
// Create buffers
|
||||
result = LZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);
|
||||
CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
|
||||
result = LZ4F_createCompressionContext(&cCtx, LZ4F_VERSION);
|
||||
CHECK(LZ4F_isError(result), "Allocation failed (error %i)", (int)result);
|
||||
srcBuffer = malloc(srcDataLength);
|
||||
CHECK(srcBuffer==NULL, "srcBuffer Allocation failed");
|
||||
compressedBuffer = malloc(LZ4F_compressFrameBound(srcDataLength, NULL));
|
||||
CHECK(compressedBuffer==NULL, "compressedBuffer Allocation failed");
|
||||
decodedBuffer = malloc(srcDataLength);
|
||||
CHECK(decodedBuffer==NULL, "decodedBuffer Allocation failed");
|
||||
FUZ_fillCompressibleNoiseBuffer(srcBuffer, srcDataLength, compressibility, &coreRand);
|
||||
|
||||
// jump to requested testNb
|
||||
for (testNb =0; testNb < startTest; testNb++) (void)FUZ_rand(&coreRand); // sync randomizer
|
||||
|
||||
// main fuzzer loop
|
||||
for ( ; testNb < nbTests; testNb++)
|
||||
{
|
||||
U32 randState = coreRand ^ prime1;
|
||||
unsigned BSId = 4 + (FUZ_rand(&randState) & 3);
|
||||
unsigned BMId = FUZ_rand(&randState) & 1;
|
||||
unsigned CCflag = FUZ_rand(&randState) & 1;
|
||||
unsigned autoflush = (FUZ_rand(&randState) & 7) == 2;
|
||||
LZ4F_preferences_t prefs = { 0 };
|
||||
LZ4F_compressOptions_t cOptions = { 0 };
|
||||
LZ4F_decompressOptions_t dOptions = { 0 };
|
||||
unsigned nbBits = (FUZ_rand(&randState) % (FUZ_highbit(srcDataLength-1) - 1)) + 1;
|
||||
size_t srcSize = (FUZ_rand(&randState) & ((1<<nbBits)-1)) + 1;
|
||||
size_t srcStart = FUZ_rand(&randState) % (srcDataLength - srcSize);
|
||||
size_t cSize;
|
||||
U64 crcOrig, crcDecoded;
|
||||
LZ4F_preferences_t* prefsPtr = &prefs;
|
||||
|
||||
(void)FUZ_rand(&coreRand); // update rand seed
|
||||
prefs.frameInfo.blockMode = (blockMode_t)BMId;
|
||||
prefs.frameInfo.blockSizeID = (blockSizeID_t)BSId;
|
||||
prefs.frameInfo.contentChecksumFlag = (contentChecksum_t)CCflag;
|
||||
prefs.autoFlush = autoflush;
|
||||
prefs.compressionLevel = FUZ_rand(&randState) % 5;
|
||||
if ((FUZ_rand(&randState)&0xF) == 1) prefsPtr = NULL;
|
||||
|
||||
DISPLAYUPDATE(2, "\r%5u ", testNb);
|
||||
crcOrig = XXH64((BYTE*)srcBuffer+srcStart, (U32)srcSize, 1);
|
||||
|
||||
if ((FUZ_rand(&randState)&0xF) == 2)
|
||||
{
|
||||
cSize = LZ4F_compressFrame(compressedBuffer, LZ4F_compressFrameBound(srcSize, prefsPtr), (char*)srcBuffer + srcStart, srcSize, prefsPtr);
|
||||
CHECK(LZ4F_isError(cSize), "LZ4F_compressFrame failed : error %i (%s)", (int)cSize, LZ4F_getErrorName(cSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)srcBuffer + srcStart;
|
||||
const BYTE* const iend = ip + srcSize;
|
||||
BYTE* op = (BYTE*)compressedBuffer;
|
||||
BYTE* const oend = op + LZ4F_compressFrameBound(srcDataLength, NULL);
|
||||
unsigned maxBits = FUZ_highbit((U32)srcSize);
|
||||
result = LZ4F_compressBegin(cCtx, op, oend-op, prefsPtr);
|
||||
CHECK(LZ4F_isError(result), "Compression header failed (error %i)", (int)result);
|
||||
op += result;
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBitsSeg = FUZ_rand(&randState) % maxBits;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsSeg)-1)) + 1;
|
||||
size_t oSize = LZ4F_compressBound(iSize, prefsPtr);
|
||||
unsigned forceFlush = ((FUZ_rand(&randState) & 3) == 1);
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
cOptions.stableSrc = ((FUZ_rand(&randState) & 3) == 1);
|
||||
|
||||
result = LZ4F_compressUpdate(cCtx, op, oSize, ip, iSize, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
|
||||
op += result;
|
||||
ip += iSize;
|
||||
|
||||
if (forceFlush)
|
||||
{
|
||||
result = LZ4F_flush(cCtx, op, oend-op, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression failed (error %i)", (int)result);
|
||||
op += result;
|
||||
}
|
||||
}
|
||||
result = LZ4F_compressEnd(cCtx, op, oend-op, &cOptions);
|
||||
CHECK(LZ4F_isError(result), "Compression completion failed (error %i)", (int)result);
|
||||
op += result;
|
||||
cSize = op-(BYTE*)compressedBuffer;
|
||||
}
|
||||
|
||||
{
|
||||
const BYTE* ip = (const BYTE*)compressedBuffer;
|
||||
const BYTE* const iend = ip + cSize;
|
||||
BYTE* op = (BYTE*)decodedBuffer;
|
||||
BYTE* const oend = op + srcDataLength;
|
||||
unsigned maxBits = FUZ_highbit((U32)cSize);
|
||||
unsigned nonContiguousDst = (FUZ_rand(&randState) & 3) == 1;
|
||||
nonContiguousDst += FUZ_rand(&randState) & nonContiguousDst; /* 0=>0; 1=>1,2 */
|
||||
XXH64_reset(&xxh64, 1);
|
||||
while (ip < iend)
|
||||
{
|
||||
unsigned nbBitsI = (FUZ_rand(&randState) % (maxBits-1)) + 1;
|
||||
unsigned nbBitsO = (FUZ_rand(&randState) % (maxBits)) + 1;
|
||||
size_t iSize = (FUZ_rand(&randState) & ((1<<nbBitsI)-1)) + 1;
|
||||
size_t oSize = (FUZ_rand(&randState) & ((1<<nbBitsO)-1)) + 2;
|
||||
if (iSize > (size_t)(iend-ip)) iSize = iend-ip;
|
||||
if (oSize > (size_t)(oend-op)) oSize = oend-op;
|
||||
dOptions.stableDst = FUZ_rand(&randState) & 1;
|
||||
if (nonContiguousDst==2) dOptions.stableDst = 0;
|
||||
//if (ip == compressedBuffer+62073) DISPLAY("oSize : %i : pos %i \n", (int)oSize, (int)(op-(BYTE*)decodedBuffer));
|
||||
result = LZ4F_decompress(dCtx, op, &oSize, ip, &iSize, &dOptions);
|
||||
//if (op+oSize >= (BYTE*)decodedBuffer+94727) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
|
||||
//if ((int)result<0) DISPLAY("iSize : %i : pos %i \n", (int)iSize, (int)(ip-(BYTE*)compressedBuffer));
|
||||
if (result == (size_t)-ERROR_checksum_invalid) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
|
||||
CHECK(LZ4F_isError(result), "Decompression failed (error %i:%s)", (int)result, LZ4F_getErrorName((LZ4F_errorCode_t)result));
|
||||
XXH64_update(&xxh64, op, (U32)oSize);
|
||||
op += oSize;
|
||||
ip += iSize;
|
||||
op += nonContiguousDst;
|
||||
if (nonContiguousDst==2) op = decodedBuffer; // overwritten destination
|
||||
}
|
||||
CHECK(result != 0, "Frame decompression failed (error %i)", (int)result);
|
||||
crcDecoded = XXH64_digest(&xxh64);
|
||||
if (crcDecoded != crcOrig) locateBuffDiff((BYTE*)srcBuffer+srcStart, decodedBuffer, srcSize, nonContiguousDst);
|
||||
CHECK(crcDecoded != crcOrig, "Decompression corruption");
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(2, "\rAll tests completed \n");
|
||||
|
||||
_end:
|
||||
LZ4F_freeDecompressionContext(dCtx);
|
||||
LZ4F_freeCompressionContext(cCtx);
|
||||
free(srcBuffer);
|
||||
free(compressedBuffer);
|
||||
free(decodedBuffer);
|
||||
|
||||
if (pause)
|
||||
{
|
||||
DISPLAY("press enter to finish \n");
|
||||
getchar();
|
||||
}
|
||||
return testResult;
|
||||
|
||||
_output_error:
|
||||
testResult = 1;
|
||||
goto _end;
|
||||
}
|
||||
|
||||
|
||||
int FUZ_usage(void)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [args]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -i# : Nb of tests (default:%u) \n", nbTestsDefault);
|
||||
DISPLAY( " -s# : Select seed (default:prompt user)\n");
|
||||
DISPLAY( " -t# : Select starting test number (default:0)\n");
|
||||
DISPLAY( " -p# : Select compressibility in %% (default:%i%%)\n", FUZ_COMPRESSIBILITY_DEFAULT);
|
||||
DISPLAY( " -v : verbose\n");
|
||||
DISPLAY( " -h : display help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
U32 seed=0;
|
||||
int seedset=0;
|
||||
int argNb;
|
||||
int nbTests = nbTestsDefault;
|
||||
int testNb = 0;
|
||||
int proba = FUZ_COMPRESSIBILITY_DEFAULT;
|
||||
int result=0;
|
||||
|
||||
// Check command line
|
||||
programName = argv[0];
|
||||
for(argNb=1; argNb<argc; argNb++)
|
||||
{
|
||||
char* argument = argv[argNb];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
if (!strcmp(argument, "--no-prompt"))
|
||||
{
|
||||
no_prompt=1;
|
||||
seedset=1;
|
||||
displayLevel=1;
|
||||
continue;
|
||||
}
|
||||
argument++;
|
||||
|
||||
while (*argument!=0)
|
||||
{
|
||||
switch(*argument)
|
||||
{
|
||||
case 'h':
|
||||
return FUZ_usage();
|
||||
case 'v':
|
||||
argument++;
|
||||
displayLevel=4;
|
||||
break;
|
||||
case 'q':
|
||||
argument++;
|
||||
displayLevel--;
|
||||
break;
|
||||
case 'p': /* pause at the end */
|
||||
argument++;
|
||||
pause = 1;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
argument++;
|
||||
nbTests=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
nbTests *= 10;
|
||||
nbTests += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed=0;
|
||||
seedset=1;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
seed *= 10;
|
||||
seed += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
argument++;
|
||||
testNb=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
testNb *= 10;
|
||||
testNb += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 'P': /* compressibility % */
|
||||
argument++;
|
||||
proba=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
proba *= 10;
|
||||
proba += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
if (proba<0) proba=0;
|
||||
if (proba>100) proba=100;
|
||||
break;
|
||||
default:
|
||||
;
|
||||
return FUZ_usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get Seed
|
||||
printf("Starting lz4frame tester (%i-bits, %s)\n", (int)(sizeof(size_t)*8), LZ4_VERSION);
|
||||
|
||||
if (!seedset) seed = FUZ_GetMilliStart() % 10000;
|
||||
printf("Seed = %u\n", seed);
|
||||
if (proba!=FUZ_COMPRESSIBILITY_DEFAULT) printf("Compressibility : %i%%\n", proba);
|
||||
|
||||
if (nbTests<=0) nbTests=1;
|
||||
|
||||
if (testNb==0) result = basicTests(seed, ((double)proba) / 100);
|
||||
if (result) return 1;
|
||||
return fuzzerTests(seed, nbTests, testNb, ((double)proba) / 100);
|
||||
}
|
||||
842
programs/fullbench.c
Normal file
@@ -0,0 +1,842 @@
|
||||
/*
|
||||
bench.c - Demo program to benchmark open-source compression algorithm
|
||||
Copyright (C) Yann Collet 2012-2015
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4
|
||||
- LZ4 source mirror : https://github.com/Cyan4973/lz4
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
|
||||
//**************************************
|
||||
// Compiler Options
|
||||
//**************************************
|
||||
// Disable some Visual warning messages
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE // VS2005
|
||||
|
||||
// Unix Large Files support (>4GB)
|
||||
#if (defined(__sun__) && (!defined(__LP64__))) // Sun Solaris 32-bits requires specific definitions
|
||||
# define _LARGEFILE_SOURCE
|
||||
# define _FILE_OFFSET_BITS 64
|
||||
#elif ! defined(__LP64__) // No point defining Large file for 64 bit
|
||||
# define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
// S_ISREG & gettimeofday() are not supported by MSVC
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
# define BMK_LEGACY_TIMER 1
|
||||
#endif
|
||||
|
||||
|
||||
//**************************************
|
||||
// Includes
|
||||
//**************************************
|
||||
#include <stdlib.h> // malloc
|
||||
#include <stdio.h> // fprintf, fopen, ftello64
|
||||
#include <sys/types.h> // stat64
|
||||
#include <sys/stat.h> // stat64
|
||||
#include <string.h> // strcmp
|
||||
|
||||
// Use ftime() if gettimeofday() is not available on your target
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
# include <sys/timeb.h> // timeb, ftime
|
||||
#else
|
||||
# include <sys/time.h> // gettimeofday
|
||||
#endif
|
||||
|
||||
#include "lz4.h"
|
||||
#include "lz4hc.h"
|
||||
#include "lz4frame.h"
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
|
||||
//**************************************
|
||||
// Compiler Options
|
||||
//**************************************
|
||||
// S_ISREG & gettimeofday() are not supported by MSVC
|
||||
#if !defined(S_ISREG)
|
||||
# define S_ISREG(x) (((x) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
|
||||
// GCC does not support _rotl outside of Windows
|
||||
#if !defined(_WIN32)
|
||||
# define _rotl(x,r) ((x << r) | (x >> (32 - r)))
|
||||
#endif
|
||||
|
||||
|
||||
//**************************************
|
||||
// Basic Types
|
||||
//**************************************
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
typedef uint16_t U16;
|
||||
typedef uint32_t U32;
|
||||
typedef int32_t S32;
|
||||
typedef uint64_t U64;
|
||||
#else
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short U16;
|
||||
typedef unsigned int U32;
|
||||
typedef signed int S32;
|
||||
typedef unsigned long long U64;
|
||||
#endif
|
||||
|
||||
|
||||
//****************************
|
||||
// Constants
|
||||
//****************************
|
||||
#define PROGRAM_DESCRIPTION "LZ4 speed analyzer"
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION ""
|
||||
#endif
|
||||
#define AUTHOR "Yann Collet"
|
||||
#define WELCOME_MESSAGE "*** %s %s %i-bits, by %s (%s) ***\n", PROGRAM_DESCRIPTION, LZ4_VERSION, (int)(sizeof(void*)*8), AUTHOR, __DATE__
|
||||
|
||||
#define NBLOOPS 6
|
||||
#define TIMELOOP 2500
|
||||
|
||||
#define KNUTH 2654435761U
|
||||
#define MAX_MEM (1984<<20)
|
||||
#define DEFAULT_CHUNKSIZE (4<<20)
|
||||
|
||||
#define ALL_COMPRESSORS 0
|
||||
#define ALL_DECOMPRESSORS 0
|
||||
|
||||
|
||||
//**************************************
|
||||
// Local structures
|
||||
//**************************************
|
||||
struct chunkParameters
|
||||
{
|
||||
U32 id;
|
||||
char* origBuffer;
|
||||
char* compressedBuffer;
|
||||
int origSize;
|
||||
int compressedSize;
|
||||
};
|
||||
|
||||
|
||||
//**************************************
|
||||
// MACRO
|
||||
//**************************************
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define PROGRESS(...) no_prompt ? 0 : DISPLAY(__VA_ARGS__)
|
||||
|
||||
|
||||
|
||||
//**************************************
|
||||
// Benchmark Parameters
|
||||
//**************************************
|
||||
static int chunkSize = DEFAULT_CHUNKSIZE;
|
||||
static int nbIterations = NBLOOPS;
|
||||
static int BMK_pause = 0;
|
||||
static int compressionTest = 1;
|
||||
static int decompressionTest = 1;
|
||||
static int compressionAlgo = ALL_COMPRESSORS;
|
||||
static int decompressionAlgo = ALL_DECOMPRESSORS;
|
||||
static int no_prompt = 0;
|
||||
|
||||
void BMK_SetBlocksize(int bsize)
|
||||
{
|
||||
chunkSize = bsize;
|
||||
DISPLAY("-Using Block Size of %i KB-\n", chunkSize>>10);
|
||||
}
|
||||
|
||||
void BMK_SetNbIterations(int nbLoops)
|
||||
{
|
||||
nbIterations = nbLoops;
|
||||
DISPLAY("- %i iterations -\n", nbIterations);
|
||||
}
|
||||
|
||||
void BMK_SetPause(void)
|
||||
{
|
||||
BMK_pause = 1;
|
||||
}
|
||||
|
||||
//*********************************************************
|
||||
// Private functions
|
||||
//*********************************************************
|
||||
|
||||
#if defined(BMK_LEGACY_TIMER)
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
// Based on Legacy ftime()
|
||||
// Rolls over every ~ 12.1 days (0x100000/24/60/60)
|
||||
// Use GetMilliSpan to correct for rollover
|
||||
struct timeb tb;
|
||||
int nCount;
|
||||
ftime( &tb );
|
||||
nCount = (int) (tb.millitm + (tb.time & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int BMK_GetMilliStart(void)
|
||||
{
|
||||
// Based on newer gettimeofday()
|
||||
// Use GetMilliSpan to correct for rollover
|
||||
struct timeval tv;
|
||||
int nCount;
|
||||
gettimeofday(&tv, NULL);
|
||||
nCount = (int) (tv.tv_usec/1000 + (tv.tv_sec & 0xfffff) * 1000);
|
||||
return nCount;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static int BMK_GetMilliSpan( int nTimeStart )
|
||||
{
|
||||
int nSpan = BMK_GetMilliStart() - nTimeStart;
|
||||
if ( nSpan < 0 )
|
||||
nSpan += 0x100000 * 1000;
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
size_t step = (64U<<20); // 64 MB
|
||||
BYTE* testmem=NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 25) + 1) << 26);
|
||||
if (requiredMem > MAX_MEM) requiredMem = MAX_MEM;
|
||||
|
||||
requiredMem += 2*step;
|
||||
while (!testmem)
|
||||
{
|
||||
requiredMem -= step;
|
||||
testmem = (BYTE*) malloc ((size_t)requiredMem);
|
||||
}
|
||||
|
||||
free (testmem);
|
||||
return (size_t) (requiredMem - step);
|
||||
}
|
||||
|
||||
|
||||
static U64 BMK_GetFileSize(char* infilename)
|
||||
{
|
||||
int r;
|
||||
#if defined(_MSC_VER)
|
||||
struct _stat64 statbuf;
|
||||
r = _stat64(infilename, &statbuf);
|
||||
#else
|
||||
struct stat statbuf;
|
||||
r = stat(infilename, &statbuf);
|
||||
#endif
|
||||
if (r || !S_ISREG(statbuf.st_mode)) return 0; // No good...
|
||||
return (U64)statbuf.st_size;
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Benchmark function
|
||||
*********************************************************/
|
||||
|
||||
static int local_LZ4_compress_limitedOutput(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static void* stateLZ4;
|
||||
static int local_LZ4_compress_withState(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_withState(stateLZ4, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compress_limitedOutput_withState(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput_withState(stateLZ4, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static LZ4_stream_t* ctx;
|
||||
static int local_LZ4_compress_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_continue(ctx, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compress_limitedOutput_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_limitedOutput_continue(ctx, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
|
||||
LZ4_stream_t LZ4_dict;
|
||||
static void* local_LZ4_resetDictT(const char* fake)
|
||||
{
|
||||
(void)fake;
|
||||
memset(&LZ4_dict, 0, sizeof(LZ4_stream_t));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize);
|
||||
static int local_LZ4_compress_forceDict(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compress_forceExtDict(&LZ4_dict, in, out, inSize);
|
||||
}
|
||||
|
||||
|
||||
static void* stateLZ4HC;
|
||||
static int local_LZ4_compressHC_withStateHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_withStateHC(stateLZ4HC, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput_withStateHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput_withStateHC(stateLZ4HC, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput(in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_continue((LZ4_streamHC_t*)ctx, in, out, inSize);
|
||||
}
|
||||
|
||||
static int local_LZ4_compressHC_limitedOutput_continue(const char* in, char* out, int inSize)
|
||||
{
|
||||
return LZ4_compressHC_limitedOutput_continue((LZ4_streamHC_t*)ctx, in, out, inSize, LZ4_compressBound(inSize));
|
||||
}
|
||||
|
||||
static int local_LZ4F_compressFrame(const char* in, char* out, int inSize)
|
||||
{
|
||||
return (int)LZ4F_compressFrame(out, 2*inSize + 16, in, inSize, NULL);
|
||||
}
|
||||
|
||||
static int local_LZ4_saveDict(const char* in, char* out, int inSize)
|
||||
{
|
||||
(void)in;
|
||||
return LZ4_saveDict(&LZ4_dict, out, inSize);
|
||||
}
|
||||
|
||||
LZ4_streamHC_t LZ4_dictHC;
|
||||
static int local_LZ4_saveDictHC(const char* in, char* out, int inSize)
|
||||
{
|
||||
(void)in;
|
||||
return LZ4_saveDictHC(&LZ4_dictHC, out, inSize);
|
||||
}
|
||||
|
||||
|
||||
static int local_LZ4_decompress_fast(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast(in, out, outSize);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_fast_withPrefix64k(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast_withPrefix64k(in, out, outSize);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_fast_usingDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_fast_usingDict(in, out, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_safe_usingDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_safe_usingDict(in, out, inSize, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
extern int LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize, const char* dict, int dictSize);
|
||||
|
||||
static int local_LZ4_decompress_safe_forceExtDict(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
(void)inSize;
|
||||
LZ4_decompress_safe_forceExtDict(in, out, inSize, outSize, out - 65536, 65536);
|
||||
return outSize;
|
||||
}
|
||||
|
||||
static int local_LZ4_decompress_safe_partial(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
return LZ4_decompress_safe_partial(in, out, inSize, outSize - 5, outSize);
|
||||
}
|
||||
|
||||
static LZ4F_decompressionContext_t g_dCtx;
|
||||
|
||||
static int local_LZ4F_decompress(const char* in, char* out, int inSize, int outSize)
|
||||
{
|
||||
size_t srcSize = inSize;
|
||||
size_t dstSize = outSize;
|
||||
size_t result;
|
||||
result = LZ4F_decompress(g_dCtx, out, &dstSize, in, &srcSize, NULL);
|
||||
if (result!=0) { DISPLAY("Error decompressing frame : unfinished frame\n"); exit(8); }
|
||||
if (srcSize != (size_t)inSize) { DISPLAY("Error decompressing frame : read size incorrect\n"); exit(9); }
|
||||
return (int)dstSize;
|
||||
}
|
||||
|
||||
|
||||
int fullSpeedBench(char** fileNamesTable, int nbFiles)
|
||||
{
|
||||
int fileIdx=0;
|
||||
char* orig_buff;
|
||||
# define NB_COMPRESSION_ALGORITHMS 16
|
||||
double totalCTime[NB_COMPRESSION_ALGORITHMS+1] = {0};
|
||||
double totalCSize[NB_COMPRESSION_ALGORITHMS+1] = {0};
|
||||
# define NB_DECOMPRESSION_ALGORITHMS 9
|
||||
double totalDTime[NB_DECOMPRESSION_ALGORITHMS+1] = {0};
|
||||
size_t errorCode;
|
||||
|
||||
errorCode = LZ4F_createDecompressionContext(&g_dCtx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode))
|
||||
{
|
||||
DISPLAY("dctx allocation issue \n");
|
||||
return 10;
|
||||
}
|
||||
|
||||
// Loop for each file
|
||||
while (fileIdx<nbFiles)
|
||||
{
|
||||
FILE* inFile;
|
||||
char* inFileName;
|
||||
U64 inFileSize;
|
||||
size_t benchedSize;
|
||||
int nbChunks;
|
||||
int maxCompressedChunkSize;
|
||||
struct chunkParameters* chunkP;
|
||||
size_t readSize;
|
||||
char* compressed_buff; int compressedBuffSize;
|
||||
U32 crcOriginal;
|
||||
|
||||
|
||||
// Init
|
||||
stateLZ4 = LZ4_createStream();
|
||||
stateLZ4HC = LZ4_createStreamHC();
|
||||
|
||||
// Check file existence
|
||||
inFileName = fileNamesTable[fileIdx++];
|
||||
inFile = fopen( inFileName, "rb" );
|
||||
if (inFile==NULL)
|
||||
{
|
||||
DISPLAY( "Pb opening %s\n", inFileName);
|
||||
return 11;
|
||||
}
|
||||
|
||||
// Memory allocation & restrictions
|
||||
inFileSize = BMK_GetFileSize(inFileName);
|
||||
benchedSize = (size_t) BMK_findMaxMem(inFileSize) / 2;
|
||||
if ((U64)benchedSize > inFileSize) benchedSize = (size_t)inFileSize;
|
||||
if (benchedSize < inFileSize)
|
||||
{
|
||||
DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", inFileName, (int)(benchedSize>>20));
|
||||
}
|
||||
|
||||
// Alloc
|
||||
chunkP = (struct chunkParameters*) malloc(((benchedSize / (size_t)chunkSize)+1) * sizeof(struct chunkParameters));
|
||||
orig_buff = (char*) malloc((size_t)benchedSize);
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
maxCompressedChunkSize = LZ4_compressBound(chunkSize);
|
||||
compressedBuffSize = nbChunks * maxCompressedChunkSize;
|
||||
compressed_buff = (char*)malloc((size_t)compressedBuffSize);
|
||||
|
||||
|
||||
if(!orig_buff || !compressed_buff)
|
||||
{
|
||||
DISPLAY("\nError: not enough memory!\n");
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
fclose(inFile);
|
||||
return 12;
|
||||
}
|
||||
|
||||
// Fill input buffer
|
||||
DISPLAY("Loading %s... \r", inFileName);
|
||||
readSize = fread(orig_buff, 1, benchedSize, inFile);
|
||||
fclose(inFile);
|
||||
|
||||
if(readSize != benchedSize)
|
||||
{
|
||||
DISPLAY("\nError: problem reading file '%s' !! \n", inFileName);
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
return 13;
|
||||
}
|
||||
|
||||
// Calculating input Checksum
|
||||
crcOriginal = XXH32(orig_buff, (unsigned int)benchedSize,0);
|
||||
|
||||
|
||||
// Bench
|
||||
{
|
||||
int loopNb, nb_loops, chunkNb, cAlgNb, dAlgNb;
|
||||
size_t cSize=0;
|
||||
double ratio=0.;
|
||||
|
||||
DISPLAY("\r%79s\r", "");
|
||||
DISPLAY(" %s : \n", inFileName);
|
||||
|
||||
// Compression Algorithms
|
||||
for (cAlgNb=1; (cAlgNb <= NB_COMPRESSION_ALGORITHMS) && (compressionTest); cAlgNb++)
|
||||
{
|
||||
const char* compressorName;
|
||||
int (*compressionFunction)(const char*, char*, int);
|
||||
void* (*initFunction)(const char*) = NULL;
|
||||
double bestTime = 100000000.;
|
||||
|
||||
// Init data chunks
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressed_buff;
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((compressionAlgo != ALL_COMPRESSORS) && (compressionAlgo != cAlgNb)) continue;
|
||||
|
||||
switch(cAlgNb)
|
||||
{
|
||||
case 1 : compressionFunction = LZ4_compress; compressorName = "LZ4_compress"; break;
|
||||
case 2 : compressionFunction = local_LZ4_compress_limitedOutput; compressorName = "LZ4_compress_limitedOutput"; break;
|
||||
case 3 : compressionFunction = local_LZ4_compress_withState; compressorName = "LZ4_compress_withState"; break;
|
||||
case 4 : compressionFunction = local_LZ4_compress_limitedOutput_withState; compressorName = "LZ4_compress_limitedOutput_withState"; break;
|
||||
case 5 : compressionFunction = local_LZ4_compress_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_continue"; break;
|
||||
case 6 : compressionFunction = local_LZ4_compress_limitedOutput_continue; initFunction = LZ4_create; compressorName = "LZ4_compress_limitedOutput_continue"; break;
|
||||
case 7 : compressionFunction = LZ4_compressHC; compressorName = "LZ4_compressHC"; break;
|
||||
case 8 : compressionFunction = local_LZ4_compressHC_limitedOutput; compressorName = "LZ4_compressHC_limitedOutput"; break;
|
||||
case 9 : compressionFunction = local_LZ4_compressHC_withStateHC; compressorName = "LZ4_compressHC_withStateHC"; break;
|
||||
case 10: compressionFunction = local_LZ4_compressHC_limitedOutput_withStateHC; compressorName = "LZ4_compressHC_limitedOutput_withStateHC"; break;
|
||||
case 11: compressionFunction = local_LZ4_compressHC_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_continue"; break;
|
||||
case 12: compressionFunction = local_LZ4_compressHC_limitedOutput_continue; initFunction = LZ4_createHC; compressorName = "LZ4_compressHC_limitedOutput_continue"; break;
|
||||
case 13: compressionFunction = local_LZ4_compress_forceDict; initFunction = local_LZ4_resetDictT; compressorName = "LZ4_compress_forceDict"; break;
|
||||
case 14: compressionFunction = local_LZ4F_compressFrame; compressorName = "LZ4F_compressFrame";
|
||||
chunkP[0].origSize = (int)benchedSize; nbChunks=1;
|
||||
break;
|
||||
case 15: compressionFunction = local_LZ4_saveDict; compressorName = "LZ4_saveDict";
|
||||
LZ4_loadDict(&LZ4_dict, chunkP[0].origBuffer, chunkP[0].origSize);
|
||||
break;
|
||||
case 16: compressionFunction = local_LZ4_saveDictHC; compressorName = "LZ4_saveDictHC";
|
||||
LZ4_loadDictHC(&LZ4_dictHC, chunkP[0].origBuffer, chunkP[0].origSize);
|
||||
break;
|
||||
default : DISPLAY("ERROR ! Bad algorithm Id !! \n"); free(chunkP); return 1;
|
||||
}
|
||||
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
double averageTime;
|
||||
int milliTime;
|
||||
|
||||
PROGRESS("%1i- %-28.28s :%9i ->\r", loopNb, compressorName, (int)benchedSize);
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) compressed_buff[i]=(char)i; } // warming up memory
|
||||
|
||||
nb_loops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
if (initFunction!=NULL) ctx = initFunction(chunkP[0].origBuffer);
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
chunkP[chunkNb].compressedSize = compressionFunction(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", compressorName), exit(1);
|
||||
}
|
||||
if (initFunction!=NULL) free(ctx);
|
||||
nb_loops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
averageTime = (double)milliTime / nb_loops;
|
||||
if (averageTime < bestTime) bestTime = averageTime;
|
||||
cSize=0; for (chunkNb=0; chunkNb<nbChunks; chunkNb++) cSize += chunkP[chunkNb].compressedSize;
|
||||
ratio = (double)cSize/(double)benchedSize*100.;
|
||||
PROGRESS("%1i- %-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\r", loopNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
}
|
||||
|
||||
if (ratio<100.)
|
||||
DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.2f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
else
|
||||
DISPLAY("%2i-%-28.28s :%9i ->%9i (%5.1f%%),%7.1f MB/s\n", cAlgNb, compressorName, (int)benchedSize, (int)cSize, ratio, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
totalCTime[cAlgNb] += bestTime;
|
||||
totalCSize[cAlgNb] += cSize;
|
||||
}
|
||||
|
||||
// Prepare layout for decompression
|
||||
// Init data chunks
|
||||
{
|
||||
int i;
|
||||
size_t remaining = benchedSize;
|
||||
char* in = orig_buff;
|
||||
char* out = compressed_buff;
|
||||
nbChunks = (int) (((int)benchedSize + (chunkSize-1))/ chunkSize);
|
||||
for (i=0; i<nbChunks; i++)
|
||||
{
|
||||
chunkP[i].id = i;
|
||||
chunkP[i].origBuffer = in; in += chunkSize;
|
||||
if ((int)remaining > chunkSize) { chunkP[i].origSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].origSize = (int)remaining; remaining = 0; }
|
||||
chunkP[i].compressedBuffer = out; out += maxCompressedChunkSize;
|
||||
chunkP[i].compressedSize = 0;
|
||||
}
|
||||
}
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
chunkP[chunkNb].compressedSize = LZ4_compress(chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].compressedSize==0) DISPLAY("ERROR ! %s() = 0 !! \n", "LZ4_compress"), exit(1);
|
||||
}
|
||||
|
||||
// Decompression Algorithms
|
||||
for (dAlgNb=1; (dAlgNb <= NB_DECOMPRESSION_ALGORITHMS) && (decompressionTest); dAlgNb++)
|
||||
{
|
||||
//const char* dName = decompressionNames[dAlgNb];
|
||||
const char* dName;
|
||||
int (*decompressionFunction)(const char*, char*, int, int);
|
||||
double bestTime = 100000000.;
|
||||
|
||||
if ((decompressionAlgo != ALL_DECOMPRESSORS) && (decompressionAlgo != dAlgNb)) continue;
|
||||
|
||||
switch(dAlgNb)
|
||||
{
|
||||
case 1: decompressionFunction = local_LZ4_decompress_fast; dName = "LZ4_decompress_fast"; break;
|
||||
case 2: decompressionFunction = local_LZ4_decompress_fast_withPrefix64k; dName = "LZ4_decompress_fast_withPrefix64k"; break;
|
||||
case 3: decompressionFunction = local_LZ4_decompress_fast_usingDict; dName = "LZ4_decompress_fast_usingDict"; break;
|
||||
case 4: decompressionFunction = LZ4_decompress_safe; dName = "LZ4_decompress_safe"; break;
|
||||
case 5: decompressionFunction = LZ4_decompress_safe_withPrefix64k; dName = "LZ4_decompress_safe_withPrefix64k"; break;
|
||||
case 6: decompressionFunction = local_LZ4_decompress_safe_usingDict; dName = "LZ4_decompress_safe_usingDict"; break;
|
||||
case 7: decompressionFunction = local_LZ4_decompress_safe_partial; dName = "LZ4_decompress_safe_partial"; break;
|
||||
case 8: decompressionFunction = local_LZ4_decompress_safe_forceExtDict; dName = "LZ4_decompress_safe_forceExtDict"; break;
|
||||
case 9: decompressionFunction = local_LZ4F_decompress; dName = "LZ4F_decompress";
|
||||
errorCode = LZ4F_compressFrame(compressed_buff, compressedBuffSize, orig_buff, benchedSize, NULL);
|
||||
if (LZ4F_isError(errorCode)) { DISPLAY("Preparation error compressing frame\n"); return 1; }
|
||||
chunkP[0].origSize = (int)benchedSize;
|
||||
chunkP[0].compressedSize = (int)errorCode;
|
||||
nbChunks = 1;
|
||||
break;
|
||||
default : DISPLAY("ERROR ! Bad decompression algorithm Id !! \n"); free(chunkP); return 1;
|
||||
}
|
||||
|
||||
{ size_t i; for (i=0; i<benchedSize; i++) orig_buff[i]=0; } // zeroing source area, for CRC checking
|
||||
|
||||
for (loopNb = 1; loopNb <= nbIterations; loopNb++)
|
||||
{
|
||||
double averageTime;
|
||||
int milliTime;
|
||||
U32 crcDecoded;
|
||||
|
||||
PROGRESS("%1i- %-29.29s :%10i ->\r", loopNb, dName, (int)benchedSize);
|
||||
|
||||
nb_loops = 0;
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliStart() == milliTime);
|
||||
milliTime = BMK_GetMilliStart();
|
||||
while(BMK_GetMilliSpan(milliTime) < TIMELOOP)
|
||||
{
|
||||
for (chunkNb=0; chunkNb<nbChunks; chunkNb++)
|
||||
{
|
||||
int decodedSize = decompressionFunction(chunkP[chunkNb].compressedBuffer, chunkP[chunkNb].origBuffer, chunkP[chunkNb].compressedSize, chunkP[chunkNb].origSize);
|
||||
if (chunkP[chunkNb].origSize != decodedSize) DISPLAY("ERROR ! %s() == %i != %i !! \n", dName, decodedSize, chunkP[chunkNb].origSize), exit(1);
|
||||
}
|
||||
nb_loops++;
|
||||
}
|
||||
milliTime = BMK_GetMilliSpan(milliTime);
|
||||
|
||||
averageTime = (double)milliTime / nb_loops;
|
||||
if (averageTime < bestTime) bestTime = averageTime;
|
||||
|
||||
PROGRESS("%1i- %-29.29s :%10i -> %7.1f MB/s\r", loopNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
// CRC Checking
|
||||
crcDecoded = XXH32(orig_buff, (int)benchedSize, 0);
|
||||
if (crcOriginal!=crcDecoded) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", inFileName, (unsigned)crcOriginal, (unsigned)crcDecoded); exit(1); }
|
||||
}
|
||||
|
||||
DISPLAY("%2i-%-29.29s :%10i -> %7.1f MB/s\n", dAlgNb, dName, (int)benchedSize, (double)benchedSize / bestTime / 1000.);
|
||||
|
||||
totalDTime[dAlgNb] += bestTime;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
free(orig_buff);
|
||||
free(compressed_buff);
|
||||
free(chunkP);
|
||||
}
|
||||
|
||||
if (BMK_pause) { printf("press enter...\n"); getchar(); }
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int usage(char* exename)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [arg] file1 file2 ... fileX\n", exename);
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -c : compression tests only\n");
|
||||
DISPLAY( " -d : decompression tests only\n");
|
||||
DISPLAY( " -H/-h : Help (this text + advanced options)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int usage_advanced(void)
|
||||
{
|
||||
DISPLAY( "\nAdvanced options :\n");
|
||||
DISPLAY( " -c# : test only compression function # [1-%i]\n", NB_COMPRESSION_ALGORITHMS);
|
||||
DISPLAY( " -d# : test only decompression function # [1-%i]\n", NB_DECOMPRESSION_ALGORITHMS);
|
||||
DISPLAY( " -i# : iteration loops [1-9](default : %i)\n", NBLOOPS);
|
||||
DISPLAY( " -B# : Block size [4-7](default : 7)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int badusage(char* exename)
|
||||
{
|
||||
DISPLAY("Wrong parameters\n");
|
||||
usage(exename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i,
|
||||
filenamesStart=2;
|
||||
char* exename=argv[0];
|
||||
char* input_filename=0;
|
||||
|
||||
// Welcome message
|
||||
DISPLAY(WELCOME_MESSAGE);
|
||||
|
||||
if (argc<2) { badusage(exename); return 1; }
|
||||
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
char* argument = argv[i];
|
||||
|
||||
if(!argument) continue; // Protection if argument empty
|
||||
if (!strcmp(argument, "--no-prompt"))
|
||||
{
|
||||
no_prompt = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decode command (note : aggregated commands are allowed)
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
argument ++;
|
||||
|
||||
switch(argument[0])
|
||||
{
|
||||
// Select compression algorithm only
|
||||
case 'c':
|
||||
decompressionTest = 0;
|
||||
while ((argument[1]>= '0') && (argument[1]<= '9'))
|
||||
{
|
||||
compressionAlgo *= 10;
|
||||
compressionAlgo += argument[1] - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Select decompression algorithm only
|
||||
case 'd':
|
||||
compressionTest = 0;
|
||||
while ((argument[1]>= '0') && (argument[1]<= '9'))
|
||||
{
|
||||
decompressionAlgo *= 10;
|
||||
decompressionAlgo += argument[1] - '0';
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Display help on usage
|
||||
case 'h' :
|
||||
case 'H': usage(exename); usage_advanced(); return 0;
|
||||
|
||||
// Modify Block Properties
|
||||
case 'B':
|
||||
while (argument[1]!=0)
|
||||
switch(argument[1])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int B = argument[1] - '0';
|
||||
int S = 1 << (8 + 2*B);
|
||||
BMK_SetBlocksize(S);
|
||||
argument++;
|
||||
break;
|
||||
}
|
||||
case 'D': argument++; break;
|
||||
default : goto _exit_blockProperties;
|
||||
}
|
||||
_exit_blockProperties:
|
||||
break;
|
||||
|
||||
// Modify Nb Iterations
|
||||
case 'i':
|
||||
if ((argument[1] >='1') && (argument[1] <='9'))
|
||||
{
|
||||
int iters = argument[1] - '0';
|
||||
BMK_SetNbIterations(iters);
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
// Pause at the end (hidden option)
|
||||
case 'p': BMK_SetPause(); break;
|
||||
|
||||
// Unknown command
|
||||
default : badusage(exename); return 1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// first provided filename is input
|
||||
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
|
||||
|
||||
}
|
||||
|
||||
// No input filename ==> Error
|
||||
if(!input_filename) { badusage(exename); return 1; }
|
||||
|
||||
return fullSpeedBench(argv+filenamesStart, argc-filenamesStart);
|
||||
|
||||
}
|
||||
|
||||
1167
programs/fuzzer.c
Normal file
88
programs/lz4.1
Normal file
@@ -0,0 +1,88 @@
|
||||
\"
|
||||
\" lz4.1: This is a manual page for 'lz4' program. This file is part of the
|
||||
\" lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4 "1" "2014-02-27" "lz4" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4\fR - Extremely fast compression algorithm
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4\fR [\fBOPTIONS\fR] [-|INPUT-FILE] <OUTPUT-FILE>
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4\fR is an extremely fast lossless compression algorithm. It is based on
|
||||
the \fBLZ77\fR family of compression scheme. At the compression speed of 400
|
||||
MB/s per core, \fBlz4\fR is also scalable with multi-core CPUs. It features
|
||||
an extremely fast decoder, with speed in multiple GB/s per core, typically
|
||||
reaching the RAM speed limits on multi-core systems. \fBlz4\fR supports
|
||||
following options
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-1
|
||||
fast compression (default)
|
||||
.TP
|
||||
.B \-9
|
||||
high compression
|
||||
.TP
|
||||
.B \-d
|
||||
decompression
|
||||
.TP
|
||||
.B \-f
|
||||
overwrite output without prompting
|
||||
.TP
|
||||
.B \-h/\-H
|
||||
display help/long help and exit
|
||||
.TP
|
||||
.B \-V
|
||||
display Version number and exit
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.TP
|
||||
.B \-q
|
||||
suppress warnings; specify twice to suppress errors too
|
||||
.TP
|
||||
.B \-c
|
||||
force write to standard output, even if it is the console
|
||||
.TP
|
||||
.B \-t
|
||||
test compressed file integrity
|
||||
.TP
|
||||
.B \-z
|
||||
force compression
|
||||
.TP
|
||||
.B \-l
|
||||
use Legacy format (useful for Linux Kernel compression)
|
||||
.TP
|
||||
.B \-B#
|
||||
block size [4-7](default : 7)
|
||||
B4= 64KB ; B5= 256KB ; B6= 1MB ; B7= 4MB
|
||||
.TP
|
||||
.B \-BD
|
||||
block dependency (improve compression ratio)
|
||||
.TP
|
||||
.B \-BX
|
||||
enable block checksum (default:disabled)
|
||||
.TP
|
||||
.B \-Sx
|
||||
disable stream checksum (default:enabled)
|
||||
.TP
|
||||
.B \-b
|
||||
benchmark file(s)
|
||||
.TP
|
||||
.B \-i#
|
||||
iteration loops [1-9](default : 3), benchmark mode only
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
33
programs/lz4c.1
Normal file
@@ -0,0 +1,33 @@
|
||||
\"
|
||||
\" lz4c.1: This is a manual page for 'lz4c' program. This file is part of the
|
||||
\" lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4c "1" "2014-04-15" "lz4c" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4\fR - Extremely fast compression algorithm
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4c\fR [\fBOPTIONS\fR] [-|INPUT-FILE] <OUTPUT-FILE>
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4c\fR is the legacy version of \fBlz4\fR.
|
||||
As such, it supports older supplementary legacy commands.
|
||||
\fBlz4c\fR is now deprecated.
|
||||
It is recommended to use \fBlz4\fR instead whenever possible.
|
||||
|
||||
To get a list of commands specific to lz4c, do :
|
||||
lz4c -h
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
32
programs/lz4cat.1
Normal file
@@ -0,0 +1,32 @@
|
||||
\"
|
||||
\" lz4cat.1: This is a manual page for 'lz4cat' program. This file is part of
|
||||
\" the lz4 <https://code.google.com/p/lz4/> project.
|
||||
\"
|
||||
|
||||
\" No hyphenation
|
||||
.hy 0
|
||||
.nr HY 0
|
||||
|
||||
.TH lz4cat "1" "2014-06-20" "lz4cat" "User Commands"
|
||||
.SH NAME
|
||||
\fBlz4cat\fR - Utility based on LZ4
|
||||
|
||||
.SH SYNOPSIS
|
||||
.TP 5
|
||||
\fBlz4cat\fR [\fBOPTIONS\fR] [-|INPUT-FILE]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
\fBlz4cat\fR is an utility based on \fBlz4\fR, an extremely fast lossless compression algorithm.
|
||||
|
||||
\fBlz4cat\fR decompress input file or stream, redirecting its output to the console.
|
||||
It is equivalent to \fBlz4 -cd\fR,
|
||||
|
||||
Available options are the same as \fBlz4\fR ones (man lz4).
|
||||
|
||||
|
||||
.SH BUGS
|
||||
Report bugs at:- https://code.google.com/p/lz4/
|
||||
|
||||
.SH AUTHOR
|
||||
Yann Collet
|
||||
501
programs/lz4cli.c
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
LZ4cli - LZ4 Command Line Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user program of the LZ4 library.
|
||||
The license of LZ4 library is BSD.
|
||||
The license of xxHash library is BSD.
|
||||
The license of this compression CLI program is GPLv2.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Tuning parameters
|
||||
***************************************/
|
||||
/* ENABLE_LZ4C_LEGACY_OPTIONS :
|
||||
Control the availability of -c0, -c1 and -hc legacy arguments
|
||||
Default : Legacy options are disabled */
|
||||
/* #define ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
/* Disable some Visual warning messages */
|
||||
#ifdef _MSC_VER
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#endif
|
||||
|
||||
#define _POSIX_SOURCE 1 /* for fileno() within <stdio.h> on unix */
|
||||
|
||||
|
||||
/****************************
|
||||
* Includes
|
||||
*****************************/
|
||||
#include <stdio.h> /* fprintf, getchar */
|
||||
#include <stdlib.h> /* exit, calloc, free */
|
||||
#include <string.h> /* strcmp, strlen */
|
||||
#include "bench.h" /* BMK_benchFile, BMK_SetNbIterations, BMK_SetBlocksize, BMK_SetPause */
|
||||
#include "lz4io.h"
|
||||
|
||||
|
||||
/****************************
|
||||
* OS-specific Includes
|
||||
*****************************/
|
||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <fcntl.h> /* _O_BINARY */
|
||||
# include <io.h> /* _setmode, _isatty */
|
||||
# ifdef __MINGW32__
|
||||
int _fileno(FILE *stream); /* MINGW somehow forgets to include this prototype into <stdio.h> */
|
||||
# endif
|
||||
# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)
|
||||
# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
|
||||
#else
|
||||
# include <unistd.h> /* isatty */
|
||||
# define SET_BINARY_MODE(file)
|
||||
# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************
|
||||
* Constants
|
||||
******************************/
|
||||
#define COMPRESSOR_NAME "LZ4 command line interface"
|
||||
#ifndef LZ4_VERSION
|
||||
# define LZ4_VERSION "r126"
|
||||
#endif
|
||||
#define AUTHOR "Yann Collet"
|
||||
#define WELCOME_MESSAGE "*** %s %i-bits %s, by %s (%s) ***\n", COMPRESSOR_NAME, (int)(sizeof(void*)*8), LZ4_VERSION, AUTHOR, __DATE__
|
||||
#define LZ4_EXTENSION ".lz4"
|
||||
#define LZ4_CAT "lz4cat"
|
||||
|
||||
#define KB *(1U<<10)
|
||||
#define MB *(1U<<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define LZ4_BLOCKSIZEID_DEFAULT 7
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
static unsigned displayLevel = 2; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local Variables
|
||||
***************************************/
|
||||
static char* programName;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Exceptions
|
||||
***************************************/
|
||||
#define DEBUG 0
|
||||
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", error); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, "\n"); \
|
||||
exit(error); \
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Version modifiers
|
||||
***************************************/
|
||||
#define EXTENDED_ARGUMENTS
|
||||
#define EXTENDED_HELP
|
||||
#define EXTENDED_FORMAT
|
||||
#define DEFAULT_COMPRESSOR LZ4IO_compressFilename
|
||||
#define DEFAULT_DECOMPRESSOR LZ4IO_decompressFilename
|
||||
int LZ4IO_compressFilename_Legacy(char* input_filename, char* output_filename, int compressionlevel); /* hidden function */
|
||||
|
||||
|
||||
/****************************
|
||||
* Functions
|
||||
*****************************/
|
||||
static int usage(void)
|
||||
{
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [arg] [input] [output]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "input : a filename\n");
|
||||
DISPLAY( " with no FILE, or when FILE is - or %s, read standard input\n", stdinmark);
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -1 : Fast compression (default) \n");
|
||||
DISPLAY( " -9 : High compression \n");
|
||||
DISPLAY( " -d : decompression (default for %s extension)\n", LZ4_EXTENSION);
|
||||
DISPLAY( " -z : force compression\n");
|
||||
DISPLAY( " -f : overwrite output without prompting \n");
|
||||
DISPLAY( " -h/-H : display help/long help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage_advanced(void)
|
||||
{
|
||||
DISPLAY(WELCOME_MESSAGE);
|
||||
usage();
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Advanced arguments :\n");
|
||||
DISPLAY( " -V : display Version number and exit\n");
|
||||
DISPLAY( " -v : verbose mode\n");
|
||||
DISPLAY( " -q : suppress warnings; specify twice to suppress errors too\n");
|
||||
DISPLAY( " -c : force write to standard output, even if it is the console\n");
|
||||
DISPLAY( " -t : test compressed file integrity\n");
|
||||
DISPLAY( " -l : compress using Legacy format (Linux kernel compression)\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( " -Sx : disable stream checksum (default:enabled)\n");
|
||||
DISPLAY( "Benchmark arguments :\n");
|
||||
DISPLAY( " -b : benchmark file(s)\n");
|
||||
DISPLAY( " -i# : iteration loops [1-9](default : 3), benchmark mode only\n");
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
DISPLAY( "Legacy arguments :\n");
|
||||
DISPLAY( " -c0 : fast compression\n");
|
||||
DISPLAY( " -c1 : high compression\n");
|
||||
DISPLAY( " -hc : high compression\n");
|
||||
DISPLAY( " -y : overwrite output without prompting \n");
|
||||
DISPLAY( " -s : suppress warnings \n");
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
EXTENDED_HELP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usage_longhelp(void)
|
||||
{
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Which values can get [output] ? \n");
|
||||
DISPLAY( "[output] : a filename\n");
|
||||
DISPLAY( " '%s', or '-' for standard output (pipe mode)\n", stdoutmark);
|
||||
DISPLAY( " '%s' to discard output (test mode)\n", NULL_OUTPUT);
|
||||
DISPLAY( "[output] can be left empty. In this case, it receives the following value : \n");
|
||||
DISPLAY( " - if stdout is not the console, then [output] = stdout \n");
|
||||
DISPLAY( " - if stdout is console : \n");
|
||||
DISPLAY( " + if compression selected, output to filename%s \n", LZ4_EXTENSION);
|
||||
DISPLAY( " + if decompression selected, output to filename without '%s'\n", LZ4_EXTENSION);
|
||||
DISPLAY( " > if input filename has no '%s' extension : error\n", LZ4_EXTENSION);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Compression levels : \n");
|
||||
DISPLAY( "There are technically 2 accessible compression levels.\n");
|
||||
DISPLAY( "-0 ... -2 => Fast compression\n");
|
||||
DISPLAY( "-3 ... -9 => High compression\n");
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "stdin, stdout and the console : \n");
|
||||
DISPLAY( "To protect the console from binary flooding (bad argument mistake)\n");
|
||||
DISPLAY( "%s will refuse to read from console, or write to console \n", programName);
|
||||
DISPLAY( "except if '-c' command is specified, to force output to console \n");
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Simple example :\n");
|
||||
DISPLAY( "1 : compress 'filename' fast, using default output name 'filename.lz4'\n");
|
||||
DISPLAY( " %s filename\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments can be appended together, or provided independently. For example :\n");
|
||||
DISPLAY( "2 : compress 'filename' in high compression mode, overwrite output if exists\n");
|
||||
DISPLAY( " %s -f9 filename \n", programName);
|
||||
DISPLAY( " is equivalent to :\n");
|
||||
DISPLAY( " %s -f -9 filename \n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "%s can be used in 'pure pipe mode', for example :\n", programName);
|
||||
DISPLAY( "3 : compress data stream from 'generator', send result to 'consumer'\n");
|
||||
DISPLAY( " generator | %s | consumer \n", programName);
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Warning :\n");
|
||||
DISPLAY( "Legacy arguments take precedence. Therefore : \n");
|
||||
DISPLAY( " %s -hc filename\n", programName);
|
||||
DISPLAY( "means 'compress filename in high compression mode'\n");
|
||||
DISPLAY( "It is not equivalent to :\n");
|
||||
DISPLAY( " %s -h -c filename\n", programName);
|
||||
DISPLAY( "which would display help text and exit\n");
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int badusage(void)
|
||||
{
|
||||
DISPLAYLEVEL(1, "Incorrect parameters\n");
|
||||
if (displayLevel >= 1) usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
static void waitEnter(void)
|
||||
{
|
||||
DISPLAY("Press enter to continue...\n");
|
||||
getchar();
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int i,
|
||||
cLevel=0,
|
||||
decode=0,
|
||||
bench=0,
|
||||
filenamesStart=2,
|
||||
legacy_format=0,
|
||||
forceStdout=0,
|
||||
forceCompress=0,
|
||||
main_pause=0;
|
||||
char* input_filename=0;
|
||||
char* output_filename=0;
|
||||
char* dynNameSpace=0;
|
||||
char nullOutput[] = NULL_OUTPUT;
|
||||
char extension[] = LZ4_EXTENSION;
|
||||
int blockSize;
|
||||
|
||||
/* Init */
|
||||
programName = argv[0];
|
||||
LZ4IO_setOverwrite(0);
|
||||
blockSize = LZ4IO_setBlockSizeID(LZ4_BLOCKSIZEID_DEFAULT);
|
||||
|
||||
/* lz4cat behavior */
|
||||
if (!strcmp(programName, LZ4_CAT)) { decode=1; forceStdout=1; output_filename=stdoutmark; displayLevel=1; }
|
||||
|
||||
/* command switches */
|
||||
for(i=1; i<argc; i++)
|
||||
{
|
||||
char* argument = argv[i];
|
||||
|
||||
if(!argument) continue; /* Protection if argument empty */
|
||||
|
||||
/* Decode command (note : aggregated commands are allowed) */
|
||||
if (argument[0]=='-')
|
||||
{
|
||||
/* '-' means stdin/stdout */
|
||||
if (argument[1]==0)
|
||||
{
|
||||
if (!input_filename) input_filename=stdinmark;
|
||||
else output_filename=stdoutmark;
|
||||
}
|
||||
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
argument ++;
|
||||
|
||||
#if defined(ENABLE_LZ4C_LEGACY_OPTIONS)
|
||||
/* Legacy arguments (-c0, -c1, -hc, -y, -s) */
|
||||
if ((argument[0]=='c') && (argument[1]=='0')) { cLevel=0; argument++; continue; } /* -c0 (fast compression) */
|
||||
if ((argument[0]=='c') && (argument[1]=='1')) { cLevel=9; argument++; continue; } /* -c1 (high compression) */
|
||||
if ((argument[0]=='h') && (argument[1]=='c')) { cLevel=9; argument++; continue; } /* -hc (high compression) */
|
||||
if (*argument=='y') { LZ4IO_setOverwrite(1); continue; } /* -y (answer 'yes' to overwrite permission) */
|
||||
if (*argument=='s') { displayLevel=1; continue; } /* -s (silent mode) */
|
||||
#endif /* ENABLE_LZ4C_LEGACY_OPTIONS */
|
||||
|
||||
if ((*argument>='0') && (*argument<='9'))
|
||||
{
|
||||
cLevel = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
{
|
||||
cLevel *= 10;
|
||||
cLevel += *argument - '0';
|
||||
argument++;
|
||||
}
|
||||
argument--;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch(argument[0])
|
||||
{
|
||||
/* Display help */
|
||||
case 'V': DISPLAY(WELCOME_MESSAGE); return 0; /* Version */
|
||||
case 'h': usage_advanced(); return 0;
|
||||
case 'H': usage_advanced(); usage_longhelp(); return 0;
|
||||
|
||||
/* Compression (default) */
|
||||
case 'z': forceCompress = 1; break;
|
||||
|
||||
/* Use Legacy format (ex : Linux kernel compression) */
|
||||
case 'l': legacy_format = 1; blockSize = 8 MB; break;
|
||||
|
||||
/* Decoding */
|
||||
case 'd': decode=1; break;
|
||||
|
||||
/* Force stdout, even if stdout==console */
|
||||
case 'c': forceStdout=1; output_filename=stdoutmark; displayLevel=1; break;
|
||||
|
||||
/* Test integrity */
|
||||
case 't': decode=1; LZ4IO_setOverwrite(1); output_filename=nulmark; break;
|
||||
|
||||
/* Overwrite */
|
||||
case 'f': LZ4IO_setOverwrite(1); break;
|
||||
|
||||
/* Verbose mode */
|
||||
case 'v': displayLevel=4; break;
|
||||
|
||||
/* Quiet mode */
|
||||
case 'q': displayLevel--; break;
|
||||
|
||||
/* keep source file (default anyway, so useless) (for xz/lzma compatibility) */
|
||||
case 'k': break;
|
||||
|
||||
/* Modify Block Properties */
|
||||
case 'B':
|
||||
while (argument[1]!=0)
|
||||
{
|
||||
int exitBlockProperties=0;
|
||||
switch(argument[1])
|
||||
{
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
{
|
||||
int B = argument[1] - '0';
|
||||
blockSize = LZ4IO_setBlockSizeID(B);
|
||||
BMK_SetBlocksize(blockSize);
|
||||
argument++;
|
||||
break;
|
||||
}
|
||||
case 'D': LZ4IO_setBlockMode(LZ4IO_blockLinked); argument++; break;
|
||||
case 'X': LZ4IO_setBlockChecksumMode(1); argument ++; break; /* currently disables */
|
||||
default : exitBlockProperties=1;
|
||||
}
|
||||
if (exitBlockProperties) break;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Modify Stream properties */
|
||||
case 'S': if (argument[1]=='x') { LZ4IO_setStreamChecksumMode(0); argument++; break; } else { badusage(); }
|
||||
|
||||
/* Benchmark */
|
||||
case 'b': bench=1; break;
|
||||
|
||||
/* Modify Nb Iterations (benchmark only) */
|
||||
case 'i':
|
||||
if ((argument[1] >='1') && (argument[1] <='9'))
|
||||
{
|
||||
int iters = argument[1] - '0';
|
||||
BMK_SetNbIterations(iters);
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Pause at the end (hidden option) */
|
||||
case 'p': main_pause=1; BMK_SetPause(); break;
|
||||
|
||||
/* Specific commands for customized versions */
|
||||
EXTENDED_ARGUMENTS;
|
||||
|
||||
/* Unrecognised command */
|
||||
default : badusage();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* first provided filename is input */
|
||||
if (!input_filename) { input_filename=argument; filenamesStart=i; continue; }
|
||||
|
||||
/* second provided filename is output */
|
||||
if (!output_filename)
|
||||
{
|
||||
output_filename=argument;
|
||||
if (!strcmp (output_filename, nullOutput)) output_filename = nulmark;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, WELCOME_MESSAGE);
|
||||
if (!decode) DISPLAYLEVEL(4, "Blocks size : %i KB\n", blockSize>>10);
|
||||
|
||||
/* No input filename ==> use stdin */
|
||||
if(!input_filename) { input_filename=stdinmark; }
|
||||
|
||||
/* Check if input or output are defined as console; trigger an error in this case */
|
||||
if (!strcmp(input_filename, stdinmark) && IS_CONSOLE(stdin) ) badusage();
|
||||
|
||||
/* Check if benchmark is selected */
|
||||
if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel);
|
||||
|
||||
/* No output filename ==> try to select one automatically (when possible) */
|
||||
while (!output_filename)
|
||||
{
|
||||
if (!IS_CONSOLE(stdout)) { output_filename=stdoutmark; break; } /* Default to stdout whenever possible (i.e. not a console) */
|
||||
if ((!decode) && !(forceCompress)) /* auto-determine compression or decompression, based on file extension */
|
||||
{
|
||||
size_t l = strlen(input_filename);
|
||||
if (!strcmp(input_filename+(l-4), LZ4_EXTENSION)) decode=1;
|
||||
}
|
||||
if (!decode) /* compression to file */
|
||||
{
|
||||
size_t l = strlen(input_filename);
|
||||
dynNameSpace = (char*)calloc(1,l+5);
|
||||
output_filename = dynNameSpace;
|
||||
strcpy(output_filename, input_filename);
|
||||
strcpy(output_filename+l, LZ4_EXTENSION);
|
||||
DISPLAYLEVEL(2, "Compressed filename will be : %s \n", output_filename);
|
||||
break;
|
||||
}
|
||||
/* decompression to file (automatic name will work only if input filename has correct format extension) */
|
||||
{
|
||||
size_t outl;
|
||||
size_t inl = strlen(input_filename);
|
||||
dynNameSpace = (char*)calloc(1,inl+1);
|
||||
output_filename = dynNameSpace;
|
||||
strcpy(output_filename, input_filename);
|
||||
outl = inl;
|
||||
if (inl>4)
|
||||
while ((outl >= inl-4) && (input_filename[outl] == extension[outl-inl+4])) output_filename[outl--]=0;
|
||||
if (outl != inl-5) { DISPLAYLEVEL(1, "Cannot determine an output filename\n"); badusage(); }
|
||||
DISPLAYLEVEL(2, "Decoding file %s \n", output_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if output is defined as console; trigger an error in this case */
|
||||
if (!strcmp(output_filename,stdoutmark) && IS_CONSOLE(stdout) && !forceStdout) badusage();
|
||||
|
||||
/* No warning message in pure pipe mode (stdin + stdout) */
|
||||
if (!strcmp(input_filename, stdinmark) && !strcmp(output_filename,stdoutmark) && (displayLevel==2)) displayLevel=1;
|
||||
|
||||
|
||||
/* IO Stream/File */
|
||||
LZ4IO_setNotificationLevel(displayLevel);
|
||||
if (decode) DEFAULT_DECOMPRESSOR(input_filename, output_filename);
|
||||
else
|
||||
{
|
||||
/* compression is default action */
|
||||
if (legacy_format)
|
||||
{
|
||||
DISPLAYLEVEL(3, "! Generating compressed LZ4 using Legacy format (deprecated) ! \n");
|
||||
LZ4IO_compressFilename_Legacy(input_filename, output_filename, cLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEFAULT_COMPRESSOR(input_filename, output_filename, cLevel);
|
||||
}
|
||||
}
|
||||
|
||||
if (main_pause) waitEnter();
|
||||
free(dynNameSpace);
|
||||
return 0;
|
||||
}
|
||||
669
programs/lz4io.c
Normal file
@@ -0,0 +1,669 @@
|
||||
/*
|
||||
LZ4io.c - LZ4 File/Stream Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user code of the LZ4 library.
|
||||
- The license of LZ4 library is BSD.
|
||||
- The license of xxHash library is BSD.
|
||||
- The license of this source file is GPLv2.
|
||||
*/
|
||||
|
||||
/**************************************
|
||||
* Compiler Options
|
||||
***************************************/
|
||||
#ifdef _MSC_VER /* Visual Studio */
|
||||
# define _CRT_SECURE_NO_WARNINGS
|
||||
# define _CRT_SECURE_NO_DEPRECATE /* VS2005 */
|
||||
# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
|
||||
#endif
|
||||
|
||||
#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic ignored "-Wmissing-braces" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
# pragma GCC diagnostic ignored "-Wmissing-field-initializers" /* GCC bug 53119 : doesn't accept { 0 } as initializer (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119) */
|
||||
#endif
|
||||
|
||||
#define _LARGE_FILES /* Large file support on 32-bits AIX */
|
||||
#define _FILE_OFFSET_BITS 64 /* Large file support on 32-bits unix */
|
||||
#define _POSIX_SOURCE 1 /* for fileno() within <stdio.h> on unix */
|
||||
|
||||
|
||||
/****************************
|
||||
* Includes
|
||||
*****************************/
|
||||
#include <stdio.h> /* fprintf, fopen, fread, _fileno, stdin, stdout */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* strcmp, strlen */
|
||||
#include <time.h> /* clock */
|
||||
#include "lz4io.h"
|
||||
#include "lz4.h" /* still required for legacy format */
|
||||
#include "lz4hc.h" /* still required for legacy format */
|
||||
#include "lz4frame.h"
|
||||
|
||||
|
||||
/****************************
|
||||
* OS-specific Includes
|
||||
*****************************/
|
||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
|
||||
# include <fcntl.h> /* _O_BINARY */
|
||||
# include <io.h> /* _setmode, _isatty */
|
||||
# ifdef __MINGW32__
|
||||
int _fileno(FILE *stream); /* MINGW somehow forgets to include this windows declaration into <stdio.h> */
|
||||
# endif
|
||||
# define SET_BINARY_MODE(file) _setmode(_fileno(file), _O_BINARY)
|
||||
# define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
|
||||
#else
|
||||
# include <unistd.h> /* isatty */
|
||||
# define SET_BINARY_MODE(file)
|
||||
# define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
|
||||
#endif
|
||||
|
||||
|
||||
/****************************
|
||||
* Constants
|
||||
*****************************/
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
|
||||
#define _1BIT 0x01
|
||||
#define _2BITS 0x03
|
||||
#define _3BITS 0x07
|
||||
#define _4BITS 0x0F
|
||||
#define _8BITS 0xFF
|
||||
|
||||
#define MAGICNUMBER_SIZE 4
|
||||
#define LZ4S_MAGICNUMBER 0x184D2204
|
||||
#define LZ4S_SKIPPABLE0 0x184D2A50
|
||||
#define LZ4S_SKIPPABLEMASK 0xFFFFFFF0
|
||||
#define LEGACY_MAGICNUMBER 0x184C2102
|
||||
|
||||
#define CACHELINE 64
|
||||
#define LEGACY_BLOCKSIZE (8 MB)
|
||||
#define MIN_STREAM_BUFSIZE (192 KB)
|
||||
#define LZ4S_BLOCKSIZEID_DEFAULT 7
|
||||
#define LZ4S_CHECKSUM_SEED 0
|
||||
#define LZ4S_EOS 0
|
||||
#define LZ4S_MAXHEADERSIZE (MAGICNUMBER_SIZE+2+8+4+1)
|
||||
|
||||
|
||||
/**************************************
|
||||
* Macros
|
||||
***************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
#define DISPLAYUPDATE(l, ...) if (displayLevel>=l) { \
|
||||
if ((LZ4IO_GetMilliSpan(g_time) > refreshRate) || (displayLevel>=4)) \
|
||||
{ g_time = clock(); DISPLAY(__VA_ARGS__); \
|
||||
if (displayLevel>=4) fflush(stdout); } }
|
||||
static const unsigned refreshRate = 150;
|
||||
static clock_t g_time = 0;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Local Parameters
|
||||
***************************************/
|
||||
static int displayLevel = 0; /* 0 : no display ; 1: errors ; 2 : + result + interaction + warnings ; 3 : + progression; 4 : + information */
|
||||
static int overwrite = 1;
|
||||
static int globalBlockSizeId = LZ4S_BLOCKSIZEID_DEFAULT;
|
||||
static int blockChecksum = 0;
|
||||
static int streamChecksum = 1;
|
||||
static int blockIndependence = 1;
|
||||
|
||||
static const int minBlockSizeID = 4;
|
||||
static const int maxBlockSizeID = 7;
|
||||
|
||||
|
||||
/**************************************
|
||||
* Exceptions
|
||||
***************************************/
|
||||
#define DEBUG 0
|
||||
#define DEBUGOUTPUT(...) if (DEBUG) DISPLAY(__VA_ARGS__);
|
||||
#define EXM_THROW(error, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("Error defined at %s, line %i : \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", error); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, "\n"); \
|
||||
exit(error); \
|
||||
}
|
||||
|
||||
|
||||
/**************************************
|
||||
* Version modifiers
|
||||
***************************************/
|
||||
#define EXTENDED_ARGUMENTS
|
||||
#define EXTENDED_HELP
|
||||
#define EXTENDED_FORMAT
|
||||
#define DEFAULT_COMPRESSOR compress_file
|
||||
#define DEFAULT_DECOMPRESSOR decodeLZ4S
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Parameters ******************** */
|
||||
/* ************************************************** */
|
||||
|
||||
/* Default setting : overwrite = 1; return : overwrite mode (0/1) */
|
||||
int LZ4IO_setOverwrite(int yes)
|
||||
{
|
||||
overwrite = (yes!=0);
|
||||
return overwrite;
|
||||
}
|
||||
|
||||
/* blockSizeID : valid values : 4-5-6-7 */
|
||||
int LZ4IO_setBlockSizeID(int bsid)
|
||||
{
|
||||
static const int blockSizeTable[] = { 64 KB, 256 KB, 1 MB, 4 MB };
|
||||
if ((bsid < minBlockSizeID) || (bsid > maxBlockSizeID)) return -1;
|
||||
globalBlockSizeId = bsid;
|
||||
return blockSizeTable[globalBlockSizeId-minBlockSizeID];
|
||||
}
|
||||
|
||||
int LZ4IO_setBlockMode(LZ4IO_blockMode_t blockMode)
|
||||
{
|
||||
blockIndependence = (blockMode == LZ4IO_blockIndependent);
|
||||
return blockIndependence;
|
||||
}
|
||||
|
||||
/* Default setting : no checksum */
|
||||
int LZ4IO_setBlockChecksumMode(int xxhash)
|
||||
{
|
||||
blockChecksum = (xxhash != 0);
|
||||
return blockChecksum;
|
||||
}
|
||||
|
||||
/* Default setting : checksum enabled */
|
||||
int LZ4IO_setStreamChecksumMode(int xxhash)
|
||||
{
|
||||
streamChecksum = (xxhash != 0);
|
||||
return streamChecksum;
|
||||
}
|
||||
|
||||
/* Default setting : 0 (no notification) */
|
||||
int LZ4IO_setNotificationLevel(int level)
|
||||
{
|
||||
displayLevel = level;
|
||||
return displayLevel;
|
||||
}
|
||||
|
||||
static unsigned LZ4IO_GetMilliSpan(clock_t nPrevious)
|
||||
{
|
||||
clock_t nCurrent = clock();
|
||||
unsigned nSpan = (unsigned)(((nCurrent - nPrevious) * 1000) / CLOCKS_PER_SEC);
|
||||
return nSpan;
|
||||
}
|
||||
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* ********************** LZ4 File / Pipe compression ********************* */
|
||||
/* ************************************************************************ */
|
||||
|
||||
static int LZ4S_GetBlockSize_FromBlockId (int id) { return (1 << (8 + (2 * id))); }
|
||||
static int LZ4S_isSkippableMagicNumber(unsigned int magic) { return (magic & LZ4S_SKIPPABLEMASK) == LZ4S_SKIPPABLE0; }
|
||||
|
||||
|
||||
static int get_fileHandle(char* input_filename, char* output_filename, FILE** pfinput, FILE** pfoutput)
|
||||
{
|
||||
|
||||
if (!strcmp (input_filename, stdinmark))
|
||||
{
|
||||
DISPLAYLEVEL(4,"Using stdin for input\n");
|
||||
*pfinput = stdin;
|
||||
SET_BINARY_MODE(stdin);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pfinput = fopen(input_filename, "rb");
|
||||
}
|
||||
|
||||
if (!strcmp (output_filename, stdoutmark))
|
||||
{
|
||||
DISPLAYLEVEL(4,"Using stdout for output\n");
|
||||
*pfoutput = stdout;
|
||||
SET_BINARY_MODE(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if destination file already exists */
|
||||
*pfoutput=0;
|
||||
if (output_filename != nulmark) *pfoutput = fopen( output_filename, "rb" );
|
||||
if (*pfoutput!=0)
|
||||
{
|
||||
fclose(*pfoutput);
|
||||
if (!overwrite)
|
||||
{
|
||||
char ch;
|
||||
DISPLAYLEVEL(2, "Warning : %s already exists\n", output_filename);
|
||||
DISPLAYLEVEL(2, "Overwrite ? (Y/N) : ");
|
||||
if (displayLevel <= 1) EXM_THROW(11, "Operation aborted : %s already exists", output_filename); /* No interaction possible */
|
||||
ch = (char)getchar();
|
||||
if ((ch!='Y') && (ch!='y')) EXM_THROW(11, "Operation aborted : %s already exists", output_filename);
|
||||
}
|
||||
}
|
||||
*pfoutput = fopen( output_filename, "wb" );
|
||||
}
|
||||
|
||||
if ( *pfinput==0 ) EXM_THROW(12, "Pb opening %s", input_filename);
|
||||
if ( *pfoutput==0) EXM_THROW(13, "Pb opening %s", output_filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************
|
||||
* Legacy Compression
|
||||
* *************************************/
|
||||
|
||||
/* unoptimized version; solves endianess & alignment issues */
|
||||
static void LZ4IO_writeLE32 (void* p, unsigned value32)
|
||||
{
|
||||
unsigned char* dstPtr = p;
|
||||
dstPtr[0] = (unsigned char)value32;
|
||||
dstPtr[1] = (unsigned char)(value32 >> 8);
|
||||
dstPtr[2] = (unsigned char)(value32 >> 16);
|
||||
dstPtr[3] = (unsigned char)(value32 >> 24);
|
||||
}
|
||||
|
||||
/* LZ4IO_compressFilename_Legacy :
|
||||
* This function is intentionally "hidden" (not published in .h)
|
||||
* It generates compressed streams using the old 'legacy' format */
|
||||
int LZ4IO_compressFilename_Legacy(char* input_filename, char* output_filename, int compressionlevel)
|
||||
{
|
||||
int (*compressionFunction)(const char*, char*, int);
|
||||
unsigned long long filesize = 0;
|
||||
unsigned long long compressedfilesize = MAGICNUMBER_SIZE;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
size_t sizeCheck;
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
if (compressionlevel < 3) compressionFunction = LZ4_compress; else compressionFunction = LZ4_compressHC;
|
||||
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
if ((displayLevel==2) && (compressionlevel==1)) displayLevel=3;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(LEGACY_BLOCKSIZE);
|
||||
out_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));
|
||||
if (!in_buff || !out_buff) EXM_THROW(21, "Allocation error : not enough memory");
|
||||
|
||||
/* Write Archive Header */
|
||||
LZ4IO_writeLE32(out_buff, LEGACY_MAGICNUMBER);
|
||||
sizeCheck = fwrite(out_buff, 1, MAGICNUMBER_SIZE, foutput);
|
||||
if (sizeCheck!=MAGICNUMBER_SIZE) EXM_THROW(22, "Write error : cannot write header");
|
||||
|
||||
/* Main Loop */
|
||||
while (1)
|
||||
{
|
||||
unsigned int outSize;
|
||||
/* Read Block */
|
||||
int inSize = (int) fread(in_buff, (size_t)1, (size_t)LEGACY_BLOCKSIZE, finput);
|
||||
if( inSize<=0 ) break;
|
||||
filesize += inSize;
|
||||
|
||||
/* Compress Block */
|
||||
outSize = compressionFunction(in_buff, out_buff+4, inSize);
|
||||
compressedfilesize += outSize+4;
|
||||
DISPLAYUPDATE(3, "\rRead : %i MB ==> %.2f%% ", (int)(filesize>>20), (double)compressedfilesize/filesize*100);
|
||||
|
||||
/* Write Block */
|
||||
LZ4IO_writeLE32(out_buff, outSize);
|
||||
sizeCheck = fwrite(out_buff, 1, outSize+4, foutput);
|
||||
if (sizeCheck!=(size_t)(outSize+4)) EXM_THROW(23, "Write error : cannot write compressed block");
|
||||
}
|
||||
|
||||
/* Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2,"Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
|
||||
(unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4,"Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
/* Close & Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************
|
||||
* Compression using Frame format
|
||||
* ********************************************/
|
||||
|
||||
int LZ4IO_compressFilename(char* input_filename, char* output_filename, int compressionLevel)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
unsigned long long compressedfilesize = 0;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
int blockSize;
|
||||
size_t sizeCheck, headerSize, readSize, outBuffSize;
|
||||
LZ4F_compressionContext_t ctx;
|
||||
LZ4F_errorCode_t errorCode;
|
||||
LZ4F_preferences_t prefs = {0};
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
if ((displayLevel==2) && (compressionLevel>=3)) displayLevel=3;
|
||||
errorCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(30, "Allocation error : can't create LZ4F context : %s", LZ4F_getErrorName(errorCode));
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
blockSize = LZ4S_GetBlockSize_FromBlockId (globalBlockSizeId);
|
||||
|
||||
/* Set compression parameters */
|
||||
prefs.autoFlush = 1;
|
||||
prefs.compressionLevel = compressionLevel;
|
||||
prefs.frameInfo.blockMode = blockIndependence;
|
||||
prefs.frameInfo.blockSizeID = globalBlockSizeId;
|
||||
prefs.frameInfo.contentChecksumFlag = streamChecksum;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(blockSize);
|
||||
outBuffSize = LZ4F_compressBound(blockSize, &prefs);
|
||||
out_buff = (char*)malloc(outBuffSize);
|
||||
if (!in_buff || !out_buff) EXM_THROW(31, "Allocation error : not enough memory");
|
||||
|
||||
/* Write Archive Header */
|
||||
headerSize = LZ4F_compressBegin(ctx, out_buff, outBuffSize, &prefs);
|
||||
if (LZ4F_isError(headerSize)) EXM_THROW(32, "File header generation failed : %s", LZ4F_getErrorName(headerSize));
|
||||
sizeCheck = fwrite(out_buff, 1, headerSize, foutput);
|
||||
if (sizeCheck!=headerSize) EXM_THROW(33, "Write error : cannot write header");
|
||||
compressedfilesize += headerSize;
|
||||
|
||||
/* read first block */
|
||||
readSize = fread(in_buff, (size_t)1, (size_t)blockSize, finput);
|
||||
filesize += readSize;
|
||||
|
||||
/* Main Loop */
|
||||
while (readSize>0)
|
||||
{
|
||||
size_t outSize;
|
||||
|
||||
/* Compress Block */
|
||||
outSize = LZ4F_compressUpdate(ctx, out_buff, outBuffSize, in_buff, readSize, NULL);
|
||||
if (LZ4F_isError(outSize)) EXM_THROW(34, "Compression failed : %s", LZ4F_getErrorName(outSize));
|
||||
compressedfilesize += outSize;
|
||||
DISPLAYUPDATE(3, "\rRead : %i MB ==> %.2f%% ", (int)(filesize>>20), (double)compressedfilesize/filesize*100);
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(out_buff, 1, outSize, foutput);
|
||||
if (sizeCheck!=outSize) EXM_THROW(35, "Write error : cannot write compressed block");
|
||||
|
||||
/* Read next block */
|
||||
readSize = fread(in_buff, (size_t)1, (size_t)blockSize, finput);
|
||||
filesize += readSize;
|
||||
}
|
||||
|
||||
/* End of Stream mark */
|
||||
headerSize = LZ4F_compressEnd(ctx, out_buff, outBuffSize, NULL);
|
||||
if (LZ4F_isError(headerSize)) EXM_THROW(36, "End of file generation failed : %s", LZ4F_getErrorName(headerSize));
|
||||
|
||||
sizeCheck = fwrite(out_buff, 1, headerSize, foutput);
|
||||
if (sizeCheck!=headerSize) EXM_THROW(37, "Write error : cannot write end of stream");
|
||||
compressedfilesize += headerSize;
|
||||
|
||||
/* Close & Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
errorCode = LZ4F_freeCompressionContext(ctx);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(38, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
/* Final Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2, "Compressed %llu bytes into %llu bytes ==> %.2f%%\n",
|
||||
(unsigned long long) filesize, (unsigned long long) compressedfilesize, (double)compressedfilesize/filesize*100);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************************* */
|
||||
/* ********************** LZ4 File / Stream decoding ******************* */
|
||||
/* ********************************************************************* */
|
||||
|
||||
static unsigned LZ4IO_readLE32 (const void* s)
|
||||
{
|
||||
const unsigned char* srcPtr = s;
|
||||
unsigned value32 = srcPtr[0];
|
||||
value32 += (srcPtr[1]<<8);
|
||||
value32 += (srcPtr[2]<<16);
|
||||
value32 += (srcPtr[3]<<24);
|
||||
return value32;
|
||||
}
|
||||
|
||||
static unsigned long long decodeLegacyStream(FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
char* in_buff;
|
||||
char* out_buff;
|
||||
|
||||
/* Allocate Memory */
|
||||
in_buff = (char*)malloc(LZ4_compressBound(LEGACY_BLOCKSIZE));
|
||||
out_buff = (char*)malloc(LEGACY_BLOCKSIZE);
|
||||
if (!in_buff || !out_buff) EXM_THROW(51, "Allocation error : not enough memory");
|
||||
|
||||
/* Main Loop */
|
||||
while (1)
|
||||
{
|
||||
int decodeSize;
|
||||
size_t sizeCheck;
|
||||
unsigned int blockSize;
|
||||
|
||||
/* Block Size */
|
||||
sizeCheck = fread(in_buff, 1, 4, finput);
|
||||
if (sizeCheck==0) break; /* Nothing to read : file read is completed */
|
||||
blockSize = LZ4IO_readLE32(in_buff); /* Convert to Little Endian */
|
||||
if (blockSize > LZ4_COMPRESSBOUND(LEGACY_BLOCKSIZE))
|
||||
{ /* Cannot read next block : maybe new stream ? */
|
||||
fseek(finput, -4, SEEK_CUR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read Block */
|
||||
sizeCheck = fread(in_buff, 1, blockSize, finput);
|
||||
|
||||
/* Decode Block */
|
||||
decodeSize = LZ4_decompress_safe(in_buff, out_buff, blockSize, LEGACY_BLOCKSIZE);
|
||||
if (decodeSize < 0) EXM_THROW(52, "Decoding Failed ! Corrupted input detected !");
|
||||
filesize += decodeSize;
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(out_buff, 1, decodeSize, foutput);
|
||||
if (sizeCheck != (size_t)decodeSize) EXM_THROW(53, "Write error : cannot write decoded block into output\n");
|
||||
}
|
||||
|
||||
/* Free */
|
||||
free(in_buff);
|
||||
free(out_buff);
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long long decodeLZ4S(FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned long long filesize = 0;
|
||||
char* inBuff;
|
||||
char* outBuff;
|
||||
# define HEADERMAX 20
|
||||
char headerBuff[HEADERMAX];
|
||||
size_t sizeCheck, nextToRead, outBuffSize, inBuffSize;
|
||||
LZ4F_decompressionContext_t ctx;
|
||||
LZ4F_errorCode_t errorCode;
|
||||
LZ4F_frameInfo_t frameInfo;
|
||||
|
||||
/* init */
|
||||
errorCode = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(60, "Allocation error : can't create context : %s", LZ4F_getErrorName(errorCode));
|
||||
LZ4IO_writeLE32(headerBuff, LZ4S_MAGICNUMBER); /* regenerated here, as it was already read from finput */
|
||||
|
||||
/* Decode stream descriptor */
|
||||
outBuffSize = 0; inBuffSize = 0; sizeCheck = MAGICNUMBER_SIZE;
|
||||
nextToRead = LZ4F_decompress(ctx, NULL, &outBuffSize, headerBuff, &sizeCheck, NULL);
|
||||
if (LZ4F_isError(nextToRead)) EXM_THROW(61, "Decompression error : %s", LZ4F_getErrorName(nextToRead));
|
||||
if (nextToRead > HEADERMAX) EXM_THROW(62, "Header too large (%i>%i)", (int)nextToRead, HEADERMAX);
|
||||
sizeCheck = fread(headerBuff, 1, nextToRead, finput);
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(63, "Read error ");
|
||||
nextToRead = LZ4F_decompress(ctx, NULL, &outBuffSize, headerBuff, &sizeCheck, NULL);
|
||||
errorCode = LZ4F_getFrameInfo(ctx, &frameInfo, NULL, &inBuffSize);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(64, "can't decode frame header : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
/* Allocate Memory */
|
||||
outBuffSize = LZ4IO_setBlockSizeID(frameInfo.blockSizeID);
|
||||
inBuffSize = outBuffSize + 4;
|
||||
inBuff = (char*)malloc(inBuffSize);
|
||||
outBuff = (char*)malloc(outBuffSize);
|
||||
if (!inBuff || !outBuff) EXM_THROW(65, "Allocation error : not enough memory");
|
||||
|
||||
/* Main Loop */
|
||||
while (nextToRead != 0)
|
||||
{
|
||||
size_t decodedBytes = outBuffSize;
|
||||
|
||||
/* Read Block */
|
||||
sizeCheck = fread(inBuff, 1, nextToRead, finput);
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(66, "Read error ");
|
||||
|
||||
/* Decode Block */
|
||||
errorCode = LZ4F_decompress(ctx, outBuff, &decodedBytes, inBuff, &sizeCheck, NULL);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(67, "Decompression error : %s", LZ4F_getErrorName(errorCode));
|
||||
if (sizeCheck!=nextToRead) EXM_THROW(67, "Synchronization error");
|
||||
nextToRead = errorCode;
|
||||
filesize += decodedBytes;
|
||||
|
||||
/* Write Block */
|
||||
sizeCheck = fwrite(outBuff, 1, decodedBytes, foutput);
|
||||
if (sizeCheck != decodedBytes) EXM_THROW(68, "Write error : cannot write decoded block\n");
|
||||
}
|
||||
|
||||
/* Free */
|
||||
free(inBuff);
|
||||
free(outBuff);
|
||||
errorCode = LZ4F_freeDecompressionContext(ctx);
|
||||
if (LZ4F_isError(errorCode)) EXM_THROW(69, "Error : can't free LZ4F context resource : %s", LZ4F_getErrorName(errorCode));
|
||||
|
||||
return filesize;
|
||||
}
|
||||
|
||||
|
||||
#define ENDOFSTREAM ((unsigned long long)-1)
|
||||
static unsigned long long selectDecoder( FILE* finput, FILE* foutput)
|
||||
{
|
||||
unsigned char U32store[MAGICNUMBER_SIZE];
|
||||
unsigned magicNumber, size;
|
||||
int errorNb;
|
||||
size_t nbReadBytes;
|
||||
|
||||
/* Check Archive Header */
|
||||
nbReadBytes = fread(U32store, 1, MAGICNUMBER_SIZE, finput);
|
||||
if (nbReadBytes==0) return ENDOFSTREAM; /* EOF */
|
||||
if (nbReadBytes != MAGICNUMBER_SIZE) EXM_THROW(40, "Unrecognized header : Magic Number unreadable");
|
||||
magicNumber = LZ4IO_readLE32(U32store); /* Little Endian format */
|
||||
if (LZ4S_isSkippableMagicNumber(magicNumber)) magicNumber = LZ4S_SKIPPABLE0; /* fold skippable magic numbers */
|
||||
|
||||
switch(magicNumber)
|
||||
{
|
||||
case LZ4S_MAGICNUMBER:
|
||||
return DEFAULT_DECOMPRESSOR(finput, foutput);
|
||||
case LEGACY_MAGICNUMBER:
|
||||
DISPLAYLEVEL(4, "Detected : Legacy format \n");
|
||||
return decodeLegacyStream(finput, foutput);
|
||||
case LZ4S_SKIPPABLE0:
|
||||
DISPLAYLEVEL(4, "Skipping detected skippable area \n");
|
||||
nbReadBytes = fread(U32store, 1, 4, finput);
|
||||
if (nbReadBytes != 4) EXM_THROW(42, "Stream error : skippable size unreadable");
|
||||
size = LZ4IO_readLE32(U32store); /* Little Endian format */
|
||||
errorNb = fseek(finput, size, SEEK_CUR);
|
||||
if (errorNb != 0) EXM_THROW(43, "Stream error : cannot skip skippable area");
|
||||
return selectDecoder(finput, foutput);
|
||||
EXTENDED_FORMAT;
|
||||
default:
|
||||
if (ftell(finput) == MAGICNUMBER_SIZE) EXM_THROW(44,"Unrecognized header : file cannot be decoded"); /* Wrong magic number at the beginning of 1st stream */
|
||||
DISPLAYLEVEL(2, "Stream followed by unrecognized data\n");
|
||||
return ENDOFSTREAM;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int LZ4IO_decompressFilename(char* input_filename, char* output_filename)
|
||||
{
|
||||
unsigned long long filesize = 0, decodedSize=0;
|
||||
FILE* finput;
|
||||
FILE* foutput;
|
||||
clock_t start, end;
|
||||
|
||||
|
||||
/* Init */
|
||||
start = clock();
|
||||
get_fileHandle(input_filename, output_filename, &finput, &foutput);
|
||||
|
||||
/* Loop over multiple streams */
|
||||
do
|
||||
{
|
||||
decodedSize = selectDecoder(finput, foutput);
|
||||
if (decodedSize != ENDOFSTREAM)
|
||||
filesize += decodedSize;
|
||||
} while (decodedSize != ENDOFSTREAM);
|
||||
|
||||
/* Final Status */
|
||||
end = clock();
|
||||
DISPLAYLEVEL(2, "\r%79s\r", "");
|
||||
DISPLAYLEVEL(2, "Successfully decoded %llu bytes \n", filesize);
|
||||
{
|
||||
double seconds = (double)(end - start)/CLOCKS_PER_SEC;
|
||||
DISPLAYLEVEL(4, "Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024);
|
||||
}
|
||||
|
||||
/* Close */
|
||||
fclose(finput);
|
||||
fclose(foutput);
|
||||
|
||||
/* Error status = OK */
|
||||
return 0;
|
||||
}
|
||||
|
||||
77
programs/lz4io.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
LZ4io.h - LZ4 File/Stream Interface
|
||||
Copyright (C) Yann Collet 2011-2014
|
||||
GPL v2 License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
|
||||
*/
|
||||
/*
|
||||
Note : this is stand-alone program.
|
||||
It is not part of LZ4 compression library, it is a user code of the LZ4 library.
|
||||
- The license of LZ4 library is BSD.
|
||||
- The license of xxHash library is BSD.
|
||||
- The license of this source file is GPLv2.
|
||||
*/
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* Special input/output values */
|
||||
/* ************************************************** */
|
||||
#define NULL_OUTPUT "null"
|
||||
static char stdinmark[] = "stdin";
|
||||
static char stdoutmark[] = "stdout";
|
||||
#ifdef _WIN32
|
||||
static char nulmark[] = "nul";
|
||||
#else
|
||||
static char nulmark[] = "/dev/null";
|
||||
#endif
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Functions ********************* */
|
||||
/* ************************************************** */
|
||||
|
||||
int LZ4IO_compressFilename (char* input_filename, char* output_filename, int compressionlevel);
|
||||
int LZ4IO_decompressFilename(char* input_filename, char* output_filename);
|
||||
|
||||
|
||||
/* ************************************************** */
|
||||
/* ****************** Parameters ******************** */
|
||||
/* ************************************************** */
|
||||
|
||||
/* Default setting : overwrite = 1;
|
||||
return : overwrite mode (0/1) */
|
||||
int LZ4IO_setOverwrite(int yes);
|
||||
|
||||
/* blockSizeID : valid values : 4-5-6-7
|
||||
return : -1 if error, blockSize if OK */
|
||||
int LZ4IO_setBlockSizeID(int blockSizeID);
|
||||
|
||||
/* Default setting : independent blocks */
|
||||
typedef enum { LZ4IO_blockLinked=0, LZ4IO_blockIndependent} LZ4IO_blockMode_t;
|
||||
int LZ4IO_setBlockMode(LZ4IO_blockMode_t blockMode);
|
||||
|
||||
/* Default setting : no checksum */
|
||||
int LZ4IO_setBlockChecksumMode(int xxhash);
|
||||
|
||||
/* Default setting : checksum enabled */
|
||||
int LZ4IO_setStreamChecksumMode(int xxhash);
|
||||
|
||||
/* Default setting : 0 (no notification) */
|
||||
int LZ4IO_setNotificationLevel(int level);
|
||||